]> git.proxmox.com Git - mirror_iproute2.git/blame - ip/ipmptcp.c
man: dcb-ets: Remove an unnecessary empty line
[mirror_iproute2.git] / ip / ipmptcp.c
CommitLineData
7e0767cd
PA
1// SPDX-License-Identifier: GPL-2.0
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 " [ 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 "FLAG-LIST := [ FLAG-LIST ] FLAG\n"
27 "FLAG := [ signal | subflow | backup ]\n");
28
29 exit(-1);
30}
31
32/* netlink socket */
33static struct rtnl_handle genl_rth = { .fd = -1 };
34static int genl_family = -1;
35
36#define MPTCP_BUFLEN 4096
37#define MPTCP_REQUEST(_req, _cmd, _flags) \
38 GENL_REQUEST(_req, MPTCP_BUFLEN, genl_family, 0, \
39 MPTCP_PM_VER, _cmd, _flags)
40
41/* Mapping from argument to address flag mask */
42static const struct {
43 const char *name;
44 unsigned long value;
45} mptcp_addr_flag_names[] = {
46 { "signal", MPTCP_PM_ADDR_FLAG_SIGNAL },
47 { "subflow", MPTCP_PM_ADDR_FLAG_SUBFLOW },
48 { "backup", MPTCP_PM_ADDR_FLAG_BACKUP },
49};
50
51static void print_mptcp_addr_flags(unsigned int flags)
52{
53 unsigned int i;
54
55 for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
56 unsigned long mask = mptcp_addr_flag_names[i].value;
57
58 if (flags & mask) {
59 print_string(PRINT_FP, NULL, "%s ",
60 mptcp_addr_flag_names[i].name);
61 print_bool(PRINT_JSON,
62 mptcp_addr_flag_names[i].name, NULL, true);
63 }
64
65 flags &= ~mask;
66 }
67
68 if (flags) {
69 /* unknown flags */
70 SPRINT_BUF(b1);
71
72 snprintf(b1, sizeof(b1), "%02x", flags);
73 print_string(PRINT_ANY, "rawflags", "rawflags %s ", b1);
74 }
75}
76
77static int get_flags(const char *arg, __u32 *flags)
78{
79 unsigned int i;
80
81 for (i = 0; i < ARRAY_SIZE(mptcp_addr_flag_names); i++) {
82 if (strcmp(arg, mptcp_addr_flag_names[i].name))
83 continue;
84
85 *flags |= mptcp_addr_flag_names[i].value;
86 return 0;
87 }
88 return -1;
89}
90
91static int mptcp_parse_opt(int argc, char **argv, struct nlmsghdr *n,
92 bool adding)
93{
94 struct rtattr *attr_addr;
95 bool addr_set = false;
96 inet_prefix address;
97 bool id_set = false;
98 __u32 index = 0;
99 __u32 flags = 0;
100 __u8 id = 0;
101
102 ll_init_map(&rth);
103 while (argc > 0) {
104 if (get_flags(*argv, &flags) == 0) {
105 } else if (matches(*argv, "id") == 0) {
106 NEXT_ARG();
107
108 if (get_u8(&id, *argv, 0))
109 invarg("invalid ID\n", *argv);
110 id_set = true;
111 } else if (matches(*argv, "dev") == 0) {
112 const char *ifname;
113
114 NEXT_ARG();
115
116 ifname = *argv;
117
118 if (check_ifname(ifname))
119 invarg("invalid interface name\n", ifname);
120
121 index = ll_name_to_index(ifname);
122
123 if (!index)
124 invarg("device does not exist\n", ifname);
125
126 } else if (get_addr(&address, *argv, AF_UNSPEC) == 0) {
127 addr_set = true;
128 } else {
129 invarg("unknown argument", *argv);
130 }
131 NEXT_ARG_FWD();
132 }
133
134 if (!addr_set && adding)
135 missarg("ADDRESS");
136
137 if (!id_set && !adding)
138 missarg("ID");
139
140 attr_addr = addattr_nest(n, MPTCP_BUFLEN,
141 MPTCP_PM_ATTR_ADDR | NLA_F_NESTED);
142 if (id_set)
143 addattr8(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_ID, id);
144 if (flags)
145 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FLAGS, flags);
146 if (index)
147 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_IF_IDX, index);
148 if (addr_set) {
149 int type;
150
151 addattr16(n, MPTCP_BUFLEN, MPTCP_PM_ADDR_ATTR_FAMILY,
152 address.family);
153 type = address.family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
154 MPTCP_PM_ADDR_ATTR_ADDR6;
155 addattr_l(n, MPTCP_BUFLEN, type, &address.data,
156 address.bytelen);
157 }
158
159 addattr_nest_end(n, attr_addr);
160 return 0;
161}
162
163static int mptcp_addr_modify(int argc, char **argv, int cmd)
164{
165 MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
166 int ret;
167
168 ret = mptcp_parse_opt(argc, argv, &req.n, cmd == MPTCP_PM_CMD_ADD_ADDR);
169 if (ret)
170 return ret;
171
172 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
173 return -2;
174
175 return 0;
176}
177
178static int print_mptcp_addrinfo(struct rtattr *addrinfo)
179{
180 struct rtattr *tb[MPTCP_PM_ADDR_ATTR_MAX + 1];
181 __u8 family = AF_UNSPEC, addr_attr_type;
182 const char *ifname;
183 unsigned int flags;
184 int index;
185 __u16 id;
186
187 parse_rtattr_nested(tb, MPTCP_PM_ADDR_ATTR_MAX, addrinfo);
188
189 open_json_object(NULL);
190 if (tb[MPTCP_PM_ADDR_ATTR_FAMILY])
191 family = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_FAMILY]);
192
193 addr_attr_type = family == AF_INET ? MPTCP_PM_ADDR_ATTR_ADDR4 :
194 MPTCP_PM_ADDR_ATTR_ADDR6;
195 if (tb[addr_attr_type]) {
196 print_string(PRINT_ANY, "address", "%s ",
197 format_host_rta(family, tb[addr_attr_type]));
198 }
199 if (tb[MPTCP_PM_ADDR_ATTR_ID]) {
200 id = rta_getattr_u8(tb[MPTCP_PM_ADDR_ATTR_ID]);
201 print_uint(PRINT_ANY, "id", "id %u ", id);
202 }
203 if (tb[MPTCP_PM_ADDR_ATTR_FLAGS]) {
204 flags = rta_getattr_u32(tb[MPTCP_PM_ADDR_ATTR_FLAGS]);
205 print_mptcp_addr_flags(flags);
206 }
207 if (tb[MPTCP_PM_ADDR_ATTR_IF_IDX]) {
208 index = rta_getattr_s32(tb[MPTCP_PM_ADDR_ATTR_IF_IDX]);
209 ifname = index ? ll_index_to_name(index) : NULL;
210
211 if (ifname)
212 print_string(PRINT_ANY, "dev", "dev %s ", ifname);
213 }
214
215 close_json_object();
216 print_string(PRINT_FP, NULL, "\n", NULL);
217 fflush(stdout);
218
219 return 0;
220}
221
222static int print_mptcp_addr(struct nlmsghdr *n, void *arg)
223{
224 struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
225 struct genlmsghdr *ghdr;
226 struct rtattr *addrinfo;
227 int len = n->nlmsg_len;
228
229 if (n->nlmsg_type != genl_family)
230 return 0;
231
232 len -= NLMSG_LENGTH(GENL_HDRLEN);
233 if (len < 0)
234 return -1;
235
236 ghdr = NLMSG_DATA(n);
237 parse_rtattr_flags(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN,
238 len, NLA_F_NESTED);
239 addrinfo = tb[MPTCP_PM_ATTR_ADDR];
240 if (!addrinfo)
241 return -1;
242
243 ll_init_map(&rth);
244 return print_mptcp_addrinfo(addrinfo);
245}
246
247static int mptcp_addr_dump(void)
248{
249 MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST | NLM_F_DUMP);
250
251 if (rtnl_send(&genl_rth, &req.n, req.n.nlmsg_len) < 0) {
252 perror("Cannot send show request");
253 exit(1);
254 }
255
256 new_json_obj(json);
257
258 if (rtnl_dump_filter(&genl_rth, print_mptcp_addr, stdout) < 0) {
259 fprintf(stderr, "Dump terminated\n");
260 delete_json_obj();
261 fflush(stdout);
262 return -2;
263 }
264
265 close_json_object();
266 fflush(stdout);
267 return 0;
268}
269
270static int mptcp_addr_show(int argc, char **argv)
271{
272 MPTCP_REQUEST(req, MPTCP_PM_CMD_GET_ADDR, NLM_F_REQUEST);
273 struct nlmsghdr *answer;
274 int ret;
275
3a53ff7e 276 if (argc <= 0)
7e0767cd
PA
277 return mptcp_addr_dump();
278
279 ret = mptcp_parse_opt(argc, argv, &req.n, false);
280 if (ret)
281 return ret;
282
283 if (rtnl_talk(&genl_rth, &req.n, &answer) < 0)
284 return -2;
285
286 return print_mptcp_addr(answer, stdout);
287}
288
289static int mptcp_addr_flush(int argc, char **argv)
290{
291 MPTCP_REQUEST(req, MPTCP_PM_CMD_FLUSH_ADDRS, NLM_F_REQUEST);
292
293 if (rtnl_talk(&genl_rth, &req.n, NULL) < 0)
294 return -2;
295
296 return 0;
297}
298
299static int mptcp_parse_limit(int argc, char **argv, struct nlmsghdr *n)
300{
301 bool set_rcv_add_addrs = false;
302 bool set_subflows = false;
303 __u32 rcv_add_addrs = 0;
304 __u32 subflows = 0;
305
306 while (argc > 0) {
307 if (matches(*argv, "subflows") == 0) {
308 NEXT_ARG();
309
310 if (get_u32(&subflows, *argv, 0))
311 invarg("invalid subflows\n", *argv);
312 set_subflows = true;
313 } else if (matches(*argv, "add_addr_accepted") == 0) {
314 NEXT_ARG();
315
316 if (get_u32(&rcv_add_addrs, *argv, 0))
317 invarg("invalid add_addr_accepted\n", *argv);
318 set_rcv_add_addrs = true;
319 } else {
320 invarg("unknown limit", *argv);
321 }
322 NEXT_ARG_FWD();
323 }
324
325 if (set_rcv_add_addrs)
326 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_RCV_ADD_ADDRS,
327 rcv_add_addrs);
328 if (set_subflows)
329 addattr32(n, MPTCP_BUFLEN, MPTCP_PM_ATTR_SUBFLOWS, subflows);
330 return set_rcv_add_addrs || set_subflows;
331}
332
333static int print_mptcp_limit(struct nlmsghdr *n, void *arg)
334{
335 struct rtattr *tb[MPTCP_PM_ATTR_MAX + 1];
336 struct genlmsghdr *ghdr;
337 int len = n->nlmsg_len;
338 __u32 val;
339
340 if (n->nlmsg_type != genl_family)
341 return 0;
342
343 len -= NLMSG_LENGTH(GENL_HDRLEN);
344 if (len < 0)
345 return -1;
346
347 ghdr = NLMSG_DATA(n);
348 parse_rtattr(tb, MPTCP_PM_ATTR_MAX, (void *) ghdr + GENL_HDRLEN, len);
349
350 open_json_object(NULL);
351 if (tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]) {
352 val = rta_getattr_u32(tb[MPTCP_PM_ATTR_RCV_ADD_ADDRS]);
353
354 print_uint(PRINT_ANY, "add_addr_accepted",
355 "add_addr_accepted %d ", val);
356 }
357
358 if (tb[MPTCP_PM_ATTR_SUBFLOWS]) {
359 val = rta_getattr_u32(tb[MPTCP_PM_ATTR_SUBFLOWS]);
360
361 print_uint(PRINT_ANY, "subflows", "subflows %d ", val);
362 }
363 print_string(PRINT_FP, NULL, "%s", "\n");
364 fflush(stdout);
365 close_json_object();
366 return 0;
367}
368
369static int mptcp_limit_get_set(int argc, char **argv, int cmd)
370{
371 bool do_get = cmd == MPTCP_PM_CMD_GET_LIMITS;
372 MPTCP_REQUEST(req, cmd, NLM_F_REQUEST);
373 struct nlmsghdr *answer;
374 int ret;
375
376 ret = mptcp_parse_limit(argc, argv, &req.n);
377 if (ret < 0)
378 return -1;
379
380 if (rtnl_talk(&genl_rth, &req.n, do_get ? &answer : NULL) < 0)
381 return -2;
382
383 if (do_get)
384 return print_mptcp_limit(answer, stdout);
385 return 0;
386}
387
388int do_mptcp(int argc, char **argv)
389{
390 if (argc == 0)
391 usage();
392
393 if (matches(*argv, "help") == 0)
394 usage();
395
396 if (genl_init_handle(&genl_rth, MPTCP_PM_NAME, &genl_family))
397 exit(1);
398
399 if (matches(*argv, "endpoint") == 0) {
400 NEXT_ARG_FWD();
401 if (argc == 0)
402 return mptcp_addr_show(0, NULL);
403
404 if (matches(*argv, "add") == 0)
405 return mptcp_addr_modify(argc-1, argv+1,
406 MPTCP_PM_CMD_ADD_ADDR);
407 if (matches(*argv, "delete") == 0)
408 return mptcp_addr_modify(argc-1, argv+1,
409 MPTCP_PM_CMD_DEL_ADDR);
410 if (matches(*argv, "show") == 0)
411 return mptcp_addr_show(argc-1, argv+1);
412 if (matches(*argv, "flush") == 0)
413 return mptcp_addr_flush(argc-1, argv+1);
414
415 goto unknown;
416 }
417
418 if (matches(*argv, "limits") == 0) {
419 NEXT_ARG_FWD();
420 if (argc == 0)
421 return mptcp_limit_get_set(0, NULL,
422 MPTCP_PM_CMD_GET_LIMITS);
423
424 if (matches(*argv, "set") == 0)
425 return mptcp_limit_get_set(argc-1, argv+1,
426 MPTCP_PM_CMD_SET_LIMITS);
427 if (matches(*argv, "show") == 0)
428 return mptcp_limit_get_set(argc-1, argv+1,
429 MPTCP_PM_CMD_GET_LIMITS);
430 }
431
432unknown:
433 fprintf(stderr, "Command \"%s\" is unknown, try \"ip mptcp help\".\n",
434 *argv);
435 exit(-1);
436}