]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
devlink: remove more unused code
[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 unsigned int strslashcount(char *str)
311 {
312 unsigned int count = 0;
313 char *pos = str;
314
315 while ((pos = strchr(pos, '/'))) {
316 count++;
317 pos++;
318 }
319 return count;
320 }
321
322 static int strslashrsplit(char *str, char **before, char **after)
323 {
324 char *slash;
325
326 slash = strrchr(str, '/');
327 if (!slash)
328 return -EINVAL;
329 *slash = '\0';
330 *before = str;
331 *after = slash + 1;
332 return 0;
333 }
334
335 static int strtouint32_t(const char *str, uint32_t *p_val)
336 {
337 char *endptr;
338 unsigned long int val;
339
340 val = strtoul(str, &endptr, 10);
341 if (endptr == str || *endptr != '\0')
342 return -EINVAL;
343 if (val > UINT_MAX)
344 return -ERANGE;
345 *p_val = val;
346 return 0;
347 }
348
349 static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
350 {
351 strslashrsplit(str, p_bus_name, p_dev_name);
352 return 0;
353 }
354
355 static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
356 {
357 char *str = dl_argv_next(dl);
358
359 if (!str) {
360 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
361 return -EINVAL;
362 }
363 if (strslashcount(str) != 1) {
364 pr_err("Wrong devlink identification string format.\n");
365 pr_err("Expected \"bus_name/dev_name\".\n");
366 return -EINVAL;
367 }
368 return __dl_argv_handle(str, p_bus_name, p_dev_name);
369 }
370
371 static int __dl_argv_handle_port(char *str,
372 char **p_bus_name, char **p_dev_name,
373 uint32_t *p_port_index)
374 {
375 char *handlestr = handlestr;
376 char *portstr = portstr;
377 int err;
378
379 strslashrsplit(str, &handlestr, &portstr);
380 err = strtouint32_t(portstr, p_port_index);
381 if (err) {
382 pr_err("Port index \"%s\" is not a number or not within range\n",
383 portstr);
384 return err;
385 }
386 strslashrsplit(handlestr, p_bus_name, p_dev_name);
387 return 0;
388 }
389
390 static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
391 char **p_bus_name, char **p_dev_name,
392 uint32_t *p_port_index)
393 {
394 int err;
395
396 err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
397 p_port_index);
398 if (err) {
399 pr_err("Netdevice \"%s\" not found\n", str);
400 return err;
401 }
402 return 0;
403 }
404
405 static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
406 char **p_dev_name, uint32_t *p_port_index)
407 {
408 char *str = dl_argv_next(dl);
409 unsigned int slash_count;
410
411 if (!str) {
412 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
413 return -EINVAL;
414 }
415 slash_count = strslashcount(str);
416 if (slash_count != 2 && slash_count != 0) {
417 pr_err("Wrong port identification string format.\n");
418 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
419 return -EINVAL;
420 }
421 if (slash_count == 2) {
422 return __dl_argv_handle_port(str, p_bus_name,
423 p_dev_name, p_port_index);
424 } else if (slash_count == 0) {
425 return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
426 p_dev_name, p_port_index);
427 }
428 return 0;
429 }
430
431 static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
432 char **p_dev_name, uint32_t *p_port_index,
433 uint32_t *p_handle_bit)
434 {
435 char *str = dl_argv_next(dl);
436 unsigned int slash_count;
437 int err;
438
439 if (!str) {
440 pr_err("One of following identifications expected:\n"
441 "Devlink identification (\"bus_name/dev_name\")\n"
442 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
443 return -EINVAL;
444 }
445 slash_count = strslashcount(str);
446 if (slash_count == 1) {
447 err = __dl_argv_handle(str, p_bus_name, p_dev_name);
448 if (err)
449 return err;
450 *p_handle_bit = DL_OPT_HANDLE;
451 } else if (slash_count == 2) {
452 err = __dl_argv_handle_port(str, p_bus_name,
453 p_dev_name, p_port_index);
454 if (err)
455 return err;
456 *p_handle_bit = DL_OPT_HANDLEP;
457 } else if (slash_count == 0) {
458 err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
459 p_dev_name, p_port_index);
460 if (err)
461 return err;
462 *p_handle_bit = DL_OPT_HANDLEP;
463 } else {
464 pr_err("Wrong port identification string format.\n");
465 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
466 return -EINVAL;
467 }
468 return 0;
469 }
470
471 static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
472 {
473 char *str = dl_argv_next(dl);
474 int err;
475
476 if (!str) {
477 pr_err("Unsigned number argument expected\n");
478 return -EINVAL;
479 }
480
481 err = strtouint32_t(str, p_val);
482 if (err) {
483 pr_err("\"%s\" is not a number or not within range\n", str);
484 return err;
485 }
486 return 0;
487 }
488
489 static int dl_argv_str(struct dl *dl, const char **p_str)
490 {
491 const char *str = dl_argv_next(dl);
492
493 if (!str) {
494 pr_err("String parameter expected\n");
495 return -EINVAL;
496 }
497 *p_str = str;
498 return 0;
499 }
500
501 static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
502 {
503 if (strcmp(typestr, "auto") == 0) {
504 *p_type = DEVLINK_PORT_TYPE_AUTO;
505 } else if (strcmp(typestr, "eth") == 0) {
506 *p_type = DEVLINK_PORT_TYPE_ETH;
507 } else if (strcmp(typestr, "ib") == 0) {
508 *p_type = DEVLINK_PORT_TYPE_IB;
509 } else {
510 pr_err("Unknown port type \"%s\"\n", typestr);
511 return -EINVAL;
512 }
513 return 0;
514 }
515
516 static int dl_argv_parse(struct dl *dl, uint32_t o_required,
517 uint32_t o_optional)
518 {
519 struct dl_opts *opts = &dl->opts;
520 uint32_t o_all = o_required | o_optional;
521 uint32_t o_found = 0;
522 int err;
523
524 if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
525 uint32_t handle_bit = handle_bit;
526
527 err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
528 &opts->port_index, &handle_bit);
529 if (err)
530 return err;
531 o_found |= handle_bit;
532 } else if (o_required & DL_OPT_HANDLE) {
533 err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
534 if (err)
535 return err;
536 o_found |= DL_OPT_HANDLE;
537 } else if (o_required & DL_OPT_HANDLEP) {
538 err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
539 &opts->port_index);
540 if (err)
541 return err;
542 o_found |= DL_OPT_HANDLEP;
543 }
544
545 while (dl_argc(dl)) {
546 if (dl_argv_match(dl, "type") &&
547 (o_all & DL_OPT_PORT_TYPE)) {
548 const char *typestr;
549
550 dl_arg_inc(dl);
551 err = dl_argv_str(dl, &typestr);
552 if (err)
553 return err;
554 err = port_type_get(typestr, &opts->port_type);
555 if (err)
556 return err;
557 o_found |= DL_OPT_PORT_TYPE;
558 } else if (dl_argv_match(dl, "count") &&
559 (o_all & DL_OPT_PORT_COUNT)) {
560 dl_arg_inc(dl);
561 err = dl_argv_uint32_t(dl, &opts->port_count);
562 if (err)
563 return err;
564 o_found |= DL_OPT_PORT_COUNT;
565 } else {
566 pr_err("Unknown option \"%s\"\n", dl_argv(dl));
567 return -EINVAL;
568 }
569 }
570
571 opts->present = o_found;
572
573 if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) {
574 pr_err("Port type option expected.\n");
575 return -EINVAL;
576 }
577
578 if ((o_required & DL_OPT_PORT_COUNT) &&
579 !(o_found & DL_OPT_PORT_COUNT)) {
580 pr_err("Port split count option expected.\n");
581 return -EINVAL;
582 }
583
584 return 0;
585 }
586
587 static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
588 {
589 struct dl_opts *opts = &dl->opts;
590
591 if (opts->present & DL_OPT_HANDLE) {
592 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
593 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
594 } else if (opts->present & DL_OPT_HANDLEP) {
595 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
596 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
597 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
598 opts->port_index);
599 }
600 if (opts->present & DL_OPT_PORT_TYPE)
601 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
602 opts->port_type);
603 if (opts->present & DL_OPT_PORT_COUNT)
604 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
605 opts->port_count);
606 }
607
608 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
609 uint32_t o_required, uint32_t o_optional)
610 {
611 int err;
612
613 err = dl_argv_parse(dl, o_required, o_optional);
614 if (err)
615 return err;
616 dl_opts_put(nlh, dl);
617 return 0;
618 }
619
620
621 static void cmd_dev_help(void)
622 {
623 pr_out("Usage: devlink dev show [ DEV ]\n");
624 }
625
626 static void __pr_out_handle(const char *bus_name, const char *dev_name)
627 {
628 pr_out("%s/%s", bus_name, dev_name);
629 }
630
631 static void pr_out_handle(struct nlattr **tb)
632 {
633 __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
634 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]));
635 }
636
637 static void __pr_out_port_handle(const char *bus_name, const char *dev_name,
638 uint32_t port_index)
639 {
640 __pr_out_handle(bus_name, dev_name);
641 pr_out("/%d", port_index);
642 }
643
644 static void pr_out_port_handle(struct nlattr **tb)
645 {
646 __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
647 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]),
648 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]));
649 }
650
651 static void pr_out_dev(struct nlattr **tb)
652 {
653 pr_out_handle(tb);
654 pr_out("\n");
655 }
656
657 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
658 {
659 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
660 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
661
662 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
663 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
664 return MNL_CB_ERROR;
665 pr_out_dev(tb);
666 return MNL_CB_OK;
667 }
668
669 static int cmd_dev_show(struct dl *dl)
670 {
671 struct nlmsghdr *nlh;
672 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
673 int err;
674
675 if (dl_argc(dl) == 0)
676 flags |= NLM_F_DUMP;
677
678 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
679
680 if (dl_argc(dl) > 0) {
681 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
682 if (err)
683 return err;
684 }
685
686 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL);
687 }
688
689 static int cmd_dev(struct dl *dl)
690 {
691 if (dl_argv_match(dl, "help")) {
692 cmd_dev_help();
693 return 0;
694 } else if (dl_argv_match(dl, "show") ||
695 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
696 dl_arg_inc(dl);
697 return cmd_dev_show(dl);
698 }
699 pr_err("Command \"%s\" not found\n", dl_argv(dl));
700 return -ENOENT;
701 }
702
703 static void cmd_port_help(void)
704 {
705 pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
706 pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
707 pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n");
708 pr_out(" devlink port unsplit DEV/PORT_INDEX\n");
709 }
710
711 static const char *port_type_name(uint32_t type)
712 {
713 switch (type) {
714 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
715 case DEVLINK_PORT_TYPE_AUTO: return "auto";
716 case DEVLINK_PORT_TYPE_ETH: return "eth";
717 case DEVLINK_PORT_TYPE_IB: return "ib";
718 default: return "<unknown type>";
719 }
720 }
721
722 static void pr_out_port(struct nlattr **tb)
723 {
724 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
725 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
726
727 pr_out_port_handle(tb);
728 pr_out(":");
729 if (pt_attr) {
730 uint16_t port_type = mnl_attr_get_u16(pt_attr);
731
732 pr_out(" type %s", port_type_name(port_type));
733 if (dpt_attr) {
734 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
735
736 if (port_type != des_port_type)
737 pr_out("(%s)", port_type_name(des_port_type));
738 }
739 }
740 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
741 pr_out(" netdev %s",
742 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
743 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
744 pr_out(" ibdev %s",
745 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
746 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
747 pr_out(" split_group %u",
748 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
749 pr_out("\n");
750 }
751
752 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
753 {
754 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
755 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
756
757 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
758 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
759 !tb[DEVLINK_ATTR_PORT_INDEX])
760 return MNL_CB_ERROR;
761 pr_out_port(tb);
762 return MNL_CB_OK;
763 }
764
765 static int cmd_port_show(struct dl *dl)
766 {
767 struct nlmsghdr *nlh;
768 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
769 int err;
770
771 if (dl_argc(dl) == 0)
772 flags |= NLM_F_DUMP;
773
774 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
775
776 if (dl_argc(dl) > 0) {
777 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
778 if (err)
779 return err;
780 }
781
782 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL);
783 }
784
785 static int cmd_port_set(struct dl *dl)
786 {
787 struct nlmsghdr *nlh;
788 int err;
789
790 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
791 NLM_F_REQUEST | NLM_F_ACK);
792
793 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
794 if (err)
795 return err;
796
797 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
798 }
799
800 static int cmd_port_split(struct dl *dl)
801 {
802 struct nlmsghdr *nlh;
803 int err;
804
805 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
806 NLM_F_REQUEST | NLM_F_ACK);
807
808 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
809 if (err)
810 return err;
811
812 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
813 }
814
815 static int cmd_port_unsplit(struct dl *dl)
816 {
817 struct nlmsghdr *nlh;
818 int err;
819
820 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
821 NLM_F_REQUEST | NLM_F_ACK);
822
823 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
824 if (err)
825 return err;
826
827 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
828 }
829
830 static int cmd_port(struct dl *dl)
831 {
832 if (dl_argv_match(dl, "help")) {
833 cmd_port_help();
834 return 0;
835 } else if (dl_argv_match(dl, "show") ||
836 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
837 dl_arg_inc(dl);
838 return cmd_port_show(dl);
839 } else if (dl_argv_match(dl, "set")) {
840 dl_arg_inc(dl);
841 return cmd_port_set(dl);
842 } else if (dl_argv_match(dl, "split")) {
843 dl_arg_inc(dl);
844 return cmd_port_split(dl);
845 } else if (dl_argv_match(dl, "unsplit")) {
846 dl_arg_inc(dl);
847 return cmd_port_unsplit(dl);
848 }
849 pr_err("Command \"%s\" not found\n", dl_argv(dl));
850 return -ENOENT;
851 }
852
853 static const char *cmd_name(uint8_t cmd)
854 {
855 switch (cmd) {
856 case DEVLINK_CMD_UNSPEC: return "unspec";
857 case DEVLINK_CMD_GET: return "get";
858 case DEVLINK_CMD_SET: return "set";
859 case DEVLINK_CMD_NEW: return "new";
860 case DEVLINK_CMD_DEL: return "del";
861 case DEVLINK_CMD_PORT_GET: return "get";
862 case DEVLINK_CMD_PORT_SET: return "set";
863 case DEVLINK_CMD_PORT_NEW: return "net";
864 case DEVLINK_CMD_PORT_DEL: return "del";
865 default: return "<unknown cmd>";
866 }
867 }
868
869 static const char *cmd_obj(uint8_t cmd)
870 {
871 switch (cmd) {
872 case DEVLINK_CMD_UNSPEC: return "unspec";
873 case DEVLINK_CMD_GET:
874 case DEVLINK_CMD_SET:
875 case DEVLINK_CMD_NEW:
876 case DEVLINK_CMD_DEL:
877 return "dev";
878 case DEVLINK_CMD_PORT_GET:
879 case DEVLINK_CMD_PORT_SET:
880 case DEVLINK_CMD_PORT_NEW:
881 case DEVLINK_CMD_PORT_DEL:
882 return "port";
883 default: return "<unknown obj>";
884 }
885 }
886
887 static void pr_out_mon_header(uint8_t cmd)
888 {
889 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
890 }
891
892 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
893 {
894 const char *obj = cmd_obj(cmd);
895 unsigned int index = 0;
896 const char *cur_obj;
897
898 if (dl_no_arg(dl))
899 return true;
900 while ((cur_obj = dl_argv_index(dl, index++))) {
901 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
902 return true;
903 }
904 return false;
905 }
906
907 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
908 {
909 struct dl *dl = data;
910 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
911 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
912 uint8_t cmd = genl->cmd;
913
914 if (!cmd_filter_check(dl, cmd))
915 return MNL_CB_OK;
916
917 switch (cmd) {
918 case DEVLINK_CMD_GET: /* fall through */
919 case DEVLINK_CMD_SET: /* fall through */
920 case DEVLINK_CMD_NEW: /* fall through */
921 case DEVLINK_CMD_DEL:
922 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
923 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
924 return MNL_CB_ERROR;
925 pr_out_mon_header(genl->cmd);
926 pr_out_dev(tb);
927 break;
928 case DEVLINK_CMD_PORT_GET: /* fall through */
929 case DEVLINK_CMD_PORT_SET: /* fall through */
930 case DEVLINK_CMD_PORT_NEW: /* fall through */
931 case DEVLINK_CMD_PORT_DEL:
932 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
933 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
934 !tb[DEVLINK_ATTR_PORT_INDEX])
935 return MNL_CB_ERROR;
936 pr_out_mon_header(genl->cmd);
937 pr_out_port(tb);
938 break;
939 }
940 return MNL_CB_OK;
941 }
942
943 static int cmd_mon_show(struct dl *dl)
944 {
945 int err;
946 unsigned int index = 0;
947 const char *cur_obj;
948
949 while ((cur_obj = dl_argv_index(dl, index++))) {
950 if (strcmp(cur_obj, "all") != 0 &&
951 strcmp(cur_obj, "dev") != 0 &&
952 strcmp(cur_obj, "port") != 0) {
953 pr_err("Unknown object \"%s\"\n", cur_obj);
954 return -EINVAL;
955 }
956 }
957 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
958 if (err)
959 return err;
960 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
961 if (err)
962 return err;
963 return 0;
964 }
965
966 static void cmd_mon_help(void)
967 {
968 pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
969 "where OBJECT-LIST := { dev | port }\n");
970 }
971
972 static int cmd_mon(struct dl *dl)
973 {
974 if (dl_argv_match(dl, "help")) {
975 cmd_mon_help();
976 return 0;
977 } else if (dl_no_arg(dl)) {
978 dl_arg_inc(dl);
979 return cmd_mon_show(dl);
980 }
981 pr_err("Command \"%s\" not found\n", dl_argv(dl));
982 return -ENOENT;
983 }
984
985 static void help(void)
986 {
987 pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
988 "where OBJECT := { dev | port | monitor }\n"
989 " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n");
990 }
991
992 static int dl_cmd(struct dl *dl)
993 {
994 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
995 help();
996 return 0;
997 } else if (dl_argv_match(dl, "dev")) {
998 dl_arg_inc(dl);
999 return cmd_dev(dl);
1000 } else if (dl_argv_match(dl, "port")) {
1001 dl_arg_inc(dl);
1002 return cmd_port(dl);
1003 } else if (dl_argv_match(dl, "monitor")) {
1004 dl_arg_inc(dl);
1005 return cmd_mon(dl);
1006 }
1007 pr_err("Object \"%s\" not found\n", dl_argv(dl));
1008 return -ENOENT;
1009 }
1010
1011 static int dl_init(struct dl *dl, int argc, char **argv)
1012 {
1013 int err;
1014
1015 dl->argc = argc;
1016 dl->argv = argv;
1017
1018 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
1019 if (!dl->nlg) {
1020 pr_err("Failed to connect to devlink Netlink\n");
1021 return -errno;
1022 }
1023
1024 err = ifname_map_init(dl);
1025 if (err) {
1026 pr_err("Failed to create index map\n");
1027 goto err_ifname_map_create;
1028 }
1029 return 0;
1030
1031 err_ifname_map_create:
1032 mnlg_socket_close(dl->nlg);
1033 return err;
1034 }
1035
1036 static void dl_fini(struct dl *dl)
1037 {
1038 ifname_map_fini(dl);
1039 mnlg_socket_close(dl->nlg);
1040 }
1041
1042 static struct dl *dl_alloc(void)
1043 {
1044 struct dl *dl;
1045
1046 dl = calloc(1, sizeof(*dl));
1047 if (!dl)
1048 return NULL;
1049 return dl;
1050 }
1051
1052 static void dl_free(struct dl *dl)
1053 {
1054 free(dl);
1055 }
1056
1057 int main(int argc, char **argv)
1058 {
1059 static const struct option long_options[] = {
1060 { "Version", no_argument, NULL, 'V' },
1061 { "no-nice-names", no_argument, NULL, 'n' },
1062 { NULL, 0, NULL, 0 }
1063 };
1064 struct dl *dl;
1065 int opt;
1066 int err;
1067 int ret;
1068
1069 dl = dl_alloc();
1070 if (!dl) {
1071 pr_err("Failed to allocate memory for devlink\n");
1072 return EXIT_FAILURE;
1073 }
1074
1075 while ((opt = getopt_long(argc, argv, "Vn",
1076 long_options, NULL)) >= 0) {
1077
1078 switch (opt) {
1079 case 'V':
1080 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
1081 return EXIT_SUCCESS;
1082 case 'n':
1083 dl->no_nice_names = true;
1084 break;
1085 default:
1086 pr_err("Unknown option.\n");
1087 help();
1088 return EXIT_FAILURE;
1089 }
1090 }
1091
1092 argc -= optind;
1093 argv += optind;
1094
1095 err = dl_init(dl, argc, argv);
1096 if (err) {
1097 ret = EXIT_FAILURE;
1098 goto dl_free;
1099 }
1100
1101 err = dl_cmd(dl);
1102 if (err) {
1103 ret = EXIT_FAILURE;
1104 goto dl_fini;
1105 }
1106
1107 ret = EXIT_SUCCESS;
1108
1109 dl_fini:
1110 dl_fini(dl);
1111 dl_free:
1112 dl_free(dl);
1113
1114 return ret;
1115 }