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