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>
27 #include "json_writer.h"
29 #define ESWITCH_MODE_LEGACY "legacy"
30 #define ESWITCH_MODE_SWITCHDEV "switchdev"
31 #define ESWITCH_INLINE_MODE_NONE "none"
32 #define ESWITCH_INLINE_MODE_LINK "link"
33 #define ESWITCH_INLINE_MODE_NETWORK "network"
34 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
36 #define pr_err(args...) fprintf(stderr, ##args)
37 #define pr_out(args...) \
39 if (g_indent_newline) { \
40 fprintf(stdout, "%s", g_indent_str); \
41 g_indent_newline = false; \
43 fprintf(stdout, ##args); \
46 #define pr_out_sp(num, args...) \
48 int ret = fprintf(stdout, ##args); \
50 fprintf(stdout, "%*s", num - ret, ""); \
53 static int g_indent_level
;
54 static bool g_indent_newline
;
55 #define INDENT_STR_STEP 2
56 #define INDENT_STR_MAXLEN 32
57 static char g_indent_str
[INDENT_STR_MAXLEN
+ 1] = "";
59 static void __pr_out_indent_inc(void)
61 if (g_indent_level
+ INDENT_STR_STEP
> INDENT_STR_MAXLEN
)
63 g_indent_level
+= INDENT_STR_STEP
;
64 memset(g_indent_str
, ' ', sizeof(g_indent_str
));
65 g_indent_str
[g_indent_level
] = '\0';
68 static void __pr_out_indent_dec(void)
70 if (g_indent_level
- INDENT_STR_STEP
< 0)
72 g_indent_level
-= INDENT_STR_STEP
;
73 g_indent_str
[g_indent_level
] = '\0';
76 static void __pr_out_newline(void)
79 g_indent_newline
= true;
82 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
83 mnl_cb_t data_cb
, void *data
)
87 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
89 pr_err("devlink answers: %s\n", strerror(errno
));
95 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
96 const struct nlmsghdr
*nlh
,
97 mnl_cb_t data_cb
, void *data
)
101 err
= mnlg_socket_send(nlg
, nlh
);
103 pr_err("Failed to call mnlg_socket_send\n");
106 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
109 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
110 const char *group_name
)
114 err
= mnlg_socket_group_add(nlg
, group_name
);
116 pr_err("Failed to call mnlg_socket_group_add\n");
123 struct list_head list
;
130 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
131 const char *dev_name
,
135 struct ifname_map
*ifname_map
;
137 ifname_map
= calloc(1, sizeof(*ifname_map
));
140 ifname_map
->bus_name
= strdup(bus_name
);
141 ifname_map
->dev_name
= strdup(dev_name
);
142 ifname_map
->port_index
= port_index
;
143 ifname_map
->ifname
= strdup(ifname
);
144 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
145 !ifname_map
->ifname
) {
146 free(ifname_map
->ifname
);
147 free(ifname_map
->dev_name
);
148 free(ifname_map
->bus_name
);
155 static void ifname_map_free(struct ifname_map
*ifname_map
)
157 free(ifname_map
->ifname
);
158 free(ifname_map
->dev_name
);
159 free(ifname_map
->bus_name
);
163 #define BIT(nr) (1UL << (nr))
164 #define DL_OPT_HANDLE BIT(0)
165 #define DL_OPT_HANDLEP BIT(1)
166 #define DL_OPT_PORT_TYPE BIT(2)
167 #define DL_OPT_PORT_COUNT BIT(3)
168 #define DL_OPT_SB BIT(4)
169 #define DL_OPT_SB_POOL BIT(5)
170 #define DL_OPT_SB_SIZE BIT(6)
171 #define DL_OPT_SB_TYPE BIT(7)
172 #define DL_OPT_SB_THTYPE BIT(8)
173 #define DL_OPT_SB_TH BIT(9)
174 #define DL_OPT_SB_TC BIT(10)
175 #define DL_OPT_ESWITCH_MODE BIT(11)
176 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
177 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
178 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
179 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
182 uint32_t present
; /* flags of present items */
186 enum devlink_port_type port_type
;
189 uint16_t sb_pool_index
;
190 uint32_t sb_pool_size
;
191 enum devlink_sb_pool_type sb_pool_type
;
192 enum devlink_sb_threshold_type sb_pool_thtype
;
193 uint32_t sb_threshold
;
194 uint16_t sb_tc_index
;
195 enum devlink_eswitch_mode eswitch_mode
;
196 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
197 const char *dpipe_table_name
;
198 bool dpipe_counters_enable
;
199 bool eswitch_encap_mode
;
203 struct mnlg_socket
*nlg
;
204 struct list_head ifname_map_list
;
221 static int dl_argc(struct dl
*dl
)
226 static char *dl_argv(struct dl
*dl
)
228 if (dl_argc(dl
) == 0)
233 static void dl_arg_inc(struct dl
*dl
)
235 if (dl_argc(dl
) == 0)
241 static char *dl_argv_next(struct dl
*dl
)
245 if (dl_argc(dl
) == 0)
253 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
255 if (index
>= dl_argc(dl
))
257 return dl
->argv
[index
];
260 static int strcmpx(const char *str1
, const char *str2
)
262 if (strlen(str1
) > strlen(str2
))
264 return strncmp(str1
, str2
, strlen(str1
));
267 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
269 if (dl_argc(dl
) == 0)
271 return strcmpx(dl_argv(dl
), pattern
) == 0;
274 static bool dl_no_arg(struct dl
*dl
)
276 return dl_argc(dl
) == 0;
279 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
280 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
281 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
282 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
283 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
284 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
285 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
286 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
287 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
288 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
289 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
290 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
291 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
292 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
293 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
294 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
295 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
296 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
297 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
298 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
299 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
300 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
301 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
302 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
303 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
304 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
305 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
306 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
307 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
308 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
309 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
310 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
311 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
312 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
313 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
314 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
315 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
316 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
317 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
318 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
319 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
320 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
321 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
322 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
323 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
324 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
325 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
326 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
327 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
328 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
329 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
330 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
331 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
332 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
333 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
334 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
335 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
336 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
339 static int attr_cb(const struct nlattr
*attr
, void *data
)
341 const struct nlattr
**tb
= data
;
344 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
347 type
= mnl_attr_get_type(attr
);
348 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
355 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
357 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
358 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
359 struct dl
*dl
= data
;
360 struct ifname_map
*ifname_map
;
361 const char *bus_name
;
362 const char *dev_name
;
363 uint32_t port_ifindex
;
364 const char *port_ifname
;
366 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
367 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
368 !tb
[DEVLINK_ATTR_PORT_INDEX
])
371 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
374 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
375 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
376 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
377 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
378 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
379 port_ifindex
, port_ifname
);
382 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
387 static void ifname_map_fini(struct dl
*dl
)
389 struct ifname_map
*ifname_map
, *tmp
;
391 list_for_each_entry_safe(ifname_map
, tmp
,
392 &dl
->ifname_map_list
, list
) {
393 list_del(&ifname_map
->list
);
394 ifname_map_free(ifname_map
);
398 static int ifname_map_init(struct dl
*dl
)
400 struct nlmsghdr
*nlh
;
403 INIT_LIST_HEAD(&dl
->ifname_map_list
);
405 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
406 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
408 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
416 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
417 char **p_bus_name
, char **p_dev_name
,
418 uint32_t *p_port_index
)
420 struct ifname_map
*ifname_map
;
422 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
423 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
424 *p_bus_name
= ifname_map
->bus_name
;
425 *p_dev_name
= ifname_map
->dev_name
;
426 *p_port_index
= ifname_map
->port_index
;
433 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
434 const char *dev_name
, uint32_t port_index
,
437 struct ifname_map
*ifname_map
;
439 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
440 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
441 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
442 port_index
== ifname_map
->port_index
) {
443 *p_ifname
= ifname_map
->ifname
;
450 static unsigned int strslashcount(char *str
)
452 unsigned int count
= 0;
455 while ((pos
= strchr(pos
, '/'))) {
462 static int strslashrsplit(char *str
, char **before
, char **after
)
466 slash
= strrchr(str
, '/');
475 static int strtouint32_t(const char *str
, uint32_t *p_val
)
478 unsigned long int val
;
480 val
= strtoul(str
, &endptr
, 10);
481 if (endptr
== str
|| *endptr
!= '\0')
489 static int strtouint16_t(const char *str
, uint16_t *p_val
)
492 unsigned long int val
;
494 val
= strtoul(str
, &endptr
, 10);
495 if (endptr
== str
|| *endptr
!= '\0')
503 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
505 strslashrsplit(str
, p_bus_name
, p_dev_name
);
509 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
511 char *str
= dl_argv_next(dl
);
514 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
517 if (strslashcount(str
) != 1) {
518 pr_err("Wrong devlink identification string format.\n");
519 pr_err("Expected \"bus_name/dev_name\".\n");
522 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
525 static int __dl_argv_handle_port(char *str
,
526 char **p_bus_name
, char **p_dev_name
,
527 uint32_t *p_port_index
)
529 char *handlestr
= handlestr
;
530 char *portstr
= portstr
;
533 strslashrsplit(str
, &handlestr
, &portstr
);
534 err
= strtouint32_t(portstr
, p_port_index
);
536 pr_err("Port index \"%s\" is not a number or not within range\n",
540 strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
544 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
545 char **p_bus_name
, char **p_dev_name
,
546 uint32_t *p_port_index
)
550 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
553 pr_err("Netdevice \"%s\" not found\n", str
);
559 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
560 char **p_dev_name
, uint32_t *p_port_index
)
562 char *str
= dl_argv_next(dl
);
563 unsigned int slash_count
;
566 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
569 slash_count
= strslashcount(str
);
570 switch (slash_count
) {
572 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
573 p_dev_name
, p_port_index
);
575 return __dl_argv_handle_port(str
, p_bus_name
,
576 p_dev_name
, p_port_index
);
578 pr_err("Wrong port identification string format.\n");
579 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
584 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
585 char **p_dev_name
, uint32_t *p_port_index
,
586 uint32_t *p_handle_bit
)
588 char *str
= dl_argv_next(dl
);
589 unsigned int slash_count
;
593 pr_err("One of following identifications expected:\n"
594 "Devlink identification (\"bus_name/dev_name\")\n"
595 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
598 slash_count
= strslashcount(str
);
599 if (slash_count
== 1) {
600 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
603 *p_handle_bit
= DL_OPT_HANDLE
;
604 } else if (slash_count
== 2) {
605 err
= __dl_argv_handle_port(str
, p_bus_name
,
606 p_dev_name
, p_port_index
);
609 *p_handle_bit
= DL_OPT_HANDLEP
;
610 } else if (slash_count
== 0) {
611 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
612 p_dev_name
, p_port_index
);
615 *p_handle_bit
= DL_OPT_HANDLEP
;
617 pr_err("Wrong port identification string format.\n");
618 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
624 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
626 char *str
= dl_argv_next(dl
);
630 pr_err("Unsigned number argument expected\n");
634 err
= strtouint32_t(str
, p_val
);
636 pr_err("\"%s\" is not a number or not within range\n", str
);
642 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
644 char *str
= dl_argv_next(dl
);
648 pr_err("Unsigned number argument expected\n");
652 err
= strtouint16_t(str
, p_val
);
654 pr_err("\"%s\" is not a number or not within range\n", str
);
660 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
662 const char *str
= dl_argv_next(dl
);
665 pr_err("String parameter expected\n");
672 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
674 if (strcmp(typestr
, "auto") == 0) {
675 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
676 } else if (strcmp(typestr
, "eth") == 0) {
677 *p_type
= DEVLINK_PORT_TYPE_ETH
;
678 } else if (strcmp(typestr
, "ib") == 0) {
679 *p_type
= DEVLINK_PORT_TYPE_IB
;
681 pr_err("Unknown port type \"%s\"\n", typestr
);
687 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
689 if (strcmp(typestr
, "ingress") == 0) {
690 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
691 } else if (strcmp(typestr
, "egress") == 0) {
692 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
694 pr_err("Unknown pool type \"%s\"\n", typestr
);
700 static int threshold_type_get(const char *typestr
,
701 enum devlink_sb_threshold_type
*p_type
)
703 if (strcmp(typestr
, "static") == 0) {
704 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
705 } else if (strcmp(typestr
, "dynamic") == 0) {
706 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
708 pr_err("Unknown threshold type \"%s\"\n", typestr
);
714 static int eswitch_mode_get(const char *typestr
,
715 enum devlink_eswitch_mode
*p_mode
)
717 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
718 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
719 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
720 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
722 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
728 static int eswitch_inline_mode_get(const char *typestr
,
729 enum devlink_eswitch_inline_mode
*p_mode
)
731 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
732 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
733 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
734 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
735 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
736 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
737 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
738 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
740 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
746 static int dpipe_counters_enable_get(const char *typestr
,
747 bool *counters_enable
)
749 if (strcmp(typestr
, "enable") == 0) {
750 *counters_enable
= 1;
751 } else if (strcmp(typestr
, "disable") == 0) {
752 *counters_enable
= 0;
754 pr_err("Unknown counter_state \"%s\"\n", typestr
);
760 static int eswitch_encap_mode_get(const char *typestr
, bool *p_mode
)
762 if (strcmp(typestr
, "enable") == 0) {
764 } else if (strcmp(typestr
, "disable") == 0) {
767 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
773 static int dl_argv_parse(struct dl
*dl
, uint32_t o_required
,
776 struct dl_opts
*opts
= &dl
->opts
;
777 uint32_t o_all
= o_required
| o_optional
;
778 uint32_t o_found
= 0;
781 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
782 uint32_t handle_bit
= handle_bit
;
784 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
785 &opts
->port_index
, &handle_bit
);
788 o_found
|= handle_bit
;
789 } else if (o_required
& DL_OPT_HANDLE
) {
790 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
793 o_found
|= DL_OPT_HANDLE
;
794 } else if (o_required
& DL_OPT_HANDLEP
) {
795 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
799 o_found
|= DL_OPT_HANDLEP
;
802 while (dl_argc(dl
)) {
803 if (dl_argv_match(dl
, "type") &&
804 (o_all
& DL_OPT_PORT_TYPE
)) {
808 err
= dl_argv_str(dl
, &typestr
);
811 err
= port_type_get(typestr
, &opts
->port_type
);
814 o_found
|= DL_OPT_PORT_TYPE
;
815 } else if (dl_argv_match(dl
, "count") &&
816 (o_all
& DL_OPT_PORT_COUNT
)) {
818 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
821 o_found
|= DL_OPT_PORT_COUNT
;
822 } else if (dl_argv_match(dl
, "sb") &&
823 (o_all
& DL_OPT_SB
)) {
825 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
828 o_found
|= DL_OPT_SB
;
829 } else if (dl_argv_match(dl
, "pool") &&
830 (o_all
& DL_OPT_SB_POOL
)) {
832 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
835 o_found
|= DL_OPT_SB_POOL
;
836 } else if (dl_argv_match(dl
, "size") &&
837 (o_all
& DL_OPT_SB_SIZE
)) {
839 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
842 o_found
|= DL_OPT_SB_SIZE
;
843 } else if (dl_argv_match(dl
, "type") &&
844 (o_all
& DL_OPT_SB_TYPE
)) {
848 err
= dl_argv_str(dl
, &typestr
);
851 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
854 o_found
|= DL_OPT_SB_TYPE
;
855 } else if (dl_argv_match(dl
, "thtype") &&
856 (o_all
& DL_OPT_SB_THTYPE
)) {
860 err
= dl_argv_str(dl
, &typestr
);
863 err
= threshold_type_get(typestr
,
864 &opts
->sb_pool_thtype
);
867 o_found
|= DL_OPT_SB_THTYPE
;
868 } else if (dl_argv_match(dl
, "th") &&
869 (o_all
& DL_OPT_SB_TH
)) {
871 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
874 o_found
|= DL_OPT_SB_TH
;
875 } else if (dl_argv_match(dl
, "tc") &&
876 (o_all
& DL_OPT_SB_TC
)) {
878 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
881 o_found
|= DL_OPT_SB_TC
;
882 } else if (dl_argv_match(dl
, "mode") &&
883 (o_all
& DL_OPT_ESWITCH_MODE
)) {
887 err
= dl_argv_str(dl
, &typestr
);
890 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
893 o_found
|= DL_OPT_ESWITCH_MODE
;
894 } else if (dl_argv_match(dl
, "inline-mode") &&
895 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
899 err
= dl_argv_str(dl
, &typestr
);
902 err
= eswitch_inline_mode_get(
903 typestr
, &opts
->eswitch_inline_mode
);
906 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
907 } else if (dl_argv_match(dl
, "name") &&
908 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
910 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
913 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
914 } else if (dl_argv_match(dl
, "counters") &&
915 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
919 err
= dl_argv_str(dl
, &typestr
);
922 err
= dpipe_counters_enable_get(typestr
,
923 &opts
->dpipe_counters_enable
);
926 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
927 } else if (dl_argv_match(dl
, "encap") &&
928 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
932 err
= dl_argv_str(dl
, &typestr
);
935 err
= eswitch_encap_mode_get(typestr
,
936 &opts
->eswitch_encap_mode
);
939 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
941 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
946 opts
->present
= o_found
;
948 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
950 opts
->present
|= DL_OPT_SB
;
953 if ((o_required
& DL_OPT_PORT_TYPE
) && !(o_found
& DL_OPT_PORT_TYPE
)) {
954 pr_err("Port type option expected.\n");
958 if ((o_required
& DL_OPT_PORT_COUNT
) &&
959 !(o_found
& DL_OPT_PORT_COUNT
)) {
960 pr_err("Port split count option expected.\n");
964 if ((o_required
& DL_OPT_SB_POOL
) && !(o_found
& DL_OPT_SB_POOL
)) {
965 pr_err("Pool index option expected.\n");
969 if ((o_required
& DL_OPT_SB_SIZE
) && !(o_found
& DL_OPT_SB_SIZE
)) {
970 pr_err("Pool size option expected.\n");
974 if ((o_required
& DL_OPT_SB_TYPE
) && !(o_found
& DL_OPT_SB_TYPE
)) {
975 pr_err("Pool type option expected.\n");
979 if ((o_required
& DL_OPT_SB_THTYPE
) && !(o_found
& DL_OPT_SB_THTYPE
)) {
980 pr_err("Pool threshold type option expected.\n");
984 if ((o_required
& DL_OPT_SB_TH
) && !(o_found
& DL_OPT_SB_TH
)) {
985 pr_err("Threshold option expected.\n");
989 if ((o_required
& DL_OPT_SB_TC
) && !(o_found
& DL_OPT_SB_TC
)) {
990 pr_err("TC index option expected.\n");
994 if ((o_required
& DL_OPT_ESWITCH_MODE
) &&
995 !(o_found
& DL_OPT_ESWITCH_MODE
)) {
996 pr_err("E-Switch mode option expected.\n");
1000 if ((o_required
& DL_OPT_ESWITCH_INLINE_MODE
) &&
1001 !(o_found
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1002 pr_err("E-Switch inline-mode option expected.\n");
1006 if ((o_required
& DL_OPT_DPIPE_TABLE_NAME
) &&
1007 !(o_found
& DL_OPT_DPIPE_TABLE_NAME
)) {
1008 pr_err("Dpipe table name expected\n");
1012 if ((o_required
& DL_OPT_DPIPE_TABLE_COUNTERS
) &&
1013 !(o_found
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1014 pr_err("Dpipe table counter state expected\n");
1018 if ((o_required
& DL_OPT_ESWITCH_ENCAP_MODE
) &&
1019 !(o_found
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1020 pr_err("E-Switch encapsulation option expected.\n");
1027 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1029 struct dl_opts
*opts
= &dl
->opts
;
1031 if (opts
->present
& DL_OPT_HANDLE
) {
1032 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1033 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1034 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1035 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1036 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1037 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1040 if (opts
->present
& DL_OPT_PORT_TYPE
)
1041 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1043 if (opts
->present
& DL_OPT_PORT_COUNT
)
1044 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1046 if (opts
->present
& DL_OPT_SB
)
1047 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1049 if (opts
->present
& DL_OPT_SB_POOL
)
1050 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1051 opts
->sb_pool_index
);
1052 if (opts
->present
& DL_OPT_SB_SIZE
)
1053 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1054 opts
->sb_pool_size
);
1055 if (opts
->present
& DL_OPT_SB_TYPE
)
1056 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1057 opts
->sb_pool_type
);
1058 if (opts
->present
& DL_OPT_SB_THTYPE
)
1059 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1060 opts
->sb_pool_thtype
);
1061 if (opts
->present
& DL_OPT_SB_TH
)
1062 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1063 opts
->sb_threshold
);
1064 if (opts
->present
& DL_OPT_SB_TC
)
1065 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1067 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1068 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1069 opts
->eswitch_mode
);
1070 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1071 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1072 opts
->eswitch_inline_mode
);
1073 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1074 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1075 opts
->dpipe_table_name
);
1076 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1077 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1078 opts
->dpipe_counters_enable
);
1079 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1080 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1081 opts
->eswitch_encap_mode
);
1084 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1085 uint32_t o_required
, uint32_t o_optional
)
1089 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1092 dl_opts_put(nlh
, dl
);
1096 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1098 struct dl_opts
*opts
= &dl
->opts
;
1099 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1100 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1101 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1102 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1104 if (opts
->present
& DL_OPT_HANDLE
&&
1105 attr_bus_name
&& attr_dev_name
) {
1106 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1107 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1109 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1110 strcmp(dev_name
, opts
->dev_name
) != 0)
1113 if (opts
->present
& DL_OPT_HANDLEP
&&
1114 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1115 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1116 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1117 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1119 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1120 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1121 port_index
!= opts
->port_index
)
1124 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1125 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1127 if (sb_index
!= opts
->sb_index
)
1133 static void cmd_dev_help(void)
1135 pr_err("Usage: devlink dev show [ DEV ]\n");
1136 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1137 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1138 pr_err(" [ encap { disable | enable } ]\n");
1139 pr_err(" devlink dev eswitch show DEV\n");
1142 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1143 const char *dev_name
)
1145 if (!dl
->arr_last
.present
)
1147 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1148 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1151 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1152 const char *dev_name
)
1154 dl
->arr_last
.present
= true;
1155 free(dl
->arr_last
.dev_name
);
1156 free(dl
->arr_last
.bus_name
);
1157 dl
->arr_last
.bus_name
= strdup(bus_name
);
1158 dl
->arr_last
.dev_name
= strdup(dev_name
);
1161 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1162 const char *dev_name
)
1164 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1167 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1168 const char *dev_name
)
1170 return dl
->arr_last
.present
&&
1171 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1174 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1175 bool content
, bool array
)
1177 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1178 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1181 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
1183 if (dl
->json_output
) {
1185 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1186 jsonw_end_array(dl
->jw
);
1187 if (should_arr_last_handle_start(dl
, bus_name
,
1189 jsonw_name(dl
->jw
, buf
);
1190 jsonw_start_array(dl
->jw
);
1191 jsonw_start_object(dl
->jw
);
1192 arr_last_handle_set(dl
, bus_name
, dev_name
);
1194 jsonw_start_object(dl
->jw
);
1197 jsonw_name(dl
->jw
, buf
);
1198 jsonw_start_object(dl
->jw
);
1202 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1203 __pr_out_indent_dec();
1204 if (should_arr_last_handle_start(dl
, bus_name
,
1206 pr_out("%s%s", buf
, content
? ":" : "");
1208 __pr_out_indent_inc();
1209 arr_last_handle_set(dl
, bus_name
, dev_name
);
1212 pr_out("%s%s", buf
, content
? ":" : "");
1217 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
1219 __pr_out_handle_start(dl
, tb
, true, true);
1222 static void pr_out_handle_end(struct dl
*dl
)
1224 if (dl
->json_output
)
1225 jsonw_end_object(dl
->jw
);
1230 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
1232 __pr_out_handle_start(dl
, tb
, false, false);
1233 pr_out_handle_end(dl
);
1236 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
1237 const char *dev_name
, uint32_t port_index
)
1239 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
1240 dl
->arr_last
.port_index
== port_index
;
1243 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
1244 const char *dev_name
, uint32_t port_index
)
1246 arr_last_handle_set(dl
, bus_name
, dev_name
);
1247 dl
->arr_last
.port_index
= port_index
;
1250 static bool should_arr_last_port_handle_start(struct dl
*dl
,
1251 const char *bus_name
,
1252 const char *dev_name
,
1253 uint32_t port_index
)
1255 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1258 static bool should_arr_last_port_handle_end(struct dl
*dl
,
1259 const char *bus_name
,
1260 const char *dev_name
,
1261 uint32_t port_index
)
1263 return dl
->arr_last
.present
&&
1264 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1267 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
1268 const char *dev_name
,
1269 uint32_t port_index
, bool try_nice
,
1272 static char buf
[32];
1273 char *ifname
= NULL
;
1275 if (dl
->no_nice_names
|| !try_nice
||
1276 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
1277 port_index
, &ifname
) != 0)
1278 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
1280 sprintf(buf
, "%s", ifname
);
1282 if (dl
->json_output
) {
1284 if (should_arr_last_port_handle_end(dl
, bus_name
,
1287 jsonw_end_array(dl
->jw
);
1288 if (should_arr_last_port_handle_start(dl
, bus_name
,
1291 jsonw_name(dl
->jw
, buf
);
1292 jsonw_start_array(dl
->jw
);
1293 jsonw_start_object(dl
->jw
);
1294 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
1297 jsonw_start_object(dl
->jw
);
1300 jsonw_name(dl
->jw
, buf
);
1301 jsonw_start_object(dl
->jw
);
1308 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1310 const char *bus_name
;
1311 const char *dev_name
;
1312 uint32_t port_index
;
1314 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1315 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1316 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1317 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
1320 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1322 const char *bus_name
;
1323 const char *dev_name
;
1324 uint32_t port_index
;
1326 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1327 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1328 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1329 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
1332 static void pr_out_port_handle_end(struct dl
*dl
)
1334 if (dl
->json_output
)
1335 jsonw_end_object(dl
->jw
);
1341 static void pr_out_str(struct dl
*dl
, const char *name
, const char *val
)
1343 if (dl
->json_output
) {
1344 jsonw_string_field(dl
->jw
, name
, val
);
1346 if (g_indent_newline
)
1347 pr_out("%s %s", name
, val
);
1349 pr_out(" %s %s", name
, val
);
1353 static void pr_out_uint(struct dl
*dl
, const char *name
, unsigned int val
)
1355 if (dl
->json_output
) {
1356 jsonw_uint_field(dl
->jw
, name
, val
);
1358 if (g_indent_newline
)
1359 pr_out("%s %u", name
, val
);
1361 pr_out(" %s %u", name
, val
);
1365 static void pr_out_dev(struct dl
*dl
, struct nlattr
**tb
)
1367 pr_out_handle(dl
, tb
);
1370 static void pr_out_section_start(struct dl
*dl
, const char *name
)
1372 if (dl
->json_output
) {
1373 jsonw_start_object(dl
->jw
);
1374 jsonw_name(dl
->jw
, name
);
1375 jsonw_start_object(dl
->jw
);
1379 static void pr_out_section_end(struct dl
*dl
)
1381 if (dl
->json_output
) {
1382 if (dl
->arr_last
.present
)
1383 jsonw_end_array(dl
->jw
);
1384 jsonw_end_object(dl
->jw
);
1385 jsonw_end_object(dl
->jw
);
1389 static void pr_out_array_start(struct dl
*dl
, const char *name
)
1391 if (dl
->json_output
) {
1392 jsonw_name(dl
->jw
, name
);
1393 jsonw_start_array(dl
->jw
);
1395 if (!g_indent_newline
)
1397 pr_out("%s:", name
);
1399 __pr_out_indent_inc();
1403 static void pr_out_array_end(struct dl
*dl
)
1405 if (dl
->json_output
)
1406 jsonw_end_array(dl
->jw
);
1408 __pr_out_indent_dec();
1411 static void pr_out_entry_start(struct dl
*dl
)
1413 if (dl
->json_output
)
1414 jsonw_start_object(dl
->jw
);
1417 static void pr_out_entry_end(struct dl
*dl
)
1419 if (dl
->json_output
)
1420 jsonw_end_object(dl
->jw
);
1425 static const char *eswitch_mode_name(uint32_t mode
)
1428 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
1429 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
1430 default: return "<unknown mode>";
1434 static const char *eswitch_inline_mode_name(uint32_t mode
)
1437 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
1438 return ESWITCH_INLINE_MODE_NONE
;
1439 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
1440 return ESWITCH_INLINE_MODE_LINK
;
1441 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
1442 return ESWITCH_INLINE_MODE_NETWORK
;
1443 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
1444 return ESWITCH_INLINE_MODE_TRANSPORT
;
1446 return "<unknown mode>";
1450 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
1452 __pr_out_handle_start(dl
, tb
, true, false);
1454 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
])
1455 pr_out_str(dl
, "mode",
1456 eswitch_mode_name(mnl_attr_get_u16(tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
1458 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])
1459 pr_out_str(dl
, "inline-mode",
1460 eswitch_inline_mode_name(mnl_attr_get_u8(
1461 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
1463 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
1464 bool encap_mode
= !!mnl_attr_get_u8(tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]);
1466 pr_out_str(dl
, "encap", encap_mode
? "enable" : "disable");
1469 pr_out_handle_end(dl
);
1472 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1474 struct dl
*dl
= data
;
1475 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1476 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1478 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1479 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
1480 return MNL_CB_ERROR
;
1481 pr_out_eswitch(dl
, tb
);
1485 static int cmd_dev_eswitch_show(struct dl
*dl
)
1487 struct nlmsghdr
*nlh
;
1490 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
1491 NLM_F_REQUEST
| NLM_F_ACK
);
1493 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
1497 pr_out_section_start(dl
, "dev");
1498 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
1499 pr_out_section_end(dl
);
1503 static int cmd_dev_eswitch_set(struct dl
*dl
)
1505 struct nlmsghdr
*nlh
;
1508 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
1509 NLM_F_REQUEST
| NLM_F_ACK
);
1511 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
1512 DL_OPT_ESWITCH_MODE
|
1513 DL_OPT_ESWITCH_INLINE_MODE
|
1514 DL_OPT_ESWITCH_ENCAP_MODE
);
1519 if (dl
->opts
.present
== 1) {
1520 pr_err("Need to set at least one option\n");
1524 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1527 static int cmd_dev_eswitch(struct dl
*dl
)
1529 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
1532 } else if (dl_argv_match(dl
, "set")) {
1534 return cmd_dev_eswitch_set(dl
);
1535 } else if (dl_argv_match(dl
, "show")) {
1537 return cmd_dev_eswitch_show(dl
);
1539 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1543 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1545 struct dl
*dl
= data
;
1546 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1547 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1549 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1550 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
1551 return MNL_CB_ERROR
;
1556 static int cmd_dev_show(struct dl
*dl
)
1558 struct nlmsghdr
*nlh
;
1559 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1562 if (dl_argc(dl
) == 0)
1563 flags
|= NLM_F_DUMP
;
1565 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
1567 if (dl_argc(dl
) > 0) {
1568 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
1573 pr_out_section_start(dl
, "dev");
1574 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
1575 pr_out_section_end(dl
);
1579 static int cmd_dev(struct dl
*dl
)
1581 if (dl_argv_match(dl
, "help")) {
1584 } else if (dl_argv_match(dl
, "show") ||
1585 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1587 return cmd_dev_show(dl
);
1588 } else if (dl_argv_match(dl
, "eswitch")) {
1590 return cmd_dev_eswitch(dl
);
1592 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1596 static void cmd_port_help(void)
1598 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
1599 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
1600 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
1601 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
1604 static const char *port_type_name(uint32_t type
)
1607 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
1608 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
1609 case DEVLINK_PORT_TYPE_ETH
: return "eth";
1610 case DEVLINK_PORT_TYPE_IB
: return "ib";
1611 default: return "<unknown type>";
1615 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
1617 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
1618 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
1620 pr_out_port_handle_start(dl
, tb
, false);
1622 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
1624 pr_out_str(dl
, "type", port_type_name(port_type
));
1626 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
1628 if (port_type
!= des_port_type
)
1629 pr_out_str(dl
, "des_type",
1630 port_type_name(des_port_type
));
1633 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
1634 pr_out_str(dl
, "netdev",
1635 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
1636 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
])
1637 pr_out_str(dl
, "ibdev",
1638 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
1639 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
1640 pr_out_uint(dl
, "split_group",
1641 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
1642 pr_out_port_handle_end(dl
);
1645 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1647 struct dl
*dl
= data
;
1648 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1649 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1651 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1652 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1653 !tb
[DEVLINK_ATTR_PORT_INDEX
])
1654 return MNL_CB_ERROR
;
1655 pr_out_port(dl
, tb
);
1659 static int cmd_port_show(struct dl
*dl
)
1661 struct nlmsghdr
*nlh
;
1662 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1665 if (dl_argc(dl
) == 0)
1666 flags
|= NLM_F_DUMP
;
1668 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
1670 if (dl_argc(dl
) > 0) {
1671 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
1676 pr_out_section_start(dl
, "port");
1677 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
1678 pr_out_section_end(dl
);
1682 static int cmd_port_set(struct dl
*dl
)
1684 struct nlmsghdr
*nlh
;
1687 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
1688 NLM_F_REQUEST
| NLM_F_ACK
);
1690 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
1694 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1697 static int cmd_port_split(struct dl
*dl
)
1699 struct nlmsghdr
*nlh
;
1702 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
1703 NLM_F_REQUEST
| NLM_F_ACK
);
1705 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
1709 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1712 static int cmd_port_unsplit(struct dl
*dl
)
1714 struct nlmsghdr
*nlh
;
1717 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
1718 NLM_F_REQUEST
| NLM_F_ACK
);
1720 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
1724 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1727 static int cmd_port(struct dl
*dl
)
1729 if (dl_argv_match(dl
, "help")) {
1732 } else if (dl_argv_match(dl
, "show") ||
1733 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1735 return cmd_port_show(dl
);
1736 } else if (dl_argv_match(dl
, "set")) {
1738 return cmd_port_set(dl
);
1739 } else if (dl_argv_match(dl
, "split")) {
1741 return cmd_port_split(dl
);
1742 } else if (dl_argv_match(dl
, "unsplit")) {
1744 return cmd_port_unsplit(dl
);
1746 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1750 static void cmd_sb_help(void)
1752 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
1753 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
1754 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
1755 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
1756 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1757 pr_err(" pool POOL_INDEX ]\n");
1758 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1759 pr_err(" pool POOL_INDEX th THRESHOLD\n");
1760 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1761 pr_err(" type { ingress | egress } ]\n");
1762 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1763 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
1764 pr_err(" th THRESHOLD\n");
1765 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
1766 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
1767 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
1770 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
1772 pr_out_handle_start_arr(dl
, tb
);
1773 pr_out_uint(dl
, "sb",
1774 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
1775 pr_out_uint(dl
, "size",
1776 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
1777 pr_out_uint(dl
, "ing_pools",
1778 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
1779 pr_out_uint(dl
, "eg_pools",
1780 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
1781 pr_out_uint(dl
, "ing_tcs",
1782 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
1783 pr_out_uint(dl
, "eg_tcs",
1784 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
1785 pr_out_handle_end(dl
);
1788 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1790 struct dl
*dl
= data
;
1791 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1792 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1794 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1795 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1796 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
1797 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
1798 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
1799 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
1800 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
1801 return MNL_CB_ERROR
;
1806 static int cmd_sb_show(struct dl
*dl
)
1808 struct nlmsghdr
*nlh
;
1809 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1812 if (dl_argc(dl
) == 0)
1813 flags
|= NLM_F_DUMP
;
1815 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
1817 if (dl_argc(dl
) > 0) {
1818 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
1823 pr_out_section_start(dl
, "sb");
1824 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
1825 pr_out_section_end(dl
);
1829 static const char *pool_type_name(uint8_t type
)
1832 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
1833 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
1834 default: return "<unknown type>";
1838 static const char *threshold_type_name(uint8_t type
)
1841 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
1842 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
1843 default: return "<unknown type>";
1847 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
1849 pr_out_handle_start_arr(dl
, tb
);
1850 pr_out_uint(dl
, "sb",
1851 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
1852 pr_out_uint(dl
, "pool",
1853 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
1854 pr_out_str(dl
, "type",
1855 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
1856 pr_out_uint(dl
, "size",
1857 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
1858 pr_out_str(dl
, "thtype",
1859 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
1860 pr_out_handle_end(dl
);
1863 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1865 struct dl
*dl
= data
;
1866 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1867 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1869 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1870 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1871 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
1872 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
1873 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
1874 return MNL_CB_ERROR
;
1875 pr_out_sb_pool(dl
, tb
);
1879 static int cmd_sb_pool_show(struct dl
*dl
)
1881 struct nlmsghdr
*nlh
;
1882 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1885 if (dl_argc(dl
) == 0)
1886 flags
|= NLM_F_DUMP
;
1888 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
1890 if (dl_argc(dl
) > 0) {
1891 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
1897 pr_out_section_start(dl
, "pool");
1898 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
1899 pr_out_section_end(dl
);
1903 static int cmd_sb_pool_set(struct dl
*dl
)
1905 struct nlmsghdr
*nlh
;
1908 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
1909 NLM_F_REQUEST
| NLM_F_ACK
);
1911 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
1912 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
1916 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1919 static int cmd_sb_pool(struct dl
*dl
)
1921 if (dl_argv_match(dl
, "help")) {
1924 } else if (dl_argv_match(dl
, "show") ||
1925 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
1927 return cmd_sb_pool_show(dl
);
1928 } else if (dl_argv_match(dl
, "set")) {
1930 return cmd_sb_pool_set(dl
);
1932 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
1936 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
1938 pr_out_port_handle_start_arr(dl
, tb
, true);
1939 pr_out_uint(dl
, "sb",
1940 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
1941 pr_out_uint(dl
, "pool",
1942 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
1943 pr_out_uint(dl
, "threshold",
1944 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
1945 pr_out_port_handle_end(dl
);
1948 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1950 struct dl
*dl
= data
;
1951 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1952 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1954 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1955 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
1956 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
1957 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
1958 return MNL_CB_ERROR
;
1959 pr_out_sb_port_pool(dl
, tb
);
1963 static int cmd_sb_port_pool_show(struct dl
*dl
)
1965 struct nlmsghdr
*nlh
;
1966 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
1969 if (dl_argc(dl
) == 0)
1970 flags
|= NLM_F_DUMP
;
1972 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
1974 if (dl_argc(dl
) > 0) {
1975 err
= dl_argv_parse_put(nlh
, dl
,
1976 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
1982 pr_out_section_start(dl
, "port_pool");
1983 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
1984 pr_out_section_end(dl
);
1988 static int cmd_sb_port_pool_set(struct dl
*dl
)
1990 struct nlmsghdr
*nlh
;
1993 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
1994 NLM_F_REQUEST
| NLM_F_ACK
);
1996 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
1997 DL_OPT_SB_TH
, DL_OPT_SB
);
2001 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2004 static int cmd_sb_port_pool(struct dl
*dl
)
2006 if (dl_argv_match(dl
, "help")) {
2009 } else if (dl_argv_match(dl
, "show") ||
2010 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2012 return cmd_sb_port_pool_show(dl
);
2013 } else if (dl_argv_match(dl
, "set")) {
2015 return cmd_sb_port_pool_set(dl
);
2017 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2021 static int cmd_sb_port(struct dl
*dl
)
2023 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2026 } else if (dl_argv_match(dl
, "pool")) {
2028 return cmd_sb_port_pool(dl
);
2030 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2034 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
2036 pr_out_port_handle_start_arr(dl
, tb
, true);
2037 pr_out_uint(dl
, "sb",
2038 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
2039 pr_out_uint(dl
, "tc",
2040 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
2041 pr_out_str(dl
, "type",
2042 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
2043 pr_out_uint(dl
, "pool",
2044 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
2045 pr_out_uint(dl
, "threshold",
2046 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
2047 pr_out_port_handle_end(dl
);
2050 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2052 struct dl
*dl
= data
;
2053 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2054 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2056 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2057 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2058 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
2059 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
2060 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
2061 return MNL_CB_ERROR
;
2062 pr_out_sb_tc_bind(dl
, tb
);
2066 static int cmd_sb_tc_bind_show(struct dl
*dl
)
2068 struct nlmsghdr
*nlh
;
2069 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2072 if (dl_argc(dl
) == 0)
2073 flags
|= NLM_F_DUMP
;
2075 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
2077 if (dl_argc(dl
) > 0) {
2078 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
2079 DL_OPT_SB_TYPE
, DL_OPT_SB
);
2084 pr_out_section_start(dl
, "tc_bind");
2085 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
2086 pr_out_section_end(dl
);
2090 static int cmd_sb_tc_bind_set(struct dl
*dl
)
2092 struct nlmsghdr
*nlh
;
2095 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
2096 NLM_F_REQUEST
| NLM_F_ACK
);
2098 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
2099 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
2104 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2107 static int cmd_sb_tc_bind(struct dl
*dl
)
2109 if (dl_argv_match(dl
, "help")) {
2112 } else if (dl_argv_match(dl
, "show") ||
2113 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2115 return cmd_sb_tc_bind_show(dl
);
2116 } else if (dl_argv_match(dl
, "set")) {
2118 return cmd_sb_tc_bind_set(dl
);
2120 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2124 static int cmd_sb_tc(struct dl
*dl
)
2126 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2129 } else if (dl_argv_match(dl
, "bind")) {
2131 return cmd_sb_tc_bind(dl
);
2133 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2138 struct list_head list
;
2142 uint32_t bound_pool_index
;
2146 struct list_head list
;
2149 uint32_t port_index
;
2151 struct list_head pool_list
;
2152 struct list_head ing_tc_list
;
2153 struct list_head eg_tc_list
;
2159 struct list_head port_list
;
2162 static struct occ_item
*occ_item_alloc(void)
2164 return calloc(1, sizeof(struct occ_item
));
2167 static void occ_item_free(struct occ_item
*occ_item
)
2172 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
2174 struct occ_port
*occ_port
;
2176 occ_port
= calloc(1, sizeof(*occ_port
));
2179 occ_port
->port_index
= port_index
;
2180 INIT_LIST_HEAD(&occ_port
->pool_list
);
2181 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
2182 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
2186 static void occ_port_free(struct occ_port
*occ_port
)
2188 struct occ_item
*occ_item
, *tmp
;
2190 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
2191 occ_item_free(occ_item
);
2192 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
2193 occ_item_free(occ_item
);
2194 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
2195 occ_item_free(occ_item
);
2198 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
2200 struct occ_show
*occ_show
;
2202 occ_show
= calloc(1, sizeof(*occ_show
));
2206 INIT_LIST_HEAD(&occ_show
->port_list
);
2210 static void occ_show_free(struct occ_show
*occ_show
)
2212 struct occ_port
*occ_port
, *tmp
;
2214 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
2215 occ_port_free(occ_port
);
2218 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
2221 struct occ_port
*occ_port
;
2222 uint32_t port_index
;
2224 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
2226 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
2227 if (occ_port
->port_index
== port_index
)
2230 occ_port
= occ_port_alloc(port_index
);
2233 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
2237 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
2240 struct occ_item
*occ_item
;
2243 pr_out_sp(7, " %s:", label
);
2244 list_for_each_entry(occ_item
, list
, list
) {
2245 if ((i
- 1) % 4 == 0 && i
!= 1)
2248 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
2249 occ_item
->bound_pool_index
);
2251 pr_out_sp(7, "%2u:", occ_item
->index
);
2252 pr_out_sp(15, "%7u/%u", occ_item
->cur
, occ_item
->max
);
2256 if ((i
- 1) % 4 != 0)
2260 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
2261 struct list_head
*list
,
2264 struct occ_item
*occ_item
;
2267 jsonw_name(dl
->jw
, label
);
2268 jsonw_start_object(dl
->jw
);
2269 list_for_each_entry(occ_item
, list
, list
) {
2270 sprintf(buf
, "%u", occ_item
->index
);
2271 jsonw_name(dl
->jw
, buf
);
2272 jsonw_start_object(dl
->jw
);
2274 jsonw_uint_field(dl
->jw
, "bound_pool",
2275 occ_item
->bound_pool_index
);
2276 jsonw_uint_field(dl
->jw
, "current", occ_item
->cur
);
2277 jsonw_uint_field(dl
->jw
, "max", occ_item
->max
);
2278 jsonw_end_object(dl
->jw
);
2280 jsonw_end_object(dl
->jw
);
2283 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
2285 if (dl
->json_output
) {
2286 pr_out_json_occ_show_item_list(dl
, "pool",
2287 &occ_port
->pool_list
, false);
2288 pr_out_json_occ_show_item_list(dl
, "itc",
2289 &occ_port
->ing_tc_list
, true);
2290 pr_out_json_occ_show_item_list(dl
, "etc",
2291 &occ_port
->eg_tc_list
, true);
2294 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
2295 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
2296 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
2300 static void pr_out_occ_show(struct occ_show
*occ_show
)
2302 struct dl
*dl
= occ_show
->dl
;
2303 struct dl_opts
*opts
= &dl
->opts
;
2304 struct occ_port
*occ_port
;
2306 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
2307 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
2308 occ_port
->port_index
, true, false);
2309 pr_out_occ_show_port(dl
, occ_port
);
2310 pr_out_port_handle_end(dl
);
2314 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
2317 struct occ_port
*occ_port
;
2318 struct occ_item
*occ_item
;
2320 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
2323 occ_port
= occ_port_get(occ_show
, tb
);
2325 occ_show
->err
= -ENOMEM
;
2329 occ_item
= occ_item_alloc();
2331 occ_show
->err
= -ENOMEM
;
2334 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
2335 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
2336 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
2337 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
2340 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
2342 struct occ_show
*occ_show
= data
;
2343 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2344 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2346 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2347 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2348 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
2349 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
2350 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
2351 return MNL_CB_ERROR
;
2352 cmd_sb_occ_port_pool_process(occ_show
, tb
);
2356 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
2359 struct occ_port
*occ_port
;
2360 struct occ_item
*occ_item
;
2363 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
2366 occ_port
= occ_port_get(occ_show
, tb
);
2368 occ_show
->err
= -ENOMEM
;
2372 occ_item
= occ_item_alloc();
2374 occ_show
->err
= -ENOMEM
;
2377 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
2378 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
2379 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
2380 occ_item
->bound_pool_index
=
2381 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
2382 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
2383 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
2384 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
2385 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
2386 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
2388 occ_item_free(occ_item
);
2391 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
2393 struct occ_show
*occ_show
= data
;
2394 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2395 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2397 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2398 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2399 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
2400 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
2401 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
2402 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
2403 return MNL_CB_ERROR
;
2404 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
2408 static int cmd_sb_occ_show(struct dl
*dl
)
2410 struct nlmsghdr
*nlh
;
2411 struct occ_show
*occ_show
;
2412 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
2415 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
2419 occ_show
= occ_show_alloc(dl
);
2423 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
2425 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
2426 cmd_sb_occ_port_pool_process_cb
, occ_show
);
2430 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
2432 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
2433 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
2437 pr_out_section_start(dl
, "occupancy");
2438 pr_out_occ_show(occ_show
);
2439 pr_out_section_end(dl
);
2442 occ_show_free(occ_show
);
2446 static int cmd_sb_occ_snapshot(struct dl
*dl
)
2448 struct nlmsghdr
*nlh
;
2451 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
2452 NLM_F_REQUEST
| NLM_F_ACK
);
2454 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
2458 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2461 static int cmd_sb_occ_clearmax(struct dl
*dl
)
2463 struct nlmsghdr
*nlh
;
2466 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
2467 NLM_F_REQUEST
| NLM_F_ACK
);
2469 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
2473 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2476 static int cmd_sb_occ(struct dl
*dl
)
2478 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2481 } else if (dl_argv_match(dl
, "show") ||
2482 dl_argv_match(dl
, "list")) {
2484 return cmd_sb_occ_show(dl
);
2485 } else if (dl_argv_match(dl
, "snapshot")) {
2487 return cmd_sb_occ_snapshot(dl
);
2488 } else if (dl_argv_match(dl
, "clearmax")) {
2490 return cmd_sb_occ_clearmax(dl
);
2492 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2496 static int cmd_sb(struct dl
*dl
)
2498 if (dl_argv_match(dl
, "help")) {
2501 } else if (dl_argv_match(dl
, "show") ||
2502 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2504 return cmd_sb_show(dl
);
2505 } else if (dl_argv_match(dl
, "pool")) {
2507 return cmd_sb_pool(dl
);
2508 } else if (dl_argv_match(dl
, "port")) {
2510 return cmd_sb_port(dl
);
2511 } else if (dl_argv_match(dl
, "tc")) {
2513 return cmd_sb_tc(dl
);
2514 } else if (dl_argv_match(dl
, "occupancy")) {
2516 return cmd_sb_occ(dl
);
2518 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2522 static const char *cmd_name(uint8_t cmd
)
2525 case DEVLINK_CMD_UNSPEC
: return "unspec";
2526 case DEVLINK_CMD_GET
: return "get";
2527 case DEVLINK_CMD_SET
: return "set";
2528 case DEVLINK_CMD_NEW
: return "new";
2529 case DEVLINK_CMD_DEL
: return "del";
2530 case DEVLINK_CMD_PORT_GET
: return "get";
2531 case DEVLINK_CMD_PORT_SET
: return "set";
2532 case DEVLINK_CMD_PORT_NEW
: return "net";
2533 case DEVLINK_CMD_PORT_DEL
: return "del";
2534 default: return "<unknown cmd>";
2538 static const char *cmd_obj(uint8_t cmd
)
2541 case DEVLINK_CMD_UNSPEC
: return "unspec";
2542 case DEVLINK_CMD_GET
:
2543 case DEVLINK_CMD_SET
:
2544 case DEVLINK_CMD_NEW
:
2545 case DEVLINK_CMD_DEL
:
2547 case DEVLINK_CMD_PORT_GET
:
2548 case DEVLINK_CMD_PORT_SET
:
2549 case DEVLINK_CMD_PORT_NEW
:
2550 case DEVLINK_CMD_PORT_DEL
:
2552 default: return "<unknown obj>";
2556 static void pr_out_mon_header(uint8_t cmd
)
2558 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
2561 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
2563 const char *obj
= cmd_obj(cmd
);
2564 unsigned int index
= 0;
2565 const char *cur_obj
;
2569 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
2570 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
2576 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2578 struct dl
*dl
= data
;
2579 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2580 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2581 uint8_t cmd
= genl
->cmd
;
2583 if (!cmd_filter_check(dl
, cmd
))
2587 case DEVLINK_CMD_GET
: /* fall through */
2588 case DEVLINK_CMD_SET
: /* fall through */
2589 case DEVLINK_CMD_NEW
: /* fall through */
2590 case DEVLINK_CMD_DEL
:
2591 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2592 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2593 return MNL_CB_ERROR
;
2594 pr_out_mon_header(genl
->cmd
);
2597 case DEVLINK_CMD_PORT_GET
: /* fall through */
2598 case DEVLINK_CMD_PORT_SET
: /* fall through */
2599 case DEVLINK_CMD_PORT_NEW
: /* fall through */
2600 case DEVLINK_CMD_PORT_DEL
:
2601 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2602 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2603 !tb
[DEVLINK_ATTR_PORT_INDEX
])
2604 return MNL_CB_ERROR
;
2605 pr_out_mon_header(genl
->cmd
);
2606 pr_out_port(dl
, tb
);
2612 static int cmd_mon_show(struct dl
*dl
)
2615 unsigned int index
= 0;
2616 const char *cur_obj
;
2618 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
2619 if (strcmp(cur_obj
, "all") != 0 &&
2620 strcmp(cur_obj
, "dev") != 0 &&
2621 strcmp(cur_obj
, "port") != 0) {
2622 pr_err("Unknown object \"%s\"\n", cur_obj
);
2626 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
2629 err
= _mnlg_socket_recv_run(dl
->nlg
, cmd_mon_show_cb
, dl
);
2635 static void cmd_mon_help(void)
2637 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
2638 "where OBJECT-LIST := { dev | port }\n");
2641 static int cmd_mon(struct dl
*dl
)
2643 if (dl_argv_match(dl
, "help")) {
2646 } else if (dl_no_arg(dl
)) {
2648 return cmd_mon_show(dl
);
2650 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2654 struct dpipe_field
{
2657 unsigned int bitwidth
;
2658 enum devlink_dpipe_field_mapping_type mapping_type
;
2661 struct dpipe_header
{
2662 struct list_head list
;
2665 struct dpipe_field
*fields
;
2666 unsigned int fields_count
;
2672 struct list_head global_headers
;
2673 struct list_head local_headers
;
2677 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
2679 struct dpipe_header
*header
;
2681 header
= calloc(1, sizeof(struct dpipe_header
));
2684 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
2685 if (!header
->fields
)
2686 goto err_fields_alloc
;
2687 header
->fields_count
= fields_count
;
2695 static void dpipe_header_free(struct dpipe_header
*header
)
2697 free(header
->fields
);
2701 static void dpipe_header_clear(struct dpipe_header
*header
)
2703 struct dpipe_field
*field
;
2706 for (i
= 0; i
< header
->fields_count
; i
++) {
2707 field
= &header
->fields
[i
];
2713 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
2714 struct dpipe_header
*header
, bool global
)
2717 list_add(&header
->list
, &ctx
->global_headers
);
2719 list_add(&header
->list
, &ctx
->local_headers
);
2722 static void dpipe_header_del(struct dpipe_header
*header
)
2724 list_del(&header
->list
);
2727 static struct dpipe_ctx
*dpipe_ctx_alloc(struct dl
*dl
)
2729 struct dpipe_ctx
*ctx
;
2731 ctx
= calloc(1, sizeof(struct dpipe_ctx
));
2735 INIT_LIST_HEAD(&ctx
->global_headers
);
2736 INIT_LIST_HEAD(&ctx
->local_headers
);
2740 static void dpipe_ctx_free(struct dpipe_ctx
*ctx
)
2745 static void dpipe_ctx_clear(struct dpipe_ctx
*ctx
)
2747 struct dpipe_header
*header
, *tmp
;
2749 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
2751 dpipe_header_del(header
);
2752 dpipe_header_clear(header
);
2753 dpipe_header_free(header
);
2755 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
2757 dpipe_header_del(header
);
2758 dpipe_header_clear(header
);
2759 dpipe_header_free(header
);
2763 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
2764 uint32_t header_id
, bool global
)
2766 struct list_head
*header_list
;
2767 struct dpipe_header
*header
;
2770 header_list
= &ctx
->global_headers
;
2772 header_list
= &ctx
->local_headers
;
2773 list_for_each_entry(header
, header_list
, list
) {
2774 if (header
->id
!= header_id
)
2776 return header
->name
;
2781 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
2783 uint32_t field_id
, bool global
)
2785 struct list_head
*header_list
;
2786 struct dpipe_header
*header
;
2789 header_list
= &ctx
->global_headers
;
2791 header_list
= &ctx
->local_headers
;
2792 list_for_each_entry(header
, header_list
, list
) {
2793 if (header
->id
!= header_id
)
2795 return header
->fields
[field_id
].name
;
2801 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
2803 switch (mapping_type
) {
2804 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
2806 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
2814 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
2815 uint32_t field_id
, bool global
)
2817 enum devlink_dpipe_field_mapping_type mapping_type
;
2818 struct list_head
*header_list
;
2819 struct dpipe_header
*header
;
2822 header_list
= &ctx
->global_headers
;
2824 header_list
= &ctx
->local_headers
;
2825 list_for_each_entry(header
, header_list
, list
) {
2826 if (header
->id
!= header_id
)
2828 mapping_type
= header
->fields
[field_id
].mapping_type
;
2829 return dpipe_field_mapping_e2s(mapping_type
);
2834 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
2835 struct dpipe_field
*fields
,
2836 unsigned int field_count
)
2838 struct dpipe_field
*field
;
2841 for (i
= 0; i
< field_count
; i
++) {
2843 pr_out_entry_start(ctx
->dl
);
2844 pr_out_str(ctx
->dl
, "name", field
->name
);
2845 if (ctx
->dl
->verbose
)
2846 pr_out_uint(ctx
->dl
, "id", field
->id
);
2847 pr_out_uint(ctx
->dl
, "bitwidth", field
->bitwidth
);
2848 if (field
->mapping_type
)
2849 pr_out_str(ctx
->dl
, "mapping_type",
2850 dpipe_field_mapping_e2s(field
->mapping_type
));
2851 pr_out_entry_end(ctx
->dl
);
2856 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
2857 struct dpipe_header
*header
, bool global
)
2859 pr_out_handle_start_arr(ctx
->dl
, tb
);
2860 pr_out_str(ctx
->dl
, "name", header
->name
);
2861 if (ctx
->dl
->verbose
) {
2862 pr_out_uint(ctx
->dl
, "id", header
->id
);
2863 pr_out_str(ctx
->dl
, "global",
2864 global
? "true" : "false");
2866 pr_out_array_start(ctx
->dl
, "field");
2867 pr_out_dpipe_fields(ctx
, header
->fields
,
2868 header
->fields_count
);
2869 pr_out_array_end(ctx
->dl
);
2870 pr_out_handle_end(ctx
->dl
);
2873 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
2876 struct dpipe_header
*header
;
2878 list_for_each_entry(header
, &ctx
->local_headers
, list
)
2879 pr_out_dpipe_header(ctx
, tb
, header
, false);
2881 list_for_each_entry(header
, &ctx
->global_headers
, list
)
2882 pr_out_dpipe_header(ctx
, tb
, header
, true);
2885 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
2887 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
2891 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
2892 if (err
!= MNL_CB_OK
)
2894 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
2895 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
2896 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
2897 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
2900 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
2901 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
2902 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
2903 field
->name
= strdup(name
);
2906 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
2910 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
2911 struct dpipe_field
*fields
)
2913 struct nlattr
*nla_field
;
2917 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
2918 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
2926 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
2928 struct nlattr
*nla_field
;
2929 unsigned int count
= 0;
2931 mnl_attr_for_each_nested(nla_field
, nla_fields
)
2936 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
2938 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
2939 struct dpipe_header
*header
;
2940 unsigned int fields_count
;
2941 const char *header_name
;
2945 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
2946 if (err
!= MNL_CB_OK
)
2949 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
2950 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
2951 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
2954 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
2955 header
= dpipe_header_alloc(fields_count
);
2959 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
2960 header
->name
= strdup(header_name
);
2961 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
2962 header
->fields_count
= fields_count
;
2963 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
2965 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
2969 dpipe_header_add(ctx
, header
, global
);
2973 dpipe_header_free(header
);
2977 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
2979 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
2980 struct nlattr
*nla_header
;
2983 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
2984 err
= dpipe_header_get(ctx
, nla_header
);
2991 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
2993 struct dpipe_ctx
*ctx
= data
;
2994 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2995 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2998 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2999 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3000 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
3001 return MNL_CB_ERROR
;
3002 err
= dpipe_headers_get(ctx
, tb
);
3005 return MNL_CB_ERROR
;
3008 if (ctx
->print_headers
)
3009 pr_out_dpipe_headers(ctx
, tb
);
3013 static int cmd_dpipe_headers_show(struct dl
*dl
)
3015 struct nlmsghdr
*nlh
;
3016 struct dpipe_ctx
*ctx
;
3017 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3020 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
3022 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
3026 ctx
= dpipe_ctx_alloc(dl
);
3030 ctx
->print_headers
= true;
3032 pr_out_section_start(dl
, "header");
3033 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, ctx
);
3035 pr_err("error get headers %s\n", strerror(ctx
->err
));
3036 pr_out_section_end(dl
);
3038 dpipe_ctx_clear(ctx
);
3039 dpipe_ctx_free(ctx
);
3043 static void cmd_dpipe_header_help(void)
3045 pr_err("Usage: devlink dpipe headers show DEV\n");
3048 static int cmd_dpipe_header(struct dl
*dl
)
3050 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3051 cmd_dpipe_header_help();
3053 } else if (dl_argv_match(dl
, "show")) {
3055 return cmd_dpipe_headers_show(dl
);
3057 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3062 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
3064 switch (action_type
) {
3065 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
3066 return "field_modify";
3072 static void pr_out_dpipe_action(struct dpipe_ctx
*ctx
,
3073 uint32_t header_id
, uint32_t field_id
,
3074 uint32_t action_type
, bool global
)
3076 const char *mapping
;
3078 pr_out_str(ctx
->dl
, "type", dpipe_action_type_e2s(action_type
));
3079 pr_out_str(ctx
->dl
, "header", dpipe_header_id2s(ctx
, header_id
,
3081 pr_out_str(ctx
->dl
, "field", dpipe_field_id2s(ctx
, header_id
, field_id
,
3083 mapping
= dpipe_mapping_get(ctx
, header_id
, field_id
, global
);
3085 pr_out_str(ctx
->dl
, "mapping", mapping
);
3088 static int dpipe_action_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
3090 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
3091 uint32_t header_id
, field_id
, action_type
;
3095 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
3096 if (err
!= MNL_CB_OK
)
3099 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
3100 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
3101 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
3102 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
3106 header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
3107 field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
3108 action_type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
3109 global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
3111 pr_out_dpipe_action(ctx
, header_id
, field_id
, action_type
, global
);
3115 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
3116 struct nlattr
*nla_actions
)
3118 struct nlattr
*nla_action
;
3120 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
3121 pr_out_entry_start(ctx
->dl
);
3122 if (dpipe_action_show(ctx
, nla_action
))
3123 goto err_action_show
;
3124 pr_out_entry_end(ctx
->dl
);
3129 pr_out_entry_end(ctx
->dl
);
3134 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
3136 switch (match_type
) {
3137 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
3138 return "field_exact";
3144 static void pr_out_dpipe_match(struct dpipe_ctx
*ctx
,
3145 uint32_t header_id
, uint32_t field_id
,
3146 uint32_t match_type
, bool global
)
3148 const char *mapping
;
3150 pr_out_str(ctx
->dl
, "type", dpipe_match_type_e2s(match_type
));
3151 pr_out_str(ctx
->dl
, "header", dpipe_header_id2s(ctx
, header_id
,
3153 pr_out_str(ctx
->dl
, "field", dpipe_field_id2s(ctx
, header_id
, field_id
,
3155 mapping
= dpipe_mapping_get(ctx
, header_id
, field_id
, global
);
3157 pr_out_str(ctx
->dl
, "mapping", mapping
);
3161 static int dpipe_match_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
3163 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
3164 uint32_t header_id
, field_id
, match_type
;
3168 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
3169 if (err
!= MNL_CB_OK
)
3172 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
3173 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
3174 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
3175 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
3179 match_type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
3180 header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
3181 field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
3182 global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
3184 pr_out_dpipe_match(ctx
, header_id
, field_id
, match_type
, global
);
3188 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
3189 struct nlattr
*nla_matches
)
3191 struct nlattr
*nla_match
;
3193 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
3194 pr_out_entry_start(ctx
->dl
);
3195 if (dpipe_match_show(ctx
, nla_match
))
3196 goto err_match_show
;
3197 pr_out_entry_end(ctx
->dl
);
3202 pr_out_entry_end(ctx
->dl
);
3206 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
3208 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
3209 bool counters_enabled
;
3214 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
3215 if (err
!= MNL_CB_OK
)
3218 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
3219 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
3220 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
3221 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
3222 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
3226 name
= mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]);
3227 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
3228 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
3230 pr_out_str(ctx
->dl
, "name", name
);
3231 pr_out_uint(ctx
->dl
, "size", size
);
3232 pr_out_str(ctx
->dl
, "counters_enabled",
3233 counters_enabled
? "true" : "false");
3235 pr_out_array_start(ctx
->dl
, "match");
3236 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
3237 goto err_matches_show
;
3238 pr_out_array_end(ctx
->dl
);
3240 pr_out_array_start(ctx
->dl
, "action");
3241 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
3242 goto err_actions_show
;
3243 pr_out_array_end(ctx
->dl
);
3249 pr_out_array_end(ctx
->dl
);
3253 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
3255 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
3256 struct nlattr
*nla_table
;
3258 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
3259 pr_out_handle_start_arr(ctx
->dl
, tb
);
3260 if (dpipe_table_show(ctx
, nla_table
))
3261 goto err_table_show
;
3262 pr_out_handle_end(ctx
->dl
);
3267 pr_out_handle_end(ctx
->dl
);
3271 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3273 struct dpipe_ctx
*ctx
= data
;
3274 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3275 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3277 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3278 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3279 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
3280 return MNL_CB_ERROR
;
3282 if (dpipe_tables_show(ctx
, tb
))
3283 return MNL_CB_ERROR
;
3287 static int cmd_dpipe_table_show(struct dl
*dl
)
3289 struct nlmsghdr
*nlh
;
3290 struct dpipe_ctx
*ctx
;
3291 uint16_t flags
= NLM_F_REQUEST
;
3294 ctx
= dpipe_ctx_alloc(dl
);
3298 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
3302 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
3303 dl_opts_put(nlh
, dl
);
3304 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, ctx
);
3306 pr_err("error get headers %s\n", strerror(ctx
->err
));
3310 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3311 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
3312 dl_opts_put(nlh
, dl
);
3314 pr_out_section_start(dl
, "table");
3315 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, ctx
);
3316 pr_out_section_end(dl
);
3318 dpipe_ctx_clear(ctx
);
3319 dpipe_ctx_free(ctx
);
3323 static int cmd_dpipe_table_set(struct dl
*dl
)
3325 struct nlmsghdr
*nlh
;
3328 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
3329 NLM_F_REQUEST
| NLM_F_ACK
);
3331 err
= dl_argv_parse_put(nlh
, dl
,
3332 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
3333 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
3337 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3340 static int dpipe_entry_value_show(struct dpipe_ctx
*ctx
,
3341 struct nlattr
**nla_match_value
)
3346 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
3347 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
3349 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
3350 if (value_len
== sizeof(uint32_t)) {
3351 uint32_t value
, value_mask
, value_mapping
;
3354 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
3355 pr_out_uint(ctx
->dl
, "mapping_value", value_mapping
);
3359 value_mask
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
]);
3360 pr_out_uint(ctx
->dl
, "mask_value", value_mask
);
3363 value
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
3364 pr_out_uint(ctx
->dl
, "value", value
);
3373 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
3376 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
3379 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
3380 if (err
!= MNL_CB_OK
)
3383 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
3384 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
3388 pr_out_entry_start(ctx
->dl
);
3389 if (dpipe_match_show(ctx
, nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
3390 goto err_match_show
;
3391 if (dpipe_entry_value_show(ctx
, nla_match_value
))
3392 goto err_value_show
;
3393 pr_out_entry_end(ctx
->dl
);
3399 pr_out_entry_end(ctx
->dl
);
3403 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
3406 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
3409 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
3410 if (err
!= MNL_CB_OK
)
3413 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
3414 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
3418 pr_out_entry_start(ctx
->dl
);
3419 if (dpipe_action_show(ctx
, nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
3420 goto err_action_show
;
3421 if (dpipe_entry_value_show(ctx
, nla_action_value
))
3422 goto err_value_show
;
3423 pr_out_entry_end(ctx
->dl
);
3429 pr_out_entry_end(ctx
->dl
);
3434 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
3435 struct nlattr
*nla_action_values
)
3437 struct nlattr
*nla_action_value
;
3439 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
3440 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
3447 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
3448 struct nlattr
*nla_match_values
)
3450 struct nlattr
*nla_match_value
;
3452 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
3453 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
3459 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
3461 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
3462 uint32_t entry_index
;
3466 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
3467 if (err
!= MNL_CB_OK
)
3470 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
3471 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
3472 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
3476 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
3477 pr_out_uint(ctx
->dl
, "index", entry_index
);
3479 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
3480 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
3481 pr_out_uint(ctx
->dl
, "counter", counter
);
3484 pr_out_array_start(ctx
->dl
, "match_value");
3485 if (dpipe_tables_match_values_show(ctx
,
3486 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
3487 goto err_match_values_show
;
3488 pr_out_array_end(ctx
->dl
);
3490 pr_out_array_start(ctx
->dl
, "action_value");
3491 if (dpipe_tables_action_values_show(ctx
,
3492 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
3493 goto err_action_values_show
;
3494 pr_out_array_end(ctx
->dl
);
3497 err_action_values_show
:
3498 err_match_values_show
:
3499 pr_out_array_end(ctx
->dl
);
3503 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
3505 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
3506 struct nlattr
*nla_entry
;
3508 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
3509 pr_out_handle_start_arr(ctx
->dl
, tb
);
3510 if (dpipe_entry_show(ctx
, nla_entry
))
3511 goto err_entry_show
;
3512 pr_out_handle_end(ctx
->dl
);
3517 pr_out_handle_end(ctx
->dl
);
3521 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
3523 struct dpipe_ctx
*ctx
= data
;
3524 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3525 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3527 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3528 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3529 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
3530 return MNL_CB_ERROR
;
3532 if (dpipe_table_entries_show(ctx
, tb
))
3533 return MNL_CB_ERROR
;
3537 static int cmd_dpipe_table_dump(struct dl
*dl
)
3539 struct nlmsghdr
*nlh
;
3540 struct dpipe_ctx
*ctx
;
3541 uint16_t flags
= NLM_F_REQUEST
;
3544 ctx
= dpipe_ctx_alloc(dl
);
3548 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
3552 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
3553 dl_opts_put(nlh
, dl
);
3554 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, ctx
);
3556 pr_err("error get headers %s\n", strerror(ctx
->err
));
3560 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3561 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
3562 dl_opts_put(nlh
, dl
);
3564 pr_out_section_start(dl
, "table_entry");
3565 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, ctx
);
3566 pr_out_section_end(dl
);
3568 dpipe_ctx_clear(ctx
);
3569 dpipe_ctx_free(ctx
);
3573 static void cmd_dpipe_table_help(void)
3575 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
3576 "where OBJECT-LIST := { show | set | dump }\n");
3579 static int cmd_dpipe_table(struct dl
*dl
)
3581 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3582 cmd_dpipe_table_help();
3584 } else if (dl_argv_match(dl
, "show")) {
3586 return cmd_dpipe_table_show(dl
);
3587 } else if (dl_argv_match(dl
, "set")) {
3589 return cmd_dpipe_table_set(dl
);
3590 } else if (dl_argv_match(dl
, "dump")) {
3592 return cmd_dpipe_table_dump(dl
);
3594 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3598 static void cmd_dpipe_help(void)
3600 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
3601 "where OBJECT-LIST := { header | table }\n");
3604 static int cmd_dpipe(struct dl
*dl
)
3606 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3609 } else if (dl_argv_match(dl
, "header")) {
3611 return cmd_dpipe_header(dl
);
3612 } else if (dl_argv_match(dl
, "table")) {
3614 return cmd_dpipe_table(dl
);
3616 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3620 static void help(void)
3622 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
3623 "where OBJECT := { dev | port | sb | monitor | dpipe }\n"
3624 " OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] | -v[verbose] }\n");
3627 static int dl_cmd(struct dl
*dl
)
3629 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3632 } else if (dl_argv_match(dl
, "dev")) {
3635 } else if (dl_argv_match(dl
, "port")) {
3637 return cmd_port(dl
);
3638 } else if (dl_argv_match(dl
, "sb")) {
3641 } else if (dl_argv_match(dl
, "monitor")) {
3644 } else if (dl_argv_match(dl
, "dpipe")) {
3646 return cmd_dpipe(dl
);
3648 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
3652 static int dl_init(struct dl
*dl
, int argc
, char **argv
)
3659 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
3661 pr_err("Failed to connect to devlink Netlink\n");
3665 err
= ifname_map_init(dl
);
3667 pr_err("Failed to create index map\n");
3668 goto err_ifname_map_create
;
3670 if (dl
->json_output
) {
3671 dl
->jw
= jsonw_new(stdout
);
3673 pr_err("Failed to create JSON writer\n");
3676 jsonw_pretty(dl
->jw
, dl
->pretty_output
);
3681 ifname_map_fini(dl
);
3682 err_ifname_map_create
:
3683 mnlg_socket_close(dl
->nlg
);
3687 static void dl_fini(struct dl
*dl
)
3689 if (dl
->json_output
)
3690 jsonw_destroy(&dl
->jw
);
3691 ifname_map_fini(dl
);
3692 mnlg_socket_close(dl
->nlg
);
3695 static struct dl
*dl_alloc(void)
3699 dl
= calloc(1, sizeof(*dl
));
3705 static void dl_free(struct dl
*dl
)
3710 int main(int argc
, char **argv
)
3712 static const struct option long_options
[] = {
3713 { "Version", no_argument
, NULL
, 'V' },
3714 { "no-nice-names", no_argument
, NULL
, 'n' },
3715 { "json", no_argument
, NULL
, 'j' },
3716 { "pretty", no_argument
, NULL
, 'p' },
3717 { "verbose", no_argument
, NULL
, 'v' },
3718 { NULL
, 0, NULL
, 0 }
3727 pr_err("Failed to allocate memory for devlink\n");
3728 return EXIT_FAILURE
;
3731 while ((opt
= getopt_long(argc
, argv
, "Vnjpv",
3732 long_options
, NULL
)) >= 0) {
3736 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
3740 dl
->no_nice_names
= true;
3743 dl
->json_output
= true;
3746 dl
->pretty_output
= true;
3752 pr_err("Unknown option.\n");
3762 err
= dl_init(dl
, argc
, argv
);