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)
30 #define pr_out_sp(num, args...) \
32 int ret = fprintf(stdout, ##args); \
34 fprintf(stdout, "%*s", num - ret, ""); \
37 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
38 mnl_cb_t data_cb
, void *data
)
42 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
44 pr_err("devlink answers: %s\n", strerror(errno
));
50 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
51 const struct nlmsghdr
*nlh
,
52 mnl_cb_t data_cb
, void *data
)
56 err
= mnlg_socket_send(nlg
, nlh
);
58 pr_err("Failed to call mnlg_socket_send\n");
61 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
64 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
65 const char *group_name
)
69 err
= mnlg_socket_group_add(nlg
, group_name
);
71 pr_err("Failed to call mnlg_socket_group_add\n");
78 struct list_head list
;
85 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
90 struct ifname_map
*ifname_map
;
92 ifname_map
= calloc(1, sizeof(*ifname_map
));
95 ifname_map
->bus_name
= strdup(bus_name
);
96 ifname_map
->dev_name
= strdup(dev_name
);
97 ifname_map
->port_index
= port_index
;
98 ifname_map
->ifname
= strdup(ifname
);
99 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
100 !ifname_map
->ifname
) {
101 free(ifname_map
->ifname
);
102 free(ifname_map
->dev_name
);
103 free(ifname_map
->bus_name
);
110 static void ifname_map_free(struct ifname_map
*ifname_map
)
112 free(ifname_map
->ifname
);
113 free(ifname_map
->dev_name
);
114 free(ifname_map
->bus_name
);
118 #define BIT(nr) (1UL << (nr))
119 #define DL_OPT_HANDLE BIT(0)
120 #define DL_OPT_HANDLEP BIT(1)
121 #define DL_OPT_PORT_TYPE BIT(2)
122 #define DL_OPT_PORT_COUNT BIT(3)
123 #define DL_OPT_SB BIT(4)
124 #define DL_OPT_SB_POOL BIT(5)
125 #define DL_OPT_SB_SIZE BIT(6)
126 #define DL_OPT_SB_TYPE BIT(7)
127 #define DL_OPT_SB_THTYPE BIT(8)
128 #define DL_OPT_SB_TH BIT(9)
129 #define DL_OPT_SB_TC BIT(10)
132 uint32_t present
; /* flags of present items */
136 enum devlink_port_type port_type
;
139 uint16_t sb_pool_index
;
140 uint32_t sb_pool_size
;
141 enum devlink_sb_pool_type sb_pool_type
;
142 enum devlink_sb_threshold_type sb_pool_thtype
;
143 uint32_t sb_threshold
;
144 uint16_t sb_tc_index
;
148 struct mnlg_socket
*nlg
;
149 struct list_head ifname_map_list
;
156 static int dl_argc(struct dl
*dl
)
161 static char *dl_argv(struct dl
*dl
)
163 if (dl_argc(dl
) == 0)
168 static void dl_arg_inc(struct dl
*dl
)
170 if (dl_argc(dl
) == 0)
176 static char *dl_argv_next(struct dl
*dl
)
180 if (dl_argc(dl
) == 0)
188 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
190 if (index
>= dl_argc(dl
))
192 return dl
->argv
[index
];
195 static int strcmpx(const char *str1
, const char *str2
)
197 if (strlen(str1
) > strlen(str2
))
199 return strncmp(str1
, str2
, strlen(str1
));
202 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
204 if (dl_argc(dl
) == 0)
206 return strcmpx(dl_argv(dl
), pattern
) == 0;
209 static bool dl_no_arg(struct dl
*dl
)
211 return dl_argc(dl
) == 0;
214 static int attr_cb(const struct nlattr
*attr
, void *data
)
216 const struct nlattr
**tb
= data
;
219 type
= mnl_attr_get_type(attr
);
221 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
224 if (type
== DEVLINK_ATTR_BUS_NAME
&&
225 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
227 if (type
== DEVLINK_ATTR_DEV_NAME
&&
228 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
230 if (type
== DEVLINK_ATTR_PORT_INDEX
&&
231 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
233 if (type
== DEVLINK_ATTR_PORT_TYPE
&&
234 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
236 if (type
== DEVLINK_ATTR_PORT_DESIRED_TYPE
&&
237 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
239 if (type
== DEVLINK_ATTR_PORT_NETDEV_IFINDEX
&&
240 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
242 if (type
== DEVLINK_ATTR_PORT_NETDEV_NAME
&&
243 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
245 if (type
== DEVLINK_ATTR_PORT_IBDEV_NAME
&&
246 mnl_attr_validate(attr
, MNL_TYPE_NUL_STRING
) < 0)
248 if (type
== DEVLINK_ATTR_SB_INDEX
&&
249 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
251 if (type
== DEVLINK_ATTR_SB_SIZE
&&
252 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
254 if (type
== DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
&&
255 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
257 if (type
== DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
&&
258 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
260 if (type
== DEVLINK_ATTR_SB_INGRESS_TC_COUNT
&&
261 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
263 if (type
== DEVLINK_ATTR_SB_EGRESS_TC_COUNT
&&
264 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
266 if (type
== DEVLINK_ATTR_SB_POOL_INDEX
&&
267 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
269 if (type
== DEVLINK_ATTR_SB_POOL_TYPE
&&
270 mnl_attr_validate(attr
, MNL_TYPE_U8
) < 0)
272 if (type
== DEVLINK_ATTR_SB_POOL_SIZE
&&
273 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
275 if (type
== DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
&&
276 mnl_attr_validate(attr
, MNL_TYPE_U8
) < 0)
278 if (type
== DEVLINK_ATTR_SB_THRESHOLD
&&
279 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
281 if (type
== DEVLINK_ATTR_SB_TC_INDEX
&&
282 mnl_attr_validate(attr
, MNL_TYPE_U16
) < 0)
284 if (type
== DEVLINK_ATTR_SB_OCC_CUR
&&
285 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
287 if (type
== DEVLINK_ATTR_SB_OCC_MAX
&&
288 mnl_attr_validate(attr
, MNL_TYPE_U32
) < 0)
294 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
296 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
297 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
298 struct dl
*dl
= data
;
299 struct ifname_map
*ifname_map
;
300 const char *bus_name
;
301 const char *dev_name
;
302 uint32_t port_ifindex
;
303 const char *port_ifname
;
305 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
306 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
307 !tb
[DEVLINK_ATTR_PORT_INDEX
])
310 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
313 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
314 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
315 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
316 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
317 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
318 port_ifindex
, port_ifname
);
321 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
326 static void ifname_map_fini(struct dl
*dl
)
328 struct ifname_map
*ifname_map
, *tmp
;
330 list_for_each_entry_safe(ifname_map
, tmp
,
331 &dl
->ifname_map_list
, list
) {
332 list_del(&ifname_map
->list
);
333 ifname_map_free(ifname_map
);
337 static int ifname_map_init(struct dl
*dl
)
339 struct nlmsghdr
*nlh
;
342 INIT_LIST_HEAD(&dl
->ifname_map_list
);
344 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
345 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
347 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
355 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
356 char **p_bus_name
, char **p_dev_name
,
357 uint32_t *p_port_index
)
359 struct ifname_map
*ifname_map
;
361 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
362 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
363 *p_bus_name
= ifname_map
->bus_name
;
364 *p_dev_name
= ifname_map
->dev_name
;
365 *p_port_index
= ifname_map
->port_index
;
372 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
373 const char *dev_name
, uint32_t port_index
,
376 struct ifname_map
*ifname_map
;
378 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
379 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
380 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
381 port_index
== ifname_map
->port_index
) {
382 *p_ifname
= ifname_map
->ifname
;
389 static unsigned int strslashcount(char *str
)
391 unsigned int count
= 0;
394 while ((pos
= strchr(pos
, '/'))) {
401 static int strslashrsplit(char *str
, char **before
, char **after
)
405 slash
= strrchr(str
, '/');
414 static int strtouint32_t(const char *str
, uint32_t *p_val
)
417 unsigned long int val
;
419 val
= strtoul(str
, &endptr
, 10);
420 if (endptr
== str
|| *endptr
!= '\0')
428 static int strtouint16_t(const char *str
, uint16_t *p_val
)
431 unsigned long int val
;
433 val
= strtoul(str
, &endptr
, 10);
434 if (endptr
== str
|| *endptr
!= '\0')
442 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
444 strslashrsplit(str
, p_bus_name
, p_dev_name
);
448 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
450 char *str
= dl_argv_next(dl
);
453 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
456 if (strslashcount(str
) != 1) {
457 pr_err("Wrong devlink identification string format.\n");
458 pr_err("Expected \"bus_name/dev_name\".\n");
461 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
464 static int __dl_argv_handle_port(char *str
,
465 char **p_bus_name
, char **p_dev_name
,
466 uint32_t *p_port_index
)
468 char *handlestr
= handlestr
;
469 char *portstr
= portstr
;
472 strslashrsplit(str
, &handlestr
, &portstr
);
473 err
= strtouint32_t(portstr
, p_port_index
);
475 pr_err("Port index \"%s\" is not a number or not within range\n",
479 strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
483 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
484 char **p_bus_name
, char **p_dev_name
,
485 uint32_t *p_port_index
)
489 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
492 pr_err("Netdevice \"%s\" not found\n", str
);
498 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
499 char **p_dev_name
, uint32_t *p_port_index
)
501 char *str
= dl_argv_next(dl
);
502 unsigned int slash_count
;
505 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
508 slash_count
= strslashcount(str
);
509 if (slash_count
!= 2 && slash_count
!= 0) {
510 pr_err("Wrong port identification string format.\n");
511 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
514 if (slash_count
== 2) {
515 return __dl_argv_handle_port(str
, p_bus_name
,
516 p_dev_name
, p_port_index
);
517 } else if (slash_count
== 0) {
518 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
519 p_dev_name
, p_port_index
);
524 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
525 char **p_dev_name
, uint32_t *p_port_index
,
526 uint32_t *p_handle_bit
)
528 char *str
= dl_argv_next(dl
);
529 unsigned int slash_count
;
533 pr_err("One of following identifications expected:\n"
534 "Devlink identification (\"bus_name/dev_name\")\n"
535 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
538 slash_count
= strslashcount(str
);
539 if (slash_count
== 1) {
540 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
543 *p_handle_bit
= DL_OPT_HANDLE
;
544 } else if (slash_count
== 2) {
545 err
= __dl_argv_handle_port(str
, p_bus_name
,
546 p_dev_name
, p_port_index
);
549 *p_handle_bit
= DL_OPT_HANDLEP
;
550 } else if (slash_count
== 0) {
551 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
552 p_dev_name
, p_port_index
);
555 *p_handle_bit
= DL_OPT_HANDLEP
;
557 pr_err("Wrong port identification string format.\n");
558 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
564 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
566 char *str
= dl_argv_next(dl
);
570 pr_err("Unsigned number argument expected\n");
574 err
= strtouint32_t(str
, p_val
);
576 pr_err("\"%s\" is not a number or not within range\n", str
);
582 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
584 char *str
= dl_argv_next(dl
);
588 pr_err("Unsigned number argument expected\n");
592 err
= strtouint16_t(str
, p_val
);
594 pr_err("\"%s\" is not a number or not within range\n", str
);
600 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
602 const char *str
= dl_argv_next(dl
);
605 pr_err("String parameter expected\n");
612 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
614 if (strcmp(typestr
, "auto") == 0) {
615 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
616 } else if (strcmp(typestr
, "eth") == 0) {
617 *p_type
= DEVLINK_PORT_TYPE_ETH
;
618 } else if (strcmp(typestr
, "ib") == 0) {
619 *p_type
= DEVLINK_PORT_TYPE_IB
;
621 pr_err("Unknown port type \"%s\"\n", typestr
);
627 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
629 if (strcmp(typestr
, "ingress") == 0) {
630 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
631 } else if (strcmp(typestr
, "egress") == 0) {
632 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
634 pr_err("Unknown pool type \"%s\"\n", typestr
);
640 static int threshold_type_get(const char *typestr
,
641 enum devlink_sb_threshold_type
*p_type
)
643 if (strcmp(typestr
, "static") == 0) {
644 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
645 } else if (strcmp(typestr
, "dynamic") == 0) {
646 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
648 pr_err("Unknown threshold type \"%s\"\n", typestr
);
654 static int dl_argv_parse(struct dl
*dl
, uint32_t o_required
,
657 struct dl_opts
*opts
= &dl
->opts
;
658 uint32_t o_all
= o_required
| o_optional
;
659 uint32_t o_found
= 0;
662 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
663 uint32_t handle_bit
= handle_bit
;
665 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
666 &opts
->port_index
, &handle_bit
);
669 o_found
|= handle_bit
;
670 } else if (o_required
& DL_OPT_HANDLE
) {
671 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
674 o_found
|= DL_OPT_HANDLE
;
675 } else if (o_required
& DL_OPT_HANDLEP
) {
676 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
680 o_found
|= DL_OPT_HANDLEP
;
683 while (dl_argc(dl
)) {
684 if (dl_argv_match(dl
, "type") &&
685 (o_all
& DL_OPT_PORT_TYPE
)) {
689 err
= dl_argv_str(dl
, &typestr
);
692 err
= port_type_get(typestr
, &opts
->port_type
);
695 o_found
|= DL_OPT_PORT_TYPE
;
696 } else if (dl_argv_match(dl
, "count") &&
697 (o_all
& DL_OPT_PORT_COUNT
)) {
699 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
702 o_found
|= DL_OPT_PORT_COUNT
;
703 } else if (dl_argv_match(dl
, "sb") &&
704 (o_all
& DL_OPT_SB
)) {
706 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
709 o_found
|= DL_OPT_SB
;
710 } else if (dl_argv_match(dl
, "pool") &&
711 (o_all
& DL_OPT_SB_POOL
)) {
713 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
716 o_found
|= DL_OPT_SB_POOL
;
717 } else if (dl_argv_match(dl
, "size") &&
718 (o_all
& DL_OPT_SB_SIZE
)) {
720 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
723 o_found
|= DL_OPT_SB_SIZE
;
724 } else if (dl_argv_match(dl
, "type") &&
725 (o_all
& DL_OPT_SB_TYPE
)) {
729 err
= dl_argv_str(dl
, &typestr
);
732 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
735 o_found
|= DL_OPT_SB_TYPE
;
736 } else if (dl_argv_match(dl
, "thtype") &&
737 (o_all
& DL_OPT_SB_THTYPE
)) {
741 err
= dl_argv_str(dl
, &typestr
);
744 err
= threshold_type_get(typestr
,
745 &opts
->sb_pool_thtype
);
748 o_found
|= DL_OPT_SB_THTYPE
;
749 } else if (dl_argv_match(dl
, "th") &&
750 (o_all
& DL_OPT_SB_TH
)) {
752 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
755 o_found
|= DL_OPT_SB_TH
;
756 } else if (dl_argv_match(dl
, "tc") &&
757 (o_all
& DL_OPT_SB_TC
)) {
759 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
762 o_found
|= DL_OPT_SB_TC
;
764 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
769 opts
->present
= o_found
;
771 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
773 opts
->present
|= DL_OPT_SB
;
776 if ((o_required
& DL_OPT_PORT_TYPE
) && !(o_found
& DL_OPT_PORT_TYPE
)) {
777 pr_err("Port type option expected.\n");
781 if ((o_required
& DL_OPT_PORT_COUNT
) &&
782 !(o_found
& DL_OPT_PORT_COUNT
)) {
783 pr_err("Port split count option expected.\n");
787 if ((o_required
& DL_OPT_SB_POOL
) && !(o_found
& DL_OPT_SB_POOL
)) {
788 pr_err("Pool index option expected.\n");
792 if ((o_required
& DL_OPT_SB_SIZE
) && !(o_found
& DL_OPT_SB_SIZE
)) {
793 pr_err("Pool size option expected.\n");
797 if ((o_required
& DL_OPT_SB_TYPE
) && !(o_found
& DL_OPT_SB_TYPE
)) {
798 pr_err("Pool type option expected.\n");
802 if ((o_required
& DL_OPT_SB_THTYPE
) && !(o_found
& DL_OPT_SB_THTYPE
)) {
803 pr_err("Pool threshold type option expected.\n");
807 if ((o_required
& DL_OPT_SB_TH
) && !(o_found
& DL_OPT_SB_TH
)) {
808 pr_err("Threshold option expected.\n");
812 if ((o_required
& DL_OPT_SB_TC
) && !(o_found
& DL_OPT_SB_TC
)) {
813 pr_err("TC index option expected.\n");
819 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
821 struct dl_opts
*opts
= &dl
->opts
;
823 if (opts
->present
& DL_OPT_HANDLE
) {
824 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
825 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
826 } else if (opts
->present
& DL_OPT_HANDLEP
) {
827 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
828 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
829 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
832 if (opts
->present
& DL_OPT_PORT_TYPE
)
833 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
835 if (opts
->present
& DL_OPT_PORT_COUNT
)
836 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
838 if (opts
->present
& DL_OPT_SB
)
839 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
841 if (opts
->present
& DL_OPT_SB_POOL
)
842 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
843 opts
->sb_pool_index
);
844 if (opts
->present
& DL_OPT_SB_SIZE
)
845 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
847 if (opts
->present
& DL_OPT_SB_TYPE
)
848 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
850 if (opts
->present
& DL_OPT_SB_THTYPE
)
851 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
852 opts
->sb_pool_thtype
);
853 if (opts
->present
& DL_OPT_SB_TH
)
854 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
856 if (opts
->present
& DL_OPT_SB_TC
)
857 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
861 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
862 uint32_t o_required
, uint32_t o_optional
)
866 err
= dl_argv_parse(dl
, o_required
, o_optional
);
869 dl_opts_put(nlh
, dl
);
873 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
875 struct dl_opts
*opts
= &dl
->opts
;
876 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
877 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
878 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
879 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
881 if (opts
->present
& DL_OPT_HANDLE
&&
882 attr_bus_name
&& attr_dev_name
) {
883 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
884 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
886 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
887 strcmp(dev_name
, opts
->dev_name
) != 0)
890 if (opts
->present
& DL_OPT_HANDLEP
&&
891 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
892 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
893 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
894 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
896 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
897 strcmp(dev_name
, opts
->dev_name
) != 0 ||
898 port_index
!= opts
->port_index
)
901 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
902 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
904 if (sb_index
!= opts
->sb_index
)
910 static void cmd_dev_help(void)
912 pr_out("Usage: devlink dev show [ DEV ]\n");
915 static void __pr_out_handle(const char *bus_name
, const char *dev_name
)
917 pr_out("%s/%s", bus_name
, dev_name
);
920 static void pr_out_handle(struct nlattr
**tb
)
922 __pr_out_handle(mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]),
923 mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]));
926 static void __pr_out_port_handle(const char *bus_name
, const char *dev_name
,
929 __pr_out_handle(bus_name
, dev_name
);
930 pr_out("/%d", port_index
);
933 static void pr_out_port_handle(struct nlattr
**tb
)
935 __pr_out_port_handle(mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]),
936 mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]),
937 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]));
940 static void __pr_out_port_handle_nice(struct dl
*dl
, const char *bus_name
,
941 const char *dev_name
, uint32_t port_index
)
946 if (dl
->no_nice_names
)
949 err
= ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
950 port_index
, &ifname
);
953 pr_out("%s", ifname
);
957 __pr_out_port_handle(bus_name
, dev_name
, port_index
);
960 static void pr_out_port_handle_nice(struct dl
*dl
, struct nlattr
**tb
)
962 const char *bus_name
;
963 const char *dev_name
;
966 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
967 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
968 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
970 __pr_out_port_handle_nice(dl
, bus_name
, dev_name
, port_index
);
973 static void pr_out_dev(struct nlattr
**tb
)
979 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
981 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
982 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
984 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
985 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
991 static int cmd_dev_show(struct dl
*dl
)
993 struct nlmsghdr
*nlh
;
994 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
997 if (dl_argc(dl
) == 0)
1000 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
1002 if (dl_argc(dl
) > 0) {
1003 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
1008 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, NULL
);
1011 static int cmd_dev(struct dl
*dl
)
1013 if (dl_argv_match(dl
, "help")) {
1016 } else if (dl_argv_match(dl
, "show") ||
1017 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1019 return cmd_dev_show(dl
);
1021 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1025 static void cmd_port_help(void)
1027 pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
1028 pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
1029 pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n");
1030 pr_out(" devlink port unsplit DEV/PORT_INDEX\n");
1033 static const char *port_type_name(uint32_t type
)
1036 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
1037 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
1038 case DEVLINK_PORT_TYPE_ETH
: return "eth";
1039 case DEVLINK_PORT_TYPE_IB
: return "ib";
1040 default: return "<unknown type>";
1044 static void pr_out_port(struct nlattr
**tb
)
1046 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
1047 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
1049 pr_out_port_handle(tb
);
1052 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
1054 pr_out(" type %s", port_type_name(port_type
));
1056 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
1058 if (port_type
!= des_port_type
)
1059 pr_out("(%s)", port_type_name(des_port_type
));
1062 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
1063 pr_out(" netdev %s",
1064 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
1065 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
])
1067 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
1068 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
1069 pr_out(" split_group %u",
1070 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
1074 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1076 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1077 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1079 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1080 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1081 !tb
[DEVLINK_ATTR_PORT_INDEX
])
1082 return MNL_CB_ERROR
;
1087 static int cmd_port_show(struct dl
*dl
)
1089 struct nlmsghdr
*nlh
;
1090 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1093 if (dl_argc(dl
) == 0)
1094 flags
|= NLM_F_DUMP
;
1096 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
1098 if (dl_argc(dl
) > 0) {
1099 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
1104 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, NULL
);
1107 static int cmd_port_set(struct dl
*dl
)
1109 struct nlmsghdr
*nlh
;
1112 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
1113 NLM_F_REQUEST
| NLM_F_ACK
);
1115 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
1119 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1122 static int cmd_port_split(struct dl
*dl
)
1124 struct nlmsghdr
*nlh
;
1127 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
1128 NLM_F_REQUEST
| NLM_F_ACK
);
1130 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
1134 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1137 static int cmd_port_unsplit(struct dl
*dl
)
1139 struct nlmsghdr
*nlh
;
1142 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
1143 NLM_F_REQUEST
| NLM_F_ACK
);
1145 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
1149 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1152 static int cmd_port(struct dl
*dl
)
1154 if (dl_argv_match(dl
, "help")) {
1157 } else if (dl_argv_match(dl
, "show") ||
1158 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1160 return cmd_port_show(dl
);
1161 } else if (dl_argv_match(dl
, "set")) {
1163 return cmd_port_set(dl
);
1164 } else if (dl_argv_match(dl
, "split")) {
1166 return cmd_port_split(dl
);
1167 } else if (dl_argv_match(dl
, "unsplit")) {
1169 return cmd_port_unsplit(dl
);
1171 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1175 static void cmd_sb_help(void)
1177 pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
1178 pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
1179 pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
1180 pr_out(" size POOL_SIZE thtype { static | dynamic }\n");
1181 pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1182 pr_out(" pool POOL_INDEX ]\n");
1183 pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1184 pr_out(" pool POOL_INDEX th THRESHOLD\n");
1185 pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1186 pr_out(" type { ingress | egress } ]\n");
1187 pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1188 pr_out(" type { ingress | egress } pool POOL_INDEX\n");
1189 pr_out(" th THRESHOLD\n");
1190 pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
1191 pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
1192 pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
1195 static void pr_out_sb(struct nlattr
**tb
)
1198 pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n",
1199 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]),
1200 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]),
1201 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]),
1202 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]),
1203 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]),
1204 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
1207 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1209 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1210 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1212 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1213 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1214 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
1215 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
1216 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
1217 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
1218 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
1219 return MNL_CB_ERROR
;
1224 static int cmd_sb_show(struct dl
*dl
)
1226 struct nlmsghdr
*nlh
;
1227 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1230 if (dl_argc(dl
) == 0)
1231 flags
|= NLM_F_DUMP
;
1233 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
1235 if (dl_argc(dl
) > 0) {
1236 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
1241 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, NULL
);
1244 static const char *pool_type_name(uint8_t type
)
1247 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
1248 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
1249 default: return "<unknown type>";
1253 static const char *threshold_type_name(uint8_t type
)
1256 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
1257 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
1258 default: return "<unknown type>";
1262 static void pr_out_sb_pool(struct nlattr
**tb
)
1265 pr_out(": sb %u pool %u type %s size %u thtype %s\n",
1266 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]),
1267 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]),
1268 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])),
1269 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]),
1270 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
1273 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1275 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1276 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1278 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1279 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1280 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
1281 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
1282 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
1283 return MNL_CB_ERROR
;
1288 static int cmd_sb_pool_show(struct dl
*dl
)
1290 struct nlmsghdr
*nlh
;
1291 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1294 if (dl_argc(dl
) == 0)
1295 flags
|= NLM_F_DUMP
;
1297 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
1299 if (dl_argc(dl
) > 0) {
1300 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
1306 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, NULL
);
1309 static int cmd_sb_pool_set(struct dl
*dl
)
1311 struct nlmsghdr
*nlh
;
1314 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
1315 NLM_F_REQUEST
| NLM_F_ACK
);
1317 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
1318 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
1322 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1325 static int cmd_sb_pool(struct dl
*dl
)
1327 if (dl_argv_match(dl
, "help")) {
1330 } else if (dl_argv_match(dl
, "show") ||
1331 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1333 return cmd_sb_pool_show(dl
);
1334 } else if (dl_argv_match(dl
, "set")) {
1336 return cmd_sb_pool_set(dl
);
1338 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1342 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
1344 pr_out_port_handle_nice(dl
, tb
);
1345 pr_out(": sb %u pool %u threshold %u\n",
1346 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]),
1347 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]),
1348 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
1351 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1353 struct dl
*dl
= data
;
1354 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1355 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1357 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1358 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1359 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
1360 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
1361 return MNL_CB_ERROR
;
1362 pr_out_sb_port_pool(dl
, tb
);
1366 static int cmd_sb_port_pool_show(struct dl
*dl
)
1368 struct nlmsghdr
*nlh
;
1369 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1372 if (dl_argc(dl
) == 0)
1373 flags
|= NLM_F_DUMP
;
1375 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
1377 if (dl_argc(dl
) > 0) {
1378 err
= dl_argv_parse_put(nlh
, dl
,
1379 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
1385 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
1388 static int cmd_sb_port_pool_set(struct dl
*dl
)
1390 struct nlmsghdr
*nlh
;
1393 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
1394 NLM_F_REQUEST
| NLM_F_ACK
);
1396 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
1397 DL_OPT_SB_TH
, DL_OPT_SB
);
1401 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1404 static int cmd_sb_port_pool(struct dl
*dl
)
1406 if (dl_argv_match(dl
, "help")) {
1409 } else if (dl_argv_match(dl
, "show") ||
1410 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1412 return cmd_sb_port_pool_show(dl
);
1413 } else if (dl_argv_match(dl
, "set")) {
1415 return cmd_sb_port_pool_set(dl
);
1417 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1421 static int cmd_sb_port(struct dl
*dl
)
1423 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
1426 } else if (dl_argv_match(dl
, "pool")) {
1428 return cmd_sb_port_pool(dl
);
1430 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1434 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
1436 pr_out_port_handle_nice(dl
, tb
);
1437 pr_out(": sb %u tc %u type %s pool %u threshold %u\n",
1438 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]),
1439 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]),
1440 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])),
1441 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]),
1442 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
1445 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1447 struct dl
*dl
= data
;
1448 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1449 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1451 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1452 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1453 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
1454 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
1455 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
1456 return MNL_CB_ERROR
;
1457 pr_out_sb_tc_bind(dl
, tb
);
1461 static int cmd_sb_tc_bind_show(struct dl
*dl
)
1463 struct nlmsghdr
*nlh
;
1464 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1467 if (dl_argc(dl
) == 0)
1468 flags
|= NLM_F_DUMP
;
1470 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
1472 if (dl_argc(dl
) > 0) {
1473 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
1474 DL_OPT_SB_TYPE
, DL_OPT_SB
);
1479 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
1482 static int cmd_sb_tc_bind_set(struct dl
*dl
)
1484 struct nlmsghdr
*nlh
;
1487 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
1488 NLM_F_REQUEST
| NLM_F_ACK
);
1490 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
1491 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
1496 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1499 static int cmd_sb_tc_bind(struct dl
*dl
)
1501 if (dl_argv_match(dl
, "help")) {
1504 } else if (dl_argv_match(dl
, "show") ||
1505 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1507 return cmd_sb_tc_bind_show(dl
);
1508 } else if (dl_argv_match(dl
, "set")) {
1510 return cmd_sb_tc_bind_set(dl
);
1512 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1516 static int cmd_sb_tc(struct dl
*dl
)
1518 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
1521 } else if (dl_argv_match(dl
, "bind")) {
1523 return cmd_sb_tc_bind(dl
);
1525 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1530 struct list_head list
;
1534 uint32_t bound_pool_index
;
1538 struct list_head list
;
1541 uint32_t port_index
;
1543 struct list_head pool_list
;
1544 struct list_head ing_tc_list
;
1545 struct list_head eg_tc_list
;
1551 struct list_head port_list
;
1554 static struct occ_item
*occ_item_alloc(void)
1556 return calloc(1, sizeof(struct occ_item
));
1559 static void occ_item_free(struct occ_item
*occ_item
)
1564 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
1566 struct occ_port
*occ_port
;
1568 occ_port
= calloc(1, sizeof(*occ_port
));
1571 occ_port
->port_index
= port_index
;
1572 INIT_LIST_HEAD(&occ_port
->pool_list
);
1573 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
1574 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
1578 static void occ_port_free(struct occ_port
*occ_port
)
1580 struct occ_item
*occ_item
, *tmp
;
1582 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
1583 occ_item_free(occ_item
);
1584 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
1585 occ_item_free(occ_item
);
1586 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
1587 occ_item_free(occ_item
);
1590 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
1592 struct occ_show
*occ_show
;
1594 occ_show
= calloc(1, sizeof(*occ_show
));
1598 INIT_LIST_HEAD(&occ_show
->port_list
);
1602 static void occ_show_free(struct occ_show
*occ_show
)
1604 struct occ_port
*occ_port
, *tmp
;
1606 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
1607 occ_port_free(occ_port
);
1610 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
1613 struct occ_port
*occ_port
;
1614 uint32_t port_index
;
1616 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1618 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
1619 if (occ_port
->port_index
== port_index
)
1622 occ_port
= occ_port_alloc(port_index
);
1625 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
1629 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
1632 struct occ_item
*occ_item
;
1635 pr_out_sp(7, " %s:", label
);
1636 list_for_each_entry(occ_item
, list
, list
) {
1637 if ((i
- 1) % 4 == 0 && i
!= 1)
1640 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
1641 occ_item
->bound_pool_index
);
1643 pr_out_sp(7, "%2u:", occ_item
->index
);
1644 pr_out_sp(15, "%7u/%u", occ_item
->cur
, occ_item
->max
);
1648 if ((i
- 1) % 4 != 0)
1652 static void pr_out_occ_show_port(struct occ_port
*occ_port
)
1654 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
1655 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
1656 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
1659 static void pr_out_occ_show(struct occ_show
*occ_show
)
1661 struct dl
*dl
= occ_show
->dl
;
1662 struct dl_opts
*opts
= &dl
->opts
;
1663 struct occ_port
*occ_port
;
1665 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
1666 __pr_out_port_handle_nice(dl
, opts
->bus_name
, opts
->dev_name
,
1667 occ_port
->port_index
);
1669 pr_out_occ_show_port(occ_port
);
1673 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
1676 struct occ_port
*occ_port
;
1677 struct occ_item
*occ_item
;
1679 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
1682 occ_port
= occ_port_get(occ_show
, tb
);
1684 occ_show
->err
= -ENOMEM
;
1688 occ_item
= occ_item_alloc();
1690 occ_show
->err
= -ENOMEM
;
1693 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
1694 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
1695 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
1696 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
1699 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
1701 struct occ_show
*occ_show
= data
;
1702 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1703 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1705 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1706 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1707 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
1708 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
1709 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
1710 return MNL_CB_ERROR
;
1711 cmd_sb_occ_port_pool_process(occ_show
, tb
);
1715 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
1718 struct occ_port
*occ_port
;
1719 struct occ_item
*occ_item
;
1722 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
1725 occ_port
= occ_port_get(occ_show
, tb
);
1727 occ_show
->err
= -ENOMEM
;
1731 occ_item
= occ_item_alloc();
1733 occ_show
->err
= -ENOMEM
;
1736 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
1737 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
1738 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
1739 occ_item
->bound_pool_index
=
1740 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
1741 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
1742 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
1743 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
1744 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
1745 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
1747 occ_item_free(occ_item
);
1750 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
1752 struct occ_show
*occ_show
= data
;
1753 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1754 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1756 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1757 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1758 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
1759 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
1760 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
1761 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
1762 return MNL_CB_ERROR
;
1763 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
1767 static int cmd_sb_occ_show(struct dl
*dl
)
1769 struct nlmsghdr
*nlh
;
1770 struct occ_show
*occ_show
;
1771 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
1774 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
1778 occ_show
= occ_show_alloc(dl
);
1782 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
1784 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
1785 cmd_sb_occ_port_pool_process_cb
, occ_show
);
1789 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
1791 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
1792 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
1796 pr_out_occ_show(occ_show
);
1799 occ_show_free(occ_show
);
1803 static int cmd_sb_occ_snapshot(struct dl
*dl
)
1805 struct nlmsghdr
*nlh
;
1808 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
1809 NLM_F_REQUEST
| NLM_F_ACK
);
1811 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
1815 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1818 static int cmd_sb_occ_clearmax(struct dl
*dl
)
1820 struct nlmsghdr
*nlh
;
1823 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
1824 NLM_F_REQUEST
| NLM_F_ACK
);
1826 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
1830 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1833 static int cmd_sb_occ(struct dl
*dl
)
1835 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
1838 } else if (dl_argv_match(dl
, "show") ||
1839 dl_argv_match(dl
, "list")) {
1841 return cmd_sb_occ_show(dl
);
1842 } else if (dl_argv_match(dl
, "snapshot")) {
1844 return cmd_sb_occ_snapshot(dl
);
1845 } else if (dl_argv_match(dl
, "clearmax")) {
1847 return cmd_sb_occ_clearmax(dl
);
1849 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1853 static int cmd_sb(struct dl
*dl
)
1855 if (dl_argv_match(dl
, "help")) {
1858 } else if (dl_argv_match(dl
, "show") ||
1859 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1861 return cmd_sb_show(dl
);
1862 } else if (dl_argv_match(dl
, "pool")) {
1864 return cmd_sb_pool(dl
);
1865 } else if (dl_argv_match(dl
, "port")) {
1867 return cmd_sb_port(dl
);
1868 } else if (dl_argv_match(dl
, "tc")) {
1870 return cmd_sb_tc(dl
);
1871 } else if (dl_argv_match(dl
, "occupancy")) {
1873 return cmd_sb_occ(dl
);
1875 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1879 static const char *cmd_name(uint8_t cmd
)
1882 case DEVLINK_CMD_UNSPEC
: return "unspec";
1883 case DEVLINK_CMD_GET
: return "get";
1884 case DEVLINK_CMD_SET
: return "set";
1885 case DEVLINK_CMD_NEW
: return "new";
1886 case DEVLINK_CMD_DEL
: return "del";
1887 case DEVLINK_CMD_PORT_GET
: return "get";
1888 case DEVLINK_CMD_PORT_SET
: return "set";
1889 case DEVLINK_CMD_PORT_NEW
: return "net";
1890 case DEVLINK_CMD_PORT_DEL
: return "del";
1891 default: return "<unknown cmd>";
1895 static const char *cmd_obj(uint8_t cmd
)
1898 case DEVLINK_CMD_UNSPEC
: return "unspec";
1899 case DEVLINK_CMD_GET
:
1900 case DEVLINK_CMD_SET
:
1901 case DEVLINK_CMD_NEW
:
1902 case DEVLINK_CMD_DEL
:
1904 case DEVLINK_CMD_PORT_GET
:
1905 case DEVLINK_CMD_PORT_SET
:
1906 case DEVLINK_CMD_PORT_NEW
:
1907 case DEVLINK_CMD_PORT_DEL
:
1909 default: return "<unknown obj>";
1913 static void pr_out_mon_header(uint8_t cmd
)
1915 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
1918 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
1920 const char *obj
= cmd_obj(cmd
);
1921 unsigned int index
= 0;
1922 const char *cur_obj
;
1926 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
1927 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
1933 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1935 struct dl
*dl
= data
;
1936 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1937 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1938 uint8_t cmd
= genl
->cmd
;
1940 if (!cmd_filter_check(dl
, cmd
))
1944 case DEVLINK_CMD_GET
: /* fall through */
1945 case DEVLINK_CMD_SET
: /* fall through */
1946 case DEVLINK_CMD_NEW
: /* fall through */
1947 case DEVLINK_CMD_DEL
:
1948 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1949 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
1950 return MNL_CB_ERROR
;
1951 pr_out_mon_header(genl
->cmd
);
1954 case DEVLINK_CMD_PORT_GET
: /* fall through */
1955 case DEVLINK_CMD_PORT_SET
: /* fall through */
1956 case DEVLINK_CMD_PORT_NEW
: /* fall through */
1957 case DEVLINK_CMD_PORT_DEL
:
1958 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1959 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1960 !tb
[DEVLINK_ATTR_PORT_INDEX
])
1961 return MNL_CB_ERROR
;
1962 pr_out_mon_header(genl
->cmd
);
1969 static int cmd_mon_show(struct dl
*dl
)
1972 unsigned int index
= 0;
1973 const char *cur_obj
;
1975 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
1976 if (strcmp(cur_obj
, "all") != 0 &&
1977 strcmp(cur_obj
, "dev") != 0 &&
1978 strcmp(cur_obj
, "port") != 0) {
1979 pr_err("Unknown object \"%s\"\n", cur_obj
);
1983 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
1986 err
= _mnlg_socket_recv_run(dl
->nlg
, cmd_mon_show_cb
, dl
);
1992 static void cmd_mon_help(void)
1994 pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
1995 "where OBJECT-LIST := { dev | port }\n");
1998 static int cmd_mon(struct dl
*dl
)
2000 if (dl_argv_match(dl
, "help")) {
2003 } else if (dl_no_arg(dl
)) {
2005 return cmd_mon_show(dl
);
2007 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2011 static void help(void)
2013 pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
2014 "where OBJECT := { dev | port | sb | monitor }\n"
2015 " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n");
2018 static int dl_cmd(struct dl
*dl
)
2020 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2023 } else if (dl_argv_match(dl
, "dev")) {
2026 } else if (dl_argv_match(dl
, "port")) {
2028 return cmd_port(dl
);
2029 } else if (dl_argv_match(dl
, "sb")) {
2032 } else if (dl_argv_match(dl
, "monitor")) {
2036 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
2040 static int dl_init(struct dl
*dl
, int argc
, char **argv
)
2047 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
2049 pr_err("Failed to connect to devlink Netlink\n");
2053 err
= ifname_map_init(dl
);
2055 pr_err("Failed to create index map\n");
2056 goto err_ifname_map_create
;
2060 err_ifname_map_create
:
2061 mnlg_socket_close(dl
->nlg
);
2065 static void dl_fini(struct dl
*dl
)
2067 ifname_map_fini(dl
);
2068 mnlg_socket_close(dl
->nlg
);
2071 static struct dl
*dl_alloc(void)
2075 dl
= calloc(1, sizeof(*dl
));
2081 static void dl_free(struct dl
*dl
)
2086 int main(int argc
, char **argv
)
2088 static const struct option long_options
[] = {
2089 { "Version", no_argument
, NULL
, 'V' },
2090 { "no-nice-names", no_argument
, NULL
, 'n' },
2091 { NULL
, 0, NULL
, 0 }
2100 pr_err("Failed to allocate memory for devlink\n");
2101 return EXIT_FAILURE
;
2104 while ((opt
= getopt_long(argc
, argv
, "Vn",
2105 long_options
, NULL
)) >= 0) {
2109 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
2110 return EXIT_SUCCESS
;
2112 dl
->no_nice_names
= true;
2115 pr_err("Unknown option.\n");
2117 return EXIT_FAILURE
;
2124 err
= dl_init(dl
, argc
, argv
);