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