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