]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
Merge branch 'master' into net-next
[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
638 static void cmd_dev_help(void)
639 {
640 pr_out("Usage: devlink dev show [ DEV ]\n");
641 }
642
643 static void __pr_out_handle(const char *bus_name, const char *dev_name)
644 {
645 pr_out("%s/%s", bus_name, dev_name);
646 }
647
648 static void pr_out_handle(struct nlattr **tb)
649 {
650 __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
651 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]));
652 }
653
654 static void __pr_out_port_handle(const char *bus_name, const char *dev_name,
655 uint32_t port_index)
656 {
657 __pr_out_handle(bus_name, dev_name);
658 pr_out("/%d", port_index);
659 }
660
661 static void pr_out_port_handle(struct nlattr **tb)
662 {
663 __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
664 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]),
665 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]));
666 }
667
668 static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name,
669 const char *dev_name, uint32_t port_index)
670 {
671 char *ifname;
672 int err;
673
674 if (dl->no_nice_names)
675 goto no_nice_names;
676
677 err = ifname_map_rev_lookup(dl, bus_name, dev_name,
678 port_index, &ifname);
679 if (err)
680 goto no_nice_names;
681 pr_out("%s", ifname);
682 return;
683
684 no_nice_names:
685 __pr_out_port_handle(bus_name, dev_name, port_index);
686 }
687
688 static void pr_out_dev(struct nlattr **tb)
689 {
690 pr_out_handle(tb);
691 pr_out("\n");
692 }
693
694 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
695 {
696 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
697 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
698
699 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
700 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
701 return MNL_CB_ERROR;
702 pr_out_dev(tb);
703 return MNL_CB_OK;
704 }
705
706 static int cmd_dev_show(struct dl *dl)
707 {
708 struct nlmsghdr *nlh;
709 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
710 int err;
711
712 if (dl_argc(dl) == 0)
713 flags |= NLM_F_DUMP;
714
715 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
716
717 if (dl_argc(dl) > 0) {
718 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
719 if (err)
720 return err;
721 }
722
723 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL);
724 }
725
726 static int cmd_dev(struct dl *dl)
727 {
728 if (dl_argv_match(dl, "help")) {
729 cmd_dev_help();
730 return 0;
731 } else if (dl_argv_match(dl, "show") ||
732 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
733 dl_arg_inc(dl);
734 return cmd_dev_show(dl);
735 }
736 pr_err("Command \"%s\" not found\n", dl_argv(dl));
737 return -ENOENT;
738 }
739
740 static void cmd_port_help(void)
741 {
742 pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
743 pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
744 pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n");
745 pr_out(" devlink port unsplit DEV/PORT_INDEX\n");
746 }
747
748 static const char *port_type_name(uint32_t type)
749 {
750 switch (type) {
751 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
752 case DEVLINK_PORT_TYPE_AUTO: return "auto";
753 case DEVLINK_PORT_TYPE_ETH: return "eth";
754 case DEVLINK_PORT_TYPE_IB: return "ib";
755 default: return "<unknown type>";
756 }
757 }
758
759 static void pr_out_port(struct nlattr **tb)
760 {
761 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
762 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
763
764 pr_out_port_handle(tb);
765 pr_out(":");
766 if (pt_attr) {
767 uint16_t port_type = mnl_attr_get_u16(pt_attr);
768
769 pr_out(" type %s", port_type_name(port_type));
770 if (dpt_attr) {
771 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
772
773 if (port_type != des_port_type)
774 pr_out("(%s)", port_type_name(des_port_type));
775 }
776 }
777 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
778 pr_out(" netdev %s",
779 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
780 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
781 pr_out(" ibdev %s",
782 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
783 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
784 pr_out(" split_group %u",
785 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
786 pr_out("\n");
787 }
788
789 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
790 {
791 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
792 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
793
794 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
795 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
796 !tb[DEVLINK_ATTR_PORT_INDEX])
797 return MNL_CB_ERROR;
798 pr_out_port(tb);
799 return MNL_CB_OK;
800 }
801
802 static int cmd_port_show(struct dl *dl)
803 {
804 struct nlmsghdr *nlh;
805 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
806 int err;
807
808 if (dl_argc(dl) == 0)
809 flags |= NLM_F_DUMP;
810
811 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
812
813 if (dl_argc(dl) > 0) {
814 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
815 if (err)
816 return err;
817 }
818
819 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL);
820 }
821
822 static int cmd_port_set(struct dl *dl)
823 {
824 struct nlmsghdr *nlh;
825 int err;
826
827 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
828 NLM_F_REQUEST | NLM_F_ACK);
829
830 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
831 if (err)
832 return err;
833
834 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
835 }
836
837 static int cmd_port_split(struct dl *dl)
838 {
839 struct nlmsghdr *nlh;
840 int err;
841
842 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
843 NLM_F_REQUEST | NLM_F_ACK);
844
845 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
846 if (err)
847 return err;
848
849 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
850 }
851
852 static int cmd_port_unsplit(struct dl *dl)
853 {
854 struct nlmsghdr *nlh;
855 int err;
856
857 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
858 NLM_F_REQUEST | NLM_F_ACK);
859
860 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
861 if (err)
862 return err;
863
864 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
865 }
866
867 static int cmd_port(struct dl *dl)
868 {
869 if (dl_argv_match(dl, "help")) {
870 cmd_port_help();
871 return 0;
872 } else if (dl_argv_match(dl, "show") ||
873 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
874 dl_arg_inc(dl);
875 return cmd_port_show(dl);
876 } else if (dl_argv_match(dl, "set")) {
877 dl_arg_inc(dl);
878 return cmd_port_set(dl);
879 } else if (dl_argv_match(dl, "split")) {
880 dl_arg_inc(dl);
881 return cmd_port_split(dl);
882 } else if (dl_argv_match(dl, "unsplit")) {
883 dl_arg_inc(dl);
884 return cmd_port_unsplit(dl);
885 }
886 pr_err("Command \"%s\" not found\n", dl_argv(dl));
887 return -ENOENT;
888 }
889
890 static const char *cmd_name(uint8_t cmd)
891 {
892 switch (cmd) {
893 case DEVLINK_CMD_UNSPEC: return "unspec";
894 case DEVLINK_CMD_GET: return "get";
895 case DEVLINK_CMD_SET: return "set";
896 case DEVLINK_CMD_NEW: return "new";
897 case DEVLINK_CMD_DEL: return "del";
898 case DEVLINK_CMD_PORT_GET: return "get";
899 case DEVLINK_CMD_PORT_SET: return "set";
900 case DEVLINK_CMD_PORT_NEW: return "net";
901 case DEVLINK_CMD_PORT_DEL: return "del";
902 default: return "<unknown cmd>";
903 }
904 }
905
906 static const char *cmd_obj(uint8_t cmd)
907 {
908 switch (cmd) {
909 case DEVLINK_CMD_UNSPEC: return "unspec";
910 case DEVLINK_CMD_GET:
911 case DEVLINK_CMD_SET:
912 case DEVLINK_CMD_NEW:
913 case DEVLINK_CMD_DEL:
914 return "dev";
915 case DEVLINK_CMD_PORT_GET:
916 case DEVLINK_CMD_PORT_SET:
917 case DEVLINK_CMD_PORT_NEW:
918 case DEVLINK_CMD_PORT_DEL:
919 return "port";
920 default: return "<unknown obj>";
921 }
922 }
923
924 static void pr_out_mon_header(uint8_t cmd)
925 {
926 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
927 }
928
929 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
930 {
931 const char *obj = cmd_obj(cmd);
932 unsigned int index = 0;
933 const char *cur_obj;
934
935 if (dl_no_arg(dl))
936 return true;
937 while ((cur_obj = dl_argv_index(dl, index++))) {
938 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
939 return true;
940 }
941 return false;
942 }
943
944 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
945 {
946 struct dl *dl = data;
947 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
948 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
949 uint8_t cmd = genl->cmd;
950
951 if (!cmd_filter_check(dl, cmd))
952 return MNL_CB_OK;
953
954 switch (cmd) {
955 case DEVLINK_CMD_GET: /* fall through */
956 case DEVLINK_CMD_SET: /* fall through */
957 case DEVLINK_CMD_NEW: /* fall through */
958 case DEVLINK_CMD_DEL:
959 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
960 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
961 return MNL_CB_ERROR;
962 pr_out_mon_header(genl->cmd);
963 pr_out_dev(tb);
964 break;
965 case DEVLINK_CMD_PORT_GET: /* fall through */
966 case DEVLINK_CMD_PORT_SET: /* fall through */
967 case DEVLINK_CMD_PORT_NEW: /* fall through */
968 case DEVLINK_CMD_PORT_DEL:
969 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
970 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
971 !tb[DEVLINK_ATTR_PORT_INDEX])
972 return MNL_CB_ERROR;
973 pr_out_mon_header(genl->cmd);
974 pr_out_port(tb);
975 break;
976 }
977 return MNL_CB_OK;
978 }
979
980 static int cmd_mon_show(struct dl *dl)
981 {
982 int err;
983 unsigned int index = 0;
984 const char *cur_obj;
985
986 while ((cur_obj = dl_argv_index(dl, index++))) {
987 if (strcmp(cur_obj, "all") != 0 &&
988 strcmp(cur_obj, "dev") != 0 &&
989 strcmp(cur_obj, "port") != 0) {
990 pr_err("Unknown object \"%s\"\n", cur_obj);
991 return -EINVAL;
992 }
993 }
994 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
995 if (err)
996 return err;
997 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
998 if (err)
999 return err;
1000 return 0;
1001 }
1002
1003 static void cmd_mon_help(void)
1004 {
1005 pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
1006 "where OBJECT-LIST := { dev | port }\n");
1007 }
1008
1009 static int cmd_mon(struct dl *dl)
1010 {
1011 if (dl_argv_match(dl, "help")) {
1012 cmd_mon_help();
1013 return 0;
1014 } else if (dl_no_arg(dl)) {
1015 dl_arg_inc(dl);
1016 return cmd_mon_show(dl);
1017 }
1018 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1019 return -ENOENT;
1020 }
1021
1022 static void help(void)
1023 {
1024 pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
1025 "where OBJECT := { dev | port | monitor }\n"
1026 " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n");
1027 }
1028
1029 static int dl_cmd(struct dl *dl)
1030 {
1031 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1032 help();
1033 return 0;
1034 } else if (dl_argv_match(dl, "dev")) {
1035 dl_arg_inc(dl);
1036 return cmd_dev(dl);
1037 } else if (dl_argv_match(dl, "port")) {
1038 dl_arg_inc(dl);
1039 return cmd_port(dl);
1040 } else if (dl_argv_match(dl, "monitor")) {
1041 dl_arg_inc(dl);
1042 return cmd_mon(dl);
1043 }
1044 pr_err("Object \"%s\" not found\n", dl_argv(dl));
1045 return -ENOENT;
1046 }
1047
1048 static int dl_init(struct dl *dl, int argc, char **argv)
1049 {
1050 int err;
1051
1052 dl->argc = argc;
1053 dl->argv = argv;
1054
1055 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
1056 if (!dl->nlg) {
1057 pr_err("Failed to connect to devlink Netlink\n");
1058 return -errno;
1059 }
1060
1061 err = ifname_map_init(dl);
1062 if (err) {
1063 pr_err("Failed to create index map\n");
1064 goto err_ifname_map_create;
1065 }
1066 return 0;
1067
1068 err_ifname_map_create:
1069 mnlg_socket_close(dl->nlg);
1070 return err;
1071 }
1072
1073 static void dl_fini(struct dl *dl)
1074 {
1075 ifname_map_fini(dl);
1076 mnlg_socket_close(dl->nlg);
1077 }
1078
1079 static struct dl *dl_alloc(void)
1080 {
1081 struct dl *dl;
1082
1083 dl = calloc(1, sizeof(*dl));
1084 if (!dl)
1085 return NULL;
1086 return dl;
1087 }
1088
1089 static void dl_free(struct dl *dl)
1090 {
1091 free(dl);
1092 }
1093
1094 int main(int argc, char **argv)
1095 {
1096 static const struct option long_options[] = {
1097 { "Version", no_argument, NULL, 'V' },
1098 { "no-nice-names", no_argument, NULL, 'n' },
1099 { NULL, 0, NULL, 0 }
1100 };
1101 struct dl *dl;
1102 int opt;
1103 int err;
1104 int ret;
1105
1106 dl = dl_alloc();
1107 if (!dl) {
1108 pr_err("Failed to allocate memory for devlink\n");
1109 return EXIT_FAILURE;
1110 }
1111
1112 while ((opt = getopt_long(argc, argv, "Vn",
1113 long_options, NULL)) >= 0) {
1114
1115 switch (opt) {
1116 case 'V':
1117 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
1118 return EXIT_SUCCESS;
1119 case 'n':
1120 dl->no_nice_names = true;
1121 break;
1122 default:
1123 pr_err("Unknown option.\n");
1124 help();
1125 return EXIT_FAILURE;
1126 }
1127 }
1128
1129 argc -= optind;
1130 argv += optind;
1131
1132 err = dl_init(dl, argc, argv);
1133 if (err) {
1134 ret = EXIT_FAILURE;
1135 goto dl_free;
1136 }
1137
1138 err = dl_cmd(dl);
1139 if (err) {
1140 ret = EXIT_FAILURE;
1141 goto dl_fini;
1142 }
1143
1144 ret = EXIT_SUCCESS;
1145
1146 dl_fini:
1147 dl_fini(dl);
1148 dl_free:
1149 dl_free(dl);
1150
1151 return ret;
1152 }