1
2
3#include <stdio.h>
4#include <string.h>
5#include <rt_names.h>
6#include <errno.h>
7
8#include <linux/genetlink.h>
9#include <linux/mptcp.h>
10
11#include "utils.h"
12#include "ip_common.h"
13#include "libgenl.h"
14#include "json_print.h"
15
16static void usage(void)
17{
18 fprintf(stderr,
19 "Usage: ip mptcp endpoint add ADDRESS [ dev NAME ] [ id ID ]\n"
20 " [ port NR ] [ FLAG-LIST ]\n"
21 " ip mptcp endpoint delete id ID\n"
22 " ip mptcp endpoint show [ id ID ]\n"
23 " ip mptcp endpoint flush\n"
24 " ip mptcp limits set [ subflows NR ] [ add_addr_accepted NR ]\n"
25 " ip mptcp limits show\n"
26 " ip mptcp monitor\n"
27 "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
28 "FLAG := [ signal | subflow | backup ]\n");
29
30 exit(-1);
31}
32
33
34static struct rtnl_handle genl_rth = { .fd = -1 };
35static int genl_family = -1;
36
37#define MPTCP_BUFLEN 4096
38#define MPTCP_REQUEST(_req, _cmd, _flags) \
39 GENL_REQUEST(_req, MPTCP_BUFLEN, genl_family, 0, \
40 MPTCP_PM_VER, _cmd, _flags)
41
42
43static const struct {
44 const char *name;
45 unsigned long value;
46} mptcp_addr_flag_names[] = {
47 { "signal", MPTCP_PM_ADDR_FLAG_SIGNAL },
48 { "subflow", MPTCP_PM_ADDR_FLAG_SUBFLOW },
49 { "backup", MPTCP_PM_ADDR_FLAG_BACKUP },
50};
51
52static void print_mptcp_addr_flags(unsigned int flags)
53{
54 unsigned int i;
55
56 for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
57 unsigned long mask = mptcp_addr_flag_names[i].value;
58
59 if (flags & mask) {
60 print_string(PRINT_FP, NULL, "%s ",
61 mptcp_addr_flag_names[i].name);
62 print_bool(PRINT_JSON,
63 mptcp_addr_flag_names[i].name, NULL, true);
64 }
65
66 flags &= ~mask;
67 }
68
69 if (flags) {
70
71 SPRINT_BUF(b1);
72
73 snprintf(b1, sizeof(b1), "%02x", flags);
74 print_string(PRINT_ANY, "rawflags", "rawflags %s ", b1);
75 }
76}
77
78static int get_flags(const char *arg, __u32 *flags)
79{
80 unsigned int i;
81
82 for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
83 if (strcmp(arg, mptcp_addr_flag_names[i].name))
84 continue;
85
86 *flags |= mptcp_addr_flag_names[i].value;
87 return 0;
88 }
89 return -1;
90}
91
92static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n,
93 bool adding)
94{
95 struct rtattr *attr_addr;
96 bool addr_set = false;
97 inet_prefix address;
98 bool id_set = false;
99 __u32 index = 0;
100 __u32 flags = 0;
101 __u16 port = 0;
102 __u8 id = 0;
103
104 ll_init_map(&rth);
105 while (argc > 0) {
106 if (get_flags(*argv, &flags) == 0) {
107 } else if (matches(*argv, "id") == 0) {
108 NEXT_ARG();
109
110 if (get_u8(&id, *argv, 0))
111 invarg("invalid ID\n", *argv);
112 id_set = true;
113 } else if (matches(*argv, "dev") == 0) {
114 const char *ifname;
115
116 NEXT_ARG();
117
118 ifname = *argv;
119
120 if (check_ifname(ifname))
121 invarg("invalid interface name\n", ifname);
122
123 index = ll_name_to_index(ifname);
124
125 if (!index)
126 invarg("device does not exist\n", ifname);
127
128 } else if (matches(*argv, "port") == 0) {
129 NEXT_ARG();
130 if (get_u16(&port, *argv, 0))
131 invarg("expected port", *argv);
132 } else if (get_addr(&address, *argv, AF_UNSPEC) == 0) {
133 addr_set = true;
134 } else {
135 invarg("unknown argument", *argv);
136 }
137 NEXT_ARG_FWD();
138 }
139
140 if (!addr_set && adding)
141 missarg("ADDRESS");
142
143 if (!id_set && !adding)
144 missarg("ID");
145
146 if (port && !(flags & MPTCP_PM_ADDR_FLAG_SIGNAL))
147 invarg("flags must have signal when using port", "port");
148
149 attr_addr = addattr_nest(n, MPTCP_BUFLEN,
150 MPTCP_PM_ATTR_ADDR | NLA_F_NESTED);
151 if (id_set)
152 addattr8(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_ID, id);
153 if (flags)
154 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FLAGS, flags);
155 if (index)
156 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_IF_IDX, index);
157 if (port)
158 addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_PORT, port);
159 if (addr_set) {
160 int type;
161
162 addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FAMILY,
163 address.family);
164 type = address.family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
165 MPTCP_PM_ADDR_ATTR_ADDR6;
166 addattr_l(n, MPTCP_BUFLEN, type, &address.data,
167 address.bytelen);
168 }
169
170 addattr_nest_end(n, attr_addr);
171 return 0;
172}
173
174static int mptcp_addr_modify(int argc, char **argv, int cmd)
175{
176 MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
177 int ret;
178
179 ret = mptcp_parse_opt(argc, argv, &req.n, cmd == MPTCP_PM_CMD_ADD_ADDR);
180 if (ret)
181 return ret;
182
183 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
184 return -2;
185
186 return 0;
187}
188
189static int print_mptcp_addrinfo(struct rtattr *addrinfo)
190{
191 struct rtattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
192 __u8 family = AF_UNSPEC, addr_attr_type;
193 const char *ifname;
194 unsigned int flags;
195 __u16 id, port;
196 int index;
197
198 parse_rtattr_nested(tb, MPTCP_PM_ADDR_ATTR_MAX, addrinfo);
199
200 open_json_object(NULL);
201 if (tb[MPTCP_PM_ADDR_ATTR_FAMILY])
202 family = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
203
204 addr_attr_type = family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
205 MPTCP_PM_ADDR_ATTR_ADDR6;
206 if (tb[addr_attr_type]) {
207 print_string(PRINT_ANY, "address", "%s ",
208 format_host_rta(family, tb[addr_attr_type]));
209 }
210 if (tb[MPTCP_PM_ADDR_ATTR_PORT]) {
211 port = rta_getattr_u16(tb[MPTCP_PM_ADDR_ATTR_PORT]);
212 if (port)
213 print_uint(PRINT_ANY, "port", "port %u ", port);
214 }
215 if (tb[MPTCP_PM_ADDR_ATTR_ID]) {
216 id = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
217 print_uint(PRINT_ANY, "id", "id %u ", id);
218 }
219 if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) {
220 flags = rta_getattr_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
221 print_mptcp_addr_flags(flags);
222 }
223 if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) {
224 index = rta_getattr_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
225 ifname = index ? ll_index_to_name(index) : NULL;
226
227 if (ifname)
228 print_string(PRINT_ANY, "dev", "dev %s ", ifname);
229 }
230
231 close_json_object();
232 print_string(PRINT_FP, NULL, "\n", NULL);
233 fflush(stdout);
234
235 return 0;
236}
237
238static int print_mptcp_addr(struct nlmsghdr *n, void *arg)
239{
240 struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
241 struct genlmsghdr *ghdr;
242 struct rtattr *addrinfo;
243 int len = n->nlmsg_len;
244
245 if (n->nlmsg_type != genl_family)
246 return 0;
247
248 len -= NLMSG_LENGTH(GENL_HDRLEN);
249 if (len < 0)
250 return -1;
251
252 ghdr = NLMSG_DATA(n);
253 parse_rtattr_flags(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN,
254 len, NLA_F_NESTED);
255 addrinfo = tb[MPTCP_PM_ATTR_ADDR];
256 if (!addrinfo)
257 return -1;
258
259 ll_init_map(&rth);
260 return print_mptcp_addrinfo(addrinfo);
261}
262
263static int mptcp_addr_dump(void)
264{
265 MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST | NLM_F_DUMP);
266
267 if (rtnl_send(&genl_rth, &req.n, req.n.nlmsg_len) < 0) {
268 perror("Cannot send show request");
269 exit(1);
270 }
271
272 new_json_obj(json);
273
274 if (rtnl_dump_filter(&genl_rth, print_mptcp_addr, stdout) < 0) {
275 fprintf(stderr, "Dump terminated\n");
276 delete_json_obj();
277 fflush(stdout);
278 return -2;
279 }
280
281 delete_json_obj();
282 fflush(stdout);
283 return 0;
284}
285
286static int mptcp_addr_show(int argc, char **argv)
287{
288 MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST);
289 struct nlmsghdr *answer;
290 int ret;
291
292 if (argc <= 0)
293 return mptcp_addr_dump();
294
295 ret = mptcp_parse_opt(argc, argv, &req.n, false);
296 if (ret)
297 return ret;
298
299 if (rtnl_talk(&genl_rth, &req.n, &answer) < 0)
300 return -2;
301
302 return print_mptcp_addr(answer, stdout);
303}
304
305static int mptcp_addr_flush(int argc, char **argv)
306{
307 MPTCP_REQUEST(req, MPTCP_PM_CMD_FLUSH_ADDRS, NLM_F_REQUEST);
308
309 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
310 return -2;
311
312 return 0;
313}
314
315static int mptcp_parse_limit(int argc, char **argv, struct nlmsghdr *n)
316{
317 bool set_rcv_add_addrs = false;
318 bool set_subflows = false;
319 __u32 rcv_add_addrs = 0;
320 __u32 subflows = 0;
321
322 while (argc > 0) {
323 if (matches(*argv, "subflows") == 0) {
324 NEXT_ARG();
325
326 if (get_u32(&subflows, *argv, 0))
327 invarg("invalid subflows\n", *argv);
328 set_subflows = true;
329 } else if (matches(*argv, "add_addr_accepted") == 0) {
330 NEXT_ARG();
331
332 if (get_u32(&rcv_add_addrs, *argv, 0))
333 invarg("invalid add_addr_accepted\n", *argv);
334 set_rcv_add_addrs = true;
335 } else {
336 invarg("unknown limit", *argv);
337 }
338 NEXT_ARG_FWD();
339 }
340
341 if (set_rcv_add_addrs)
342 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_RCV_ADD_ADDRS,
343 rcv_add_addrs);
344 if (set_subflows)
345 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_SUBFLOWS, subflows);
346 return set_rcv_add_addrs || set_subflows;
347}
348
349static int print_mptcp_limit(struct nlmsghdr *n, void *arg)
350{
351 struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
352 struct genlmsghdr *ghdr;
353 int len = n->nlmsg_len;
354 __u32 val;
355
356 if (n->nlmsg_type != genl_family)
357 return 0;
358
359 len -= NLMSG_LENGTH(GENL_HDRLEN);
360 if (len < 0)
361 return -1;
362
363 ghdr = NLMSG_DATA(n);
364 parse_rtattr(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
365
366 open_json_object(NULL);
367 if (tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]) {
368 val = rta_getattr_u32(tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]);
369
370 print_uint(PRINT_ANY, "add_addr_accepted",
371 "add_addr_accepted %d ", val);
372 }
373
374 if (tb[MPTCP_PM_ATTR_SUBFLOWS]) {
375 val = rta_getattr_u32(tb[MPTCP_PM_ATTR_SUBFLOWS]);
376
377 print_uint(PRINT_ANY, "subflows", "subflows %d ", val);
378 }
379 print_string(PRINT_FP, NULL, "%s", "\n");
380 fflush(stdout);
381 close_json_object();
382 return 0;
383}
384
385static int mptcp_limit_get_set(int argc, char **argv, int cmd)
386{
387 bool do_get = cmd == MPTCP_PM_CMD_GET_LIMITS;
388 MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
389 struct nlmsghdr *answer;
390 int ret;
391
392 ret = mptcp_parse_limit(argc, argv, &req.n);
393 if (ret < 0)
394 return -1;
395
396 if (rtnl_talk(&genl_rth, &req.n, do_get ? &answer : NULL) < 0)
397 return -2;
398
399 if (do_get)
400 return print_mptcp_limit(answer, stdout);
401 return 0;
402}
403
404static const char * const event_to_str[] = {
405 [MPTCP_EVENT_CREATED] = "CREATED",
406 [MPTCP_EVENT_ESTABLISHED] = "ESTABLISHED",
407 [MPTCP_EVENT_CLOSED] = "CLOSED",
408 [MPTCP_EVENT_ANNOUNCED] = "ANNOUNCED",
409 [MPTCP_EVENT_REMOVED] = "REMOVED",
410 [MPTCP_EVENT_SUB_ESTABLISHED] = "SF_ESTABLISHED",
411 [MPTCP_EVENT_SUB_CLOSED] = "SF_CLOSED",
412 [MPTCP_EVENT_SUB_PRIORITY] = "SF_PRIO",
413};
414
415static void print_addr(const char *key, int af, struct rtattr *value)
416{
417 void *data = RTA_DATA(value);
418 char str[INET6_ADDRSTRLEN];
419
420 if (inet_ntop(af, data, str, sizeof(str)))
421 printf(" %s=%s", key, str);
422}
423
424static int mptcp_monitor_msg(struct rtnl_ctrl_data *ctrl,
425 struct nlmsghdr *n, void *arg)
426{
427 const struct genlmsghdr *ghdr = NLMSG_DATA(n);
428 struct rtattr *tb[MPTCP_ATTR_MAX + 1];
429 int len = n->nlmsg_len;
430
431 len -= NLMSG_LENGTH(GENL_HDRLEN);
432 if (len < 0)
433 return -1;
434
435 if (n->nlmsg_type != genl_family)
436 return 0;
437
438 if (timestamp)
439 print_timestamp(stdout);
440
441 if (ghdr->cmd >= ARRAY_SIZE(event_to_str)) {
442 printf("[UNKNOWN %u]\n", ghdr->cmd);
443 goto out;
444 }
445
446 if (event_to_str[ghdr->cmd] == NULL) {
447 printf("[UNKNOWN %u]\n", ghdr->cmd);
448 goto out;
449 }
450
451 printf("[%14s]", event_to_str[ghdr->cmd]);
452
453 parse_rtattr(tb, MPTCP_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
454
455 printf(" token=%08x", rta_getattr_u32(tb[MPTCP_ATTR_TOKEN]));
456
457 if (tb[MPTCP_ATTR_REM_ID])
458 printf(" remid=%u", rta_getattr_u8(tb[MPTCP_ATTR_REM_ID]));
459 if (tb[MPTCP_ATTR_LOC_ID])
460 printf(" locid=%u", rta_getattr_u8(tb[MPTCP_ATTR_LOC_ID]));
461
462 if (tb[MPTCP_ATTR_SADDR4])
463 print_addr("saddr4", AF_INET, tb[MPTCP_ATTR_SADDR4]);
464 if (tb[MPTCP_ATTR_DADDR4])
465 print_addr("daddr4", AF_INET, tb[MPTCP_ATTR_DADDR4]);
466 if (tb[MPTCP_ATTR_SADDR6])
467 print_addr("saddr6", AF_INET6, tb[MPTCP_ATTR_SADDR6]);
468 if (tb[MPTCP_ATTR_DADDR6])
469 print_addr("daddr6", AF_INET6, tb[MPTCP_ATTR_DADDR6]);
470 if (tb[MPTCP_ATTR_SPORT])
471 printf(" sport=%u", rta_getattr_be16(tb[MPTCP_ATTR_SPORT]));
472 if (tb[MPTCP_ATTR_DPORT])
473 printf(" dport=%u", rta_getattr_be16(tb[MPTCP_ATTR_DPORT]));
474 if (tb[MPTCP_ATTR_BACKUP])
475 printf(" backup=%d", rta_getattr_u8(tb[MPTCP_ATTR_BACKUP]));
476 if (tb[MPTCP_ATTR_ERROR])
477 printf(" error=%d", rta_getattr_u8(tb[MPTCP_ATTR_ERROR]));
478 if (tb[MPTCP_ATTR_FLAGS])
479 printf(" flags=%x", rta_getattr_u16(tb[MPTCP_ATTR_FLAGS]));
480 if (tb[MPTCP_ATTR_TIMEOUT])
481 printf(" timeout=%u", rta_getattr_u32(tb[MPTCP_ATTR_TIMEOUT]));
482 if (tb[MPTCP_ATTR_IF_IDX])
483 printf(" ifindex=%d", rta_getattr_s32(tb[MPTCP_ATTR_IF_IDX]));
484 if (tb[MPTCP_ATTR_RESET_REASON])
485 printf(" reset_reason=%u", rta_getattr_u32(tb[MPTCP_ATTR_RESET_REASON]));
486 if (tb[MPTCP_ATTR_RESET_FLAGS])
487 printf(" reset_flags=0x%x", rta_getattr_u32(tb[MPTCP_ATTR_RESET_FLAGS]));
488
489 puts("");
490out:
491 fflush(stdout);
492 return 0;
493}
494
495static int mptcp_monitor(void)
496{
497 if (genl_add_mcast_grp(&genl_rth, genl_family, MPTCP_PM_EV_GRP_NAME) < 0) {
498 perror("can't subscribe to mptcp events");
499 return 1;
500 }
501
502 if (rtnl_listen(&genl_rth, mptcp_monitor_msg, stdout) < 0)
503 return 2;
504
505 return 0;
506}
507
508int do_mptcp(int argc, char **argv)
509{
510 if (argc == 0)
511 usage();
512
513 if (matches(*argv, "help") == 0)
514 usage();
515
516 if (genl_init_handle(&genl_rth, MPTCP_PM_NAME, &genl_family))
517 exit(1);
518
519 if (matches(*argv, "endpoint") == 0) {
520 NEXT_ARG_FWD();
521 if (argc == 0)
522 return mptcp_addr_show(0, NULL);
523
524 if (matches(*argv, "add") == 0)
525 return mptcp_addr_modify(argc-1, argv+1,
526 MPTCP_PM_CMD_ADD_ADDR);
527 if (matches(*argv, "delete") == 0)
528 return mptcp_addr_modify(argc-1, argv+1,
529 MPTCP_PM_CMD_DEL_ADDR);
530 if (matches(*argv, "show") == 0)
531 return mptcp_addr_show(argc-1, argv+1);
532 if (matches(*argv, "flush") == 0)
533 return mptcp_addr_flush(argc-1, argv+1);
534
535 goto unknown;
536 }
537
538 if (matches(*argv, "limits") == 0) {
539 NEXT_ARG_FWD();
540 if (argc == 0)
541 return mptcp_limit_get_set(0, NULL,
542 MPTCP_PM_CMD_GET_LIMITS);
543
544 if (matches(*argv, "set") == 0)
545 return mptcp_limit_get_set(argc-1, argv+1,
546 MPTCP_PM_CMD_SET_LIMITS);
547 if (matches(*argv, "show") == 0)
548 return mptcp_limit_get_set(argc-1, argv+1,
549 MPTCP_PM_CMD_GET_LIMITS);
550 }
551
552 if (matches(*argv, "monitor") == 0) {
553 NEXT_ARG_FWD();
554 if (argc == 0)
555 return mptcp_monitor();
556
557 goto unknown;
558 }
559
560unknown:
561 fprintf(stderr, "Command \"%s\" is unknown, try \"ip mptcp help\".\n",
562 *argv);
563 exit(-1);
564}
565