2 * devlink.c Devlink tool
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.
9 * Authors: Jiri Pirko <jiri@mellanox.com>
20 #include <linux/genetlink.h>
21 #include <linux/devlink.h>
22 #include <libmnl/libmnl.h>
28 #define pr_err(args...) fprintf(stderr, ##args)
29 #define pr_out(args...) fprintf(stdout, ##args)
31 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
32 mnl_cb_t data_cb
, void *data
)
36 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
38 pr_err("devlink answers: %s\n", strerror(errno
));
44 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
45 const struct nlmsghdr
*nlh
,
46 mnl_cb_t data_cb
, void *data
)
50 err
= mnlg_socket_send(nlg
, nlh
);
52 pr_err("Failed to call mnlg_socket_send\n");
55 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
58 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
59 const char *group_name
)
63 err
= mnlg_socket_group_add(nlg
, group_name
);
65 pr_err("Failed to call mnlg_socket_group_add\n");
72 struct list_head list
;
79 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
84 struct ifname_map
*ifname_map
;
86 ifname_map
= calloc(1, sizeof(*ifname_map
));
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
);
104 static void ifname_map_free(struct ifname_map
*ifname_map
)
106 free(ifname_map
->ifname
);
107 free(ifname_map
->dev_name
);
108 free(ifname_map
->bus_name
);
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)
119 uint32_t present
; /* flags of present items */
123 enum devlink_port_type port_type
;
128 struct mnlg_socket
*nlg
;
129 struct list_head ifname_map_list
;
136 static int dl_argc(struct dl
*dl
)
141 static char *dl_argv(struct dl
*dl
)
143 if (dl_argc(dl
) == 0)
148 static void dl_arg_inc(struct dl
*dl
)
150 if (dl_argc(dl
) == 0)
156 static char *dl_argv_next(struct dl
*dl
)
160 if (dl_argc(dl
) == 0)
168 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
170 if (index
>= dl_argc(dl
))
172 return dl
->argv
[index
];
175 static int strcmpx(const char *str1
, const char *str2
)
177 if (strlen(str1
) > strlen(str2
))
179 return strncmp(str1
, str2
, strlen(str1
));
182 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
184 if (dl_argc(dl
) == 0)
186 return strcmpx(dl_argv(dl
), pattern
) == 0;
189 static bool dl_no_arg(struct dl
*dl
)
191 return dl_argc(dl
) == 0;
194 static int attr_cb(const struct nlattr
*attr
, void *data
)
196 const struct nlattr
**tb
= data
;
199 type
= mnl_attr_get_type(attr
);
201 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
204 if (type
== DEVLINK_ATTR_BUS_NAME
&&
205 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
207 if (type
== DEVLINK_ATTR_DEV_NAME
&&
208 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
210 if (type
== DEVLINK_ATTR_PORT_INDEX
&&
211 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
213 if (type
== DEVLINK_ATTR_PORT_TYPE
&&
214 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
216 if (type
== DEVLINK_ATTR_PORT_DESIRED_TYPE
&&
217 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
219 if (type
== DEVLINK_ATTR_PORT_NETDEV_IFINDEX
&&
220 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
222 if (type
== DEVLINK_ATTR_PORT_NETDEV_NAME
&&
223 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
225 if (type
== DEVLINK_ATTR_PORT_IBDEV_NAME
&&
226 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
232 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
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
;
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
])
248 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
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
);
259 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
264 static void ifname_map_fini(struct dl
*dl
)
266 struct ifname_map
*ifname_map
, *tmp
;
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
);
275 static int ifname_map_init(struct dl
*dl
)
277 struct nlmsghdr
*nlh
;
280 INIT_LIST_HEAD(&dl
->ifname_map_list
);
282 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
283 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
285 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
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
)
297 struct ifname_map
*ifname_map
;
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
;
310 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
311 const char *dev_name
, uint32_t port_index
,
314 struct ifname_map
*ifname_map
;
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
;
327 static unsigned int strslashcount(char *str
)
329 unsigned int count
= 0;
332 while ((pos
= strchr(pos
, '/'))) {
339 static int strslashrsplit(char *str
, char **before
, char **after
)
343 slash
= strrchr(str
, '/');
352 static int strtouint32_t(const char *str
, uint32_t *p_val
)
355 unsigned long int val
;
357 val
= strtoul(str
, &endptr
, 10);
358 if (endptr
== str
|| *endptr
!= '\0')
366 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
368 strslashrsplit(str
, p_bus_name
, p_dev_name
);
372 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
374 char *str
= dl_argv_next(dl
);
377 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
380 if (strslashcount(str
) != 1) {
381 pr_err("Wrong devlink identification string format.\n");
382 pr_err("Expected \"bus_name/dev_name\".\n");
385 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
388 static int __dl_argv_handle_port(char *str
,
389 char **p_bus_name
, char **p_dev_name
,
390 uint32_t *p_port_index
)
392 char *handlestr
= handlestr
;
393 char *portstr
= portstr
;
396 strslashrsplit(str
, &handlestr
, &portstr
);
397 err
= strtouint32_t(portstr
, p_port_index
);
399 pr_err("Port index \"%s\" is not a number or not within range\n",
403 strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
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
)
413 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
416 pr_err("Netdevice \"%s\" not found\n", str
);
422 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
423 char **p_dev_name
, uint32_t *p_port_index
)
425 char *str
= dl_argv_next(dl
);
426 unsigned int slash_count
;
429 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
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");
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
);
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
)
452 char *str
= dl_argv_next(dl
);
453 unsigned int slash_count
;
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");
462 slash_count
= strslashcount(str
);
463 if (slash_count
== 1) {
464 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
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
);
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
);
479 *p_handle_bit
= DL_OPT_HANDLEP
;
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");
488 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
490 char *str
= dl_argv_next(dl
);
494 pr_err("Unsigned number argument expected\n");
498 err
= strtouint32_t(str
, p_val
);
500 pr_err("\"%s\" is not a number or not within range\n", str
);
506 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
508 const char *str
= dl_argv_next(dl
);
511 pr_err("String parameter expected\n");
518 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
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
;
527 pr_err("Unknown port type \"%s\"\n", typestr
);
533 static int dl_argv_parse(struct dl
*dl
, uint32_t o_required
,
536 struct dl_opts
*opts
= &dl
->opts
;
537 uint32_t o_all
= o_required
| o_optional
;
538 uint32_t o_found
= 0;
541 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
542 uint32_t handle_bit
= handle_bit
;
544 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
545 &opts
->port_index
, &handle_bit
);
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
);
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
,
559 o_found
|= DL_OPT_HANDLEP
;
562 while (dl_argc(dl
)) {
563 if (dl_argv_match(dl
, "type") &&
564 (o_all
& DL_OPT_PORT_TYPE
)) {
568 err
= dl_argv_str(dl
, &typestr
);
571 err
= port_type_get(typestr
, &opts
->port_type
);
574 o_found
|= DL_OPT_PORT_TYPE
;
575 } else if (dl_argv_match(dl
, "count") &&
576 (o_all
& DL_OPT_PORT_COUNT
)) {
578 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
581 o_found
|= DL_OPT_PORT_COUNT
;
583 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
588 opts
->present
= o_found
;
590 if ((o_required
& DL_OPT_PORT_TYPE
) && !(o_found
& DL_OPT_PORT_TYPE
)) {
591 pr_err("Port type option expected.\n");
595 if ((o_required
& DL_OPT_PORT_COUNT
) &&
596 !(o_found
& DL_OPT_PORT_COUNT
)) {
597 pr_err("Port split count option expected.\n");
604 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
606 struct dl_opts
*opts
= &dl
->opts
;
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
,
617 if (opts
->present
& DL_OPT_PORT_TYPE
)
618 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
620 if (opts
->present
& DL_OPT_PORT_COUNT
)
621 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
625 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
626 uint32_t o_required
, uint32_t o_optional
)
630 err
= dl_argv_parse(dl
, o_required
, o_optional
);
633 dl_opts_put(nlh
, dl
);
637 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
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
];
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
);
649 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
650 strcmp(dev_name
, opts
->dev_name
) != 0)
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
);
659 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
660 strcmp(dev_name
, opts
->dev_name
) != 0 ||
661 port_index
!= opts
->port_index
)
667 static void cmd_dev_help(void)
669 pr_out("Usage: devlink dev show [ DEV ]\n");
672 static void __pr_out_handle(const char *bus_name
, const char *dev_name
)
674 pr_out("%s/%s", bus_name
, dev_name
);
677 static void pr_out_handle(struct nlattr
**tb
)
679 __pr_out_handle(mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]),
680 mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]));
683 static void __pr_out_port_handle(const char *bus_name
, const char *dev_name
,
686 __pr_out_handle(bus_name
, dev_name
);
687 pr_out("/%d", port_index
);
690 static void pr_out_port_handle(struct nlattr
**tb
)
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
]));
697 static void __pr_out_port_handle_nice(struct dl
*dl
, const char *bus_name
,
698 const char *dev_name
, uint32_t port_index
)
703 if (dl
->no_nice_names
)
706 err
= ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
707 port_index
, &ifname
);
710 pr_out("%s", ifname
);
714 __pr_out_port_handle(bus_name
, dev_name
, port_index
);
717 static void pr_out_port_handle_nice(struct dl
*dl
, struct nlattr
**tb
)
719 const char *bus_name
;
720 const char *dev_name
;
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
]);
727 __pr_out_port_handle_nice(dl
, bus_name
, dev_name
, port_index
);
730 static void pr_out_dev(struct nlattr
**tb
)
736 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
738 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
739 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
741 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
742 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
748 static int cmd_dev_show(struct dl
*dl
)
750 struct nlmsghdr
*nlh
;
751 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
754 if (dl_argc(dl
) == 0)
757 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
759 if (dl_argc(dl
) > 0) {
760 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
765 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, NULL
);
768 static int cmd_dev(struct dl
*dl
)
770 if (dl_argv_match(dl
, "help")) {
773 } else if (dl_argv_match(dl
, "show") ||
774 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
776 return cmd_dev_show(dl
);
778 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
782 static void cmd_port_help(void)
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");
790 static const char *port_type_name(uint32_t 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>";
801 static void pr_out_port(struct nlattr
**tb
)
803 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
804 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
806 pr_out_port_handle(tb
);
809 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
811 pr_out(" type %s", port_type_name(port_type
));
813 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
815 if (port_type
!= des_port_type
)
816 pr_out("(%s)", port_type_name(des_port_type
));
819 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
821 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
822 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
])
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
]));
831 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
833 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
834 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
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
])
844 static int cmd_port_show(struct dl
*dl
)
846 struct nlmsghdr
*nlh
;
847 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
850 if (dl_argc(dl
) == 0)
853 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
855 if (dl_argc(dl
) > 0) {
856 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
861 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, NULL
);
864 static int cmd_port_set(struct dl
*dl
)
866 struct nlmsghdr
*nlh
;
869 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
870 NLM_F_REQUEST
| NLM_F_ACK
);
872 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
876 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
879 static int cmd_port_split(struct dl
*dl
)
881 struct nlmsghdr
*nlh
;
884 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
885 NLM_F_REQUEST
| NLM_F_ACK
);
887 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
891 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
894 static int cmd_port_unsplit(struct dl
*dl
)
896 struct nlmsghdr
*nlh
;
899 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
900 NLM_F_REQUEST
| NLM_F_ACK
);
902 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
906 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
909 static int cmd_port(struct dl
*dl
)
911 if (dl_argv_match(dl
, "help")) {
914 } else if (dl_argv_match(dl
, "show") ||
915 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
917 return cmd_port_show(dl
);
918 } else if (dl_argv_match(dl
, "set")) {
920 return cmd_port_set(dl
);
921 } else if (dl_argv_match(dl
, "split")) {
923 return cmd_port_split(dl
);
924 } else if (dl_argv_match(dl
, "unsplit")) {
926 return cmd_port_unsplit(dl
);
928 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
932 static const char *cmd_name(uint8_t 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>";
948 static const char *cmd_obj(uint8_t 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
:
957 case DEVLINK_CMD_PORT_GET
:
958 case DEVLINK_CMD_PORT_SET
:
959 case DEVLINK_CMD_PORT_NEW
:
960 case DEVLINK_CMD_PORT_DEL
:
962 default: return "<unknown obj>";
966 static void pr_out_mon_header(uint8_t cmd
)
968 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
971 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
973 const char *obj
= cmd_obj(cmd
);
974 unsigned int index
= 0;
979 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
980 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
986 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
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
;
993 if (!cmd_filter_check(dl
, 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
);
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
);
1022 static int cmd_mon_show(struct dl
*dl
)
1025 unsigned int index
= 0;
1026 const char *cur_obj
;
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
);
1036 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
1039 err
= _mnlg_socket_recv_run(dl
->nlg
, cmd_mon_show_cb
, dl
);
1045 static void cmd_mon_help(void)
1047 pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
1048 "where OBJECT-LIST := { dev | port }\n");
1051 static int cmd_mon(struct dl
*dl
)
1053 if (dl_argv_match(dl
, "help")) {
1056 } else if (dl_no_arg(dl
)) {
1058 return cmd_mon_show(dl
);
1060 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1064 static void help(void)
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");
1071 static int dl_cmd(struct dl
*dl
)
1073 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
1076 } else if (dl_argv_match(dl
, "dev")) {
1079 } else if (dl_argv_match(dl
, "port")) {
1081 return cmd_port(dl
);
1082 } else if (dl_argv_match(dl
, "monitor")) {
1086 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
1090 static int dl_init(struct dl
*dl
, int argc
, char **argv
)
1097 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
1099 pr_err("Failed to connect to devlink Netlink\n");
1103 err
= ifname_map_init(dl
);
1105 pr_err("Failed to create index map\n");
1106 goto err_ifname_map_create
;
1110 err_ifname_map_create
:
1111 mnlg_socket_close(dl
->nlg
);
1115 static void dl_fini(struct dl
*dl
)
1117 ifname_map_fini(dl
);
1118 mnlg_socket_close(dl
->nlg
);
1121 static struct dl
*dl_alloc(void)
1125 dl
= calloc(1, sizeof(*dl
));
1131 static void dl_free(struct dl
*dl
)
1136 int main(int argc
, char **argv
)
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 }
1150 pr_err("Failed to allocate memory for devlink\n");
1151 return EXIT_FAILURE
;
1154 while ((opt
= getopt_long(argc
, argv
, "Vn",
1155 long_options
, NULL
)) >= 0) {
1159 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
1160 return EXIT_SUCCESS
;
1162 dl
->no_nice_names
= true;
1165 pr_err("Unknown option.\n");
1167 return EXIT_FAILURE
;
1174 err
= dl_init(dl
, argc
, argv
);