]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
devlink: fix "devlink port" help message
[mirror_iproute2.git] / devlink / devlink.c
1 /*
2 * devlink.c Devlink tool
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Jiri Pirko <jiri@mellanox.com>
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdbool.h>
16 #include <unistd.h>
17 #include <getopt.h>
18 #include <limits.h>
19 #include <errno.h>
20 #include <linux/genetlink.h>
21 #include <linux/devlink.h>
22 #include <libmnl/libmnl.h>
23
24 #include "SNAPSHOT.h"
25 #include "list.h"
26 #include "mnlg.h"
27
28 #define pr_err(args...) fprintf(stderr, ##args)
29 #define pr_out(args...) fprintf(stdout, ##args)
30
31 static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
32 mnl_cb_t data_cb, void *data)
33 {
34 int err;
35
36 err = mnlg_socket_recv_run(nlg, data_cb, data);
37 if (err < 0) {
38 pr_err("devlink answers: %s\n", strerror(errno));
39 return -errno;
40 }
41 return 0;
42 }
43
44 static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
45 const struct nlmsghdr *nlh,
46 mnl_cb_t data_cb, void *data)
47 {
48 int err;
49
50 err = mnlg_socket_send(nlg, nlh);
51 if (err < 0) {
52 pr_err("Failed to call mnlg_socket_send\n");
53 return -errno;
54 }
55 return _mnlg_socket_recv_run(nlg, data_cb, data);
56 }
57
58 static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
59 const char *group_name)
60 {
61 int err;
62
63 err = mnlg_socket_group_add(nlg, group_name);
64 if (err < 0) {
65 pr_err("Failed to call mnlg_socket_group_add\n");
66 return -errno;
67 }
68 return 0;
69 }
70
71 struct ifname_map {
72 struct list_head list;
73 char *bus_name;
74 char *dev_name;
75 uint32_t port_index;
76 char *ifname;
77 };
78
79 static struct ifname_map *ifname_map_alloc(const char *bus_name,
80 const char *dev_name,
81 uint32_t port_index,
82 const char *ifname)
83 {
84 struct ifname_map *ifname_map;
85
86 ifname_map = calloc(1, sizeof(*ifname_map));
87 if (!ifname_map)
88 return NULL;
89 ifname_map->bus_name = strdup(bus_name);
90 ifname_map->dev_name = strdup(dev_name);
91 ifname_map->port_index = port_index;
92 ifname_map->ifname = strdup(ifname);
93 if (!ifname_map->bus_name || !ifname_map->dev_name ||
94 !ifname_map->ifname) {
95 free(ifname_map->ifname);
96 free(ifname_map->dev_name);
97 free(ifname_map->bus_name);
98 free(ifname_map);
99 return NULL;
100 }
101 return ifname_map;
102 }
103
104 static void ifname_map_free(struct ifname_map *ifname_map)
105 {
106 free(ifname_map->ifname);
107 free(ifname_map->dev_name);
108 free(ifname_map->bus_name);
109 free(ifname_map);
110 }
111
112 struct dl {
113 struct mnlg_socket *nlg;
114 struct list_head ifname_map_list;
115 int argc;
116 char **argv;
117 };
118
119 static int dl_argc(struct dl *dl)
120 {
121 return dl->argc;
122 }
123
124 static char *dl_argv(struct dl *dl)
125 {
126 if (dl_argc(dl) == 0)
127 return NULL;
128 return *dl->argv;
129 }
130
131 static void dl_arg_inc(struct dl *dl)
132 {
133 if (dl_argc(dl) == 0)
134 return;
135 dl->argc--;
136 dl->argv++;
137 }
138
139 static char *dl_argv_next(struct dl *dl)
140 {
141 char *ret;
142
143 if (dl_argc(dl) == 0)
144 return NULL;
145
146 ret = *dl->argv;
147 dl_arg_inc(dl);
148 return ret;
149 }
150
151 static char *dl_argv_index(struct dl *dl, unsigned int index)
152 {
153 if (index >= dl_argc(dl))
154 return NULL;
155 return dl->argv[index];
156 }
157
158 static int strcmpx(const char *str1, const char *str2)
159 {
160 if (strlen(str1) > strlen(str2))
161 return -1;
162 return strncmp(str1, str2, strlen(str1));
163 }
164
165 static bool dl_argv_match(struct dl *dl, const char *pattern)
166 {
167 if (dl_argc(dl) == 0)
168 return false;
169 return strcmpx(dl_argv(dl), pattern) == 0;
170 }
171
172 static bool dl_no_arg(struct dl *dl)
173 {
174 return dl_argc(dl) == 0;
175 }
176
177 static int attr_cb(const struct nlattr *attr, void *data)
178 {
179 const struct nlattr **tb = data;
180 int type;
181
182 type = mnl_attr_get_type(attr);
183
184 if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
185 return MNL_CB_ERROR;
186
187 if (type == DEVLINK_ATTR_BUS_NAME &&
188 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
189 return MNL_CB_ERROR;
190 if (type == DEVLINK_ATTR_DEV_NAME &&
191 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
192 return MNL_CB_ERROR;
193 if (type == DEVLINK_ATTR_PORT_INDEX &&
194 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
195 return MNL_CB_ERROR;
196 if (type == DEVLINK_ATTR_PORT_TYPE &&
197 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
198 return MNL_CB_ERROR;
199 if (type == DEVLINK_ATTR_PORT_DESIRED_TYPE &&
200 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
201 return MNL_CB_ERROR;
202 if (type == DEVLINK_ATTR_PORT_NETDEV_IFINDEX &&
203 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
204 return MNL_CB_ERROR;
205 if (type == DEVLINK_ATTR_PORT_NETDEV_NAME &&
206 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
207 return MNL_CB_ERROR;
208 if (type == DEVLINK_ATTR_PORT_IBDEV_NAME &&
209 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
210 return MNL_CB_ERROR;
211 tb[type] = attr;
212 return MNL_CB_OK;
213 }
214
215 static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
216 {
217 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
218 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
219 struct dl *dl = data;
220 struct ifname_map *ifname_map;
221 const char *bus_name;
222 const char *dev_name;
223 uint32_t port_ifindex;
224 const char *port_ifname;
225
226 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
227 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
228 !tb[DEVLINK_ATTR_PORT_INDEX])
229 return MNL_CB_ERROR;
230
231 if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
232 return MNL_CB_OK;
233
234 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
235 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
236 port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
237 port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
238 ifname_map = ifname_map_alloc(bus_name, dev_name,
239 port_ifindex, port_ifname);
240 if (!ifname_map)
241 return MNL_CB_ERROR;
242 list_add(&ifname_map->list, &dl->ifname_map_list);
243
244 return MNL_CB_OK;
245 }
246
247 static void ifname_map_fini(struct dl *dl)
248 {
249 struct ifname_map *ifname_map, *tmp;
250
251 list_for_each_entry_safe(ifname_map, tmp,
252 &dl->ifname_map_list, list) {
253 list_del(&ifname_map->list);
254 ifname_map_free(ifname_map);
255 }
256 }
257
258 static int ifname_map_init(struct dl *dl)
259 {
260 struct nlmsghdr *nlh;
261 int err;
262
263 INIT_LIST_HEAD(&dl->ifname_map_list);
264
265 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
266 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
267
268 err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl);
269 if (err) {
270 ifname_map_fini(dl);
271 return err;
272 }
273 return 0;
274 }
275
276 static int ifname_map_lookup(struct dl *dl, const char *ifname,
277 char **p_bus_name, char **p_dev_name,
278 uint32_t *p_port_index)
279 {
280 struct ifname_map *ifname_map;
281
282 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
283 if (strcmp(ifname, ifname_map->ifname) == 0) {
284 *p_bus_name = ifname_map->bus_name;
285 *p_dev_name = ifname_map->dev_name;
286 *p_port_index = ifname_map->port_index;
287 return 0;
288 }
289 }
290 return -ENOENT;
291 }
292
293 static unsigned int strslashcount(char *str)
294 {
295 unsigned int count = 0;
296 char *pos = str;
297
298 while ((pos = strchr(pos, '/'))) {
299 count++;
300 pos++;
301 }
302 return count;
303 }
304
305 static int strslashrsplit(char *str, char **before, char **after)
306 {
307 char *slash;
308
309 slash = strrchr(str, '/');
310 if (!slash)
311 return -EINVAL;
312 *slash = '\0';
313 *before = str;
314 *after = slash + 1;
315 return 0;
316 }
317
318 static int strtouint32_t(const char *str, uint32_t *p_val)
319 {
320 char *endptr;
321 unsigned long int val;
322
323 val = strtoul(str, &endptr, 10);
324 if (endptr == str || *endptr != '\0')
325 return -EINVAL;
326 if (val > UINT_MAX)
327 return -ERANGE;
328 *p_val = val;
329 return 0;
330 }
331
332 static int dl_argv_put_handle(struct nlmsghdr *nlh, struct dl *dl)
333 {
334 char *str = dl_argv_next(dl);
335 char *bus_name = bus_name;
336 char *dev_name = dev_name;
337
338 if (!str) {
339 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
340 return -EINVAL;
341 }
342 if (strslashcount(str) != 1) {
343 pr_err("Wrong devlink identification string format.\n");
344 pr_err("Expected \"bus_name/dev_name\".\n");
345 return -EINVAL;
346 }
347
348 strslashrsplit(str, &bus_name, &dev_name);
349 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name);
350 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name);
351 return 0;
352 }
353
354 static int dl_argv_put_handle_port(struct nlmsghdr *nlh, struct dl *dl)
355 {
356 char *str = dl_argv_next(dl);
357 unsigned int slash_count;
358 char *bus_name = bus_name;
359 char *dev_name = dev_name;
360 uint32_t port_index = port_index;
361 int err;
362
363 if (!str) {
364 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
365 return -EINVAL;
366 }
367 slash_count = strslashcount(str);
368 if (slash_count != 2 && slash_count != 0) {
369 pr_err("Wrong port identification string format.\n");
370 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
371 return -EINVAL;
372 }
373
374 if (slash_count == 2) {
375 char *handlestr = handlestr;
376 char *portstr = portstr;
377
378 err = strslashrsplit(str, &handlestr, &portstr);
379 err = strtouint32_t(portstr, &port_index);
380 if (err) {
381 pr_err("Port index \"%s\" is not a number or not within range\n",
382 portstr);
383 return err;
384 }
385 strslashrsplit(handlestr, &bus_name, &dev_name);
386 } else if (slash_count == 0) {
387 err = ifname_map_lookup(dl, str, &bus_name, &dev_name,
388 &port_index);
389 if (err) {
390 pr_err("Netdevice \"%s\" not found\n", str);
391 return err;
392 }
393 }
394 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, bus_name);
395 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, dev_name);
396 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX, port_index);
397 return 0;
398 }
399
400 static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
401 {
402 char *str = dl_argv_next(dl);
403 int err;
404
405 if (!str) {
406 pr_err("Unsigned number argument expected\n");
407 return -EINVAL;
408 }
409
410 err = strtouint32_t(str, p_val);
411 if (err) {
412 pr_err("\"%s\" is not a number or not within range\n", str);
413 return err;
414 }
415 return 0;
416 }
417
418 static int dl_argv_str(struct dl *dl, const char **p_str)
419 {
420 const char *str = dl_argv_next(dl);
421
422 if (!str) {
423 pr_err("String parameter expected\n");
424 return -EINVAL;
425 }
426 *p_str = str;
427 return 0;
428 }
429
430 static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
431 {
432 if (strcmp(typestr, "auto") == 0) {
433 *p_type = DEVLINK_PORT_TYPE_AUTO;
434 } else if (strcmp(typestr, "eth") == 0) {
435 *p_type = DEVLINK_PORT_TYPE_ETH;
436 } else if (strcmp(typestr, "ib") == 0) {
437 *p_type = DEVLINK_PORT_TYPE_IB;
438 } else {
439 pr_err("Unknown port type \"%s\"\n", typestr);
440 return -EINVAL;
441 }
442 return 0;
443 }
444
445 #define BIT(nr) (1UL << (nr))
446 #define DL_OPT_HANDLE BIT(0)
447 #define DL_OPT_HANDLEP BIT(1)
448 #define DL_OPT_PORT_TYPE BIT(2)
449 #define DL_OPT_PORT_COUNT BIT(3)
450
451 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
452 uint32_t o_required, uint32_t o_optional)
453 {
454 uint32_t o_all = o_required | o_optional;
455 uint32_t o_found = 0;
456 int err;
457
458 if (o_required & DL_OPT_HANDLE) {
459 err = dl_argv_put_handle(nlh, dl);
460 if (err)
461 return err;
462 } else if (o_required & DL_OPT_HANDLEP) {
463 err = dl_argv_put_handle_port(nlh, dl);
464 if (err)
465 return err;
466 }
467
468 while (dl_argc(dl)) {
469 if (dl_argv_match(dl, "type") &&
470 (o_all & DL_OPT_PORT_TYPE)) {
471 enum devlink_port_type port_type;
472 const char *typestr;
473
474 dl_arg_inc(dl);
475 err = dl_argv_str(dl, &typestr);
476 if (err)
477 return err;
478 err = port_type_get(typestr, &port_type);
479 if (err)
480 return err;
481 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
482 port_type);
483 o_found |= DL_OPT_PORT_TYPE;
484 } else if (dl_argv_match(dl, "count") &&
485 (o_all & DL_OPT_PORT_COUNT)) {
486 uint32_t count;
487
488 dl_arg_inc(dl);
489 err = dl_argv_uint32_t(dl, &count);
490 if (err)
491 return err;
492 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
493 count);
494 o_found |= DL_OPT_PORT_COUNT;
495 } else {
496 pr_err("Unknown option \"%s\"\n", dl_argv(dl));
497 return -EINVAL;
498 }
499 }
500
501 if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) {
502 pr_err("Port type option expected.\n");
503 return -EINVAL;
504 }
505
506 if ((o_required & DL_OPT_PORT_COUNT) &&
507 !(o_found & DL_OPT_PORT_COUNT)) {
508 pr_err("Port split count option expected.\n");
509 return -EINVAL;
510 }
511
512 return 0;
513 }
514
515 static void cmd_dev_help(void)
516 {
517 pr_out("Usage: devlink dev show [ DEV ]\n");
518 }
519
520 static void pr_out_handle(struct nlattr **tb)
521 {
522 pr_out("%s/%s", mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
523 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]));
524 }
525
526 static void pr_out_dev(struct nlattr **tb)
527 {
528 pr_out_handle(tb);
529 pr_out("\n");
530 }
531
532 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
533 {
534 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
535 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
536
537 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
538 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
539 return MNL_CB_ERROR;
540 pr_out_dev(tb);
541 return MNL_CB_OK;
542 }
543
544 static int cmd_dev_show(struct dl *dl)
545 {
546 struct nlmsghdr *nlh;
547 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
548 int err;
549
550 if (dl_argc(dl) == 0)
551 flags |= NLM_F_DUMP;
552
553 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
554
555 if (dl_argc(dl) > 0) {
556 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
557 if (err)
558 return err;
559 }
560
561 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL);
562 }
563
564 static int cmd_dev(struct dl *dl)
565 {
566 if (dl_argv_match(dl, "help")) {
567 cmd_dev_help();
568 return 0;
569 } else if (dl_argv_match(dl, "show") ||
570 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
571 dl_arg_inc(dl);
572 return cmd_dev_show(dl);
573 }
574 pr_err("Command \"%s\" not found\n", dl_argv(dl));
575 return -ENOENT;
576 }
577
578 static void cmd_port_help(void)
579 {
580 pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
581 pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
582 pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n");
583 pr_out(" devlink port unsplit DEV/PORT_INDEX\n");
584 }
585
586 static const char *port_type_name(uint32_t type)
587 {
588 switch (type) {
589 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
590 case DEVLINK_PORT_TYPE_AUTO: return "auto";
591 case DEVLINK_PORT_TYPE_ETH: return "eth";
592 case DEVLINK_PORT_TYPE_IB: return "ib";
593 default: return "<unknown type>";
594 }
595 }
596
597 static void pr_out_port(struct nlattr **tb)
598 {
599 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
600 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
601
602 pr_out_handle(tb);
603 pr_out("/%d:", mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]));
604 if (pt_attr) {
605 uint16_t port_type = mnl_attr_get_u16(pt_attr);
606
607 pr_out(" type %s", port_type_name(port_type));
608 if (dpt_attr) {
609 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
610
611 if (port_type != des_port_type)
612 pr_out("(%s)", port_type_name(des_port_type));
613 }
614 }
615 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
616 pr_out(" netdev %s",
617 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
618 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
619 pr_out(" ibdev %s",
620 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
621 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
622 pr_out(" split_group %u",
623 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
624 pr_out("\n");
625 }
626
627 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
628 {
629 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
630 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
631
632 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
633 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
634 !tb[DEVLINK_ATTR_PORT_INDEX])
635 return MNL_CB_ERROR;
636 pr_out_port(tb);
637 return MNL_CB_OK;
638 }
639
640 static int cmd_port_show(struct dl *dl)
641 {
642 struct nlmsghdr *nlh;
643 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
644 int err;
645
646 if (dl_argc(dl) == 0)
647 flags |= NLM_F_DUMP;
648
649 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
650
651 if (dl_argc(dl) > 0) {
652 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
653 if (err)
654 return err;
655 }
656
657 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL);
658 }
659
660 static int cmd_port_set(struct dl *dl)
661 {
662 struct nlmsghdr *nlh;
663 int err;
664
665 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
666 NLM_F_REQUEST | NLM_F_ACK);
667
668 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
669 if (err)
670 return err;
671
672 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
673 }
674
675 static int cmd_port_split(struct dl *dl)
676 {
677 struct nlmsghdr *nlh;
678 int err;
679
680 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
681 NLM_F_REQUEST | NLM_F_ACK);
682
683 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
684 if (err)
685 return err;
686
687 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
688 }
689
690 static int cmd_port_unsplit(struct dl *dl)
691 {
692 struct nlmsghdr *nlh;
693 int err;
694
695 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
696 NLM_F_REQUEST | NLM_F_ACK);
697
698 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
699 if (err)
700 return err;
701
702 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
703 }
704
705 static int cmd_port(struct dl *dl)
706 {
707 if (dl_argv_match(dl, "help")) {
708 cmd_port_help();
709 return 0;
710 } else if (dl_argv_match(dl, "show") ||
711 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
712 dl_arg_inc(dl);
713 return cmd_port_show(dl);
714 } else if (dl_argv_match(dl, "set")) {
715 dl_arg_inc(dl);
716 return cmd_port_set(dl);
717 } else if (dl_argv_match(dl, "split")) {
718 dl_arg_inc(dl);
719 return cmd_port_split(dl);
720 } else if (dl_argv_match(dl, "unsplit")) {
721 dl_arg_inc(dl);
722 return cmd_port_unsplit(dl);
723 }
724 pr_err("Command \"%s\" not found\n", dl_argv(dl));
725 return -ENOENT;
726 }
727
728 static const char *cmd_name(uint8_t cmd)
729 {
730 switch (cmd) {
731 case DEVLINK_CMD_UNSPEC: return "unspec";
732 case DEVLINK_CMD_GET: return "get";
733 case DEVLINK_CMD_SET: return "set";
734 case DEVLINK_CMD_NEW: return "new";
735 case DEVLINK_CMD_DEL: return "del";
736 case DEVLINK_CMD_PORT_GET: return "get";
737 case DEVLINK_CMD_PORT_SET: return "set";
738 case DEVLINK_CMD_PORT_NEW: return "net";
739 case DEVLINK_CMD_PORT_DEL: return "del";
740 default: return "<unknown cmd>";
741 }
742 }
743
744 static const char *cmd_obj(uint8_t cmd)
745 {
746 switch (cmd) {
747 case DEVLINK_CMD_UNSPEC: return "unspec";
748 case DEVLINK_CMD_GET:
749 case DEVLINK_CMD_SET:
750 case DEVLINK_CMD_NEW:
751 case DEVLINK_CMD_DEL:
752 return "dev";
753 case DEVLINK_CMD_PORT_GET:
754 case DEVLINK_CMD_PORT_SET:
755 case DEVLINK_CMD_PORT_NEW:
756 case DEVLINK_CMD_PORT_DEL:
757 return "port";
758 default: return "<unknown obj>";
759 }
760 }
761
762 static void pr_out_mon_header(uint8_t cmd)
763 {
764 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
765 }
766
767 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
768 {
769 const char *obj = cmd_obj(cmd);
770 unsigned int index = 0;
771 const char *cur_obj;
772
773 if (dl_no_arg(dl))
774 return true;
775 while ((cur_obj = dl_argv_index(dl, index++))) {
776 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
777 return true;
778 }
779 return false;
780 }
781
782 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
783 {
784 struct dl *dl = data;
785 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
786 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
787 uint8_t cmd = genl->cmd;
788
789 if (!cmd_filter_check(dl, cmd))
790 return MNL_CB_OK;
791
792 switch (cmd) {
793 case DEVLINK_CMD_GET: /* fall through */
794 case DEVLINK_CMD_SET: /* fall through */
795 case DEVLINK_CMD_NEW: /* fall through */
796 case DEVLINK_CMD_DEL:
797 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
798 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
799 return MNL_CB_ERROR;
800 pr_out_mon_header(genl->cmd);
801 pr_out_dev(tb);
802 break;
803 case DEVLINK_CMD_PORT_GET: /* fall through */
804 case DEVLINK_CMD_PORT_SET: /* fall through */
805 case DEVLINK_CMD_PORT_NEW: /* fall through */
806 case DEVLINK_CMD_PORT_DEL:
807 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
808 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
809 !tb[DEVLINK_ATTR_PORT_INDEX])
810 return MNL_CB_ERROR;
811 pr_out_mon_header(genl->cmd);
812 pr_out_port(tb);
813 break;
814 }
815 return MNL_CB_OK;
816 }
817
818 static int cmd_mon_show(struct dl *dl)
819 {
820 int err;
821 unsigned int index = 0;
822 const char *cur_obj;
823
824 while ((cur_obj = dl_argv_index(dl, index++))) {
825 if (strcmp(cur_obj, "all") != 0 &&
826 strcmp(cur_obj, "dev") != 0 &&
827 strcmp(cur_obj, "port") != 0) {
828 pr_err("Unknown object \"%s\"\n", cur_obj);
829 return -EINVAL;
830 }
831 }
832 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
833 if (err)
834 return err;
835 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
836 if (err)
837 return err;
838 return 0;
839 }
840
841 static void cmd_mon_help(void)
842 {
843 pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
844 "where OBJECT-LIST := { dev | port }\n");
845 }
846
847 static int cmd_mon(struct dl *dl)
848 {
849 if (dl_argv_match(dl, "help")) {
850 cmd_mon_help();
851 return 0;
852 } else if (dl_no_arg(dl)) {
853 dl_arg_inc(dl);
854 return cmd_mon_show(dl);
855 }
856 pr_err("Command \"%s\" not found\n", dl_argv(dl));
857 return -ENOENT;
858 }
859
860 static void help(void)
861 {
862 pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
863 "where OBJECT := { dev | port | monitor }\n"
864 " OPTIONS := { -V[ersion] }\n");
865 }
866
867 static int dl_cmd(struct dl *dl)
868 {
869 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
870 help();
871 return 0;
872 } else if (dl_argv_match(dl, "dev")) {
873 dl_arg_inc(dl);
874 return cmd_dev(dl);
875 } else if (dl_argv_match(dl, "port")) {
876 dl_arg_inc(dl);
877 return cmd_port(dl);
878 } else if (dl_argv_match(dl, "monitor")) {
879 dl_arg_inc(dl);
880 return cmd_mon(dl);
881 }
882 pr_err("Object \"%s\" not found\n", dl_argv(dl));
883 return -ENOENT;
884 }
885
886 static int dl_init(struct dl *dl, int argc, char **argv)
887 {
888 int err;
889
890 dl->argc = argc;
891 dl->argv = argv;
892
893 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
894 if (!dl->nlg) {
895 pr_err("Failed to connect to devlink Netlink\n");
896 return -errno;
897 }
898
899 err = ifname_map_init(dl);
900 if (err) {
901 pr_err("Failed to create index map\n");
902 goto err_ifname_map_create;
903 }
904 return 0;
905
906 err_ifname_map_create:
907 mnlg_socket_close(dl->nlg);
908 return err;
909 }
910
911 static void dl_fini(struct dl *dl)
912 {
913 ifname_map_fini(dl);
914 mnlg_socket_close(dl->nlg);
915 }
916
917 static struct dl *dl_alloc(void)
918 {
919 struct dl *dl;
920
921 dl = calloc(1, sizeof(*dl));
922 if (!dl)
923 return NULL;
924 return dl;
925 }
926
927 static void dl_free(struct dl *dl)
928 {
929 free(dl);
930 }
931
932 int main(int argc, char **argv)
933 {
934 static const struct option long_options[] = {
935 { "Version", no_argument, NULL, 'V' },
936 { NULL, 0, NULL, 0 }
937 };
938 struct dl *dl;
939 int opt;
940 int err;
941 int ret;
942
943 while ((opt = getopt_long(argc, argv, "V",
944 long_options, NULL)) >= 0) {
945
946 switch (opt) {
947 case 'V':
948 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
949 return EXIT_SUCCESS;
950 default:
951 pr_err("Unknown option.\n");
952 help();
953 return EXIT_FAILURE;
954 }
955 }
956
957 argc -= optind;
958 argv += optind;
959
960 dl = dl_alloc();
961 if (!dl) {
962 pr_err("Failed to allocate memory for devlink\n");
963 return EXIT_FAILURE;
964 }
965
966 err = dl_init(dl, argc, argv);
967 if (err) {
968 ret = EXIT_FAILURE;
969 goto dl_free;
970 }
971
972 err = dl_cmd(dl);
973 if (err) {
974 ret = EXIT_FAILURE;
975 goto dl_fini;
976 }
977
978 ret = EXIT_SUCCESS;
979
980 dl_fini:
981 dl_fini(dl);
982 dl_free:
983 dl_free(dl);
984
985 return ret;
986 }