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>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <sys/sysinfo.h>
27 #define _LINUX_SYSINFO_H /* avoid collision with musl header */
28 #include <linux/genetlink.h>
29 #include <linux/devlink.h>
30 #include <linux/netlink.h>
31 #include <libmnl/libmnl.h>
32 #include <netinet/ether.h>
33 #include <sys/select.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
41 #include "json_print.h"
43 #include "namespace.h"
45 #define ESWITCH_MODE_LEGACY "legacy"
46 #define ESWITCH_MODE_SWITCHDEV "switchdev"
47 #define ESWITCH_INLINE_MODE_NONE "none"
48 #define ESWITCH_INLINE_MODE_LINK "link"
49 #define ESWITCH_INLINE_MODE_NETWORK "network"
50 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
52 #define ESWITCH_ENCAP_MODE_NONE "none"
53 #define ESWITCH_ENCAP_MODE_BASIC "basic"
55 #define PARAM_CMODE_RUNTIME_STR "runtime"
56 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
57 #define PARAM_CMODE_PERMANENT_STR "permanent"
58 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
60 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
61 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
62 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
64 static int g_new_line_count
;
65 static int g_indent_level
;
66 static bool g_indent_newline
;
68 #define INDENT_STR_STEP 2
69 #define INDENT_STR_MAXLEN 32
70 static char g_indent_str
[INDENT_STR_MAXLEN
+ 1] = "";
72 static void __attribute__((format(printf
, 1, 2)))
73 pr_err(const char *fmt
, ...)
78 vfprintf(stderr
, fmt
, ap
);
82 static void __attribute__((format(printf
, 1, 2)))
83 pr_out(const char *fmt
, ...)
87 if (g_indent_newline
) {
88 printf("%s", g_indent_str
);
89 g_indent_newline
= false;
97 static void __attribute__((format(printf
, 2, 3)))
98 pr_out_sp(unsigned int num
, const char *fmt
, ...)
104 ret
= vprintf(fmt
, ap
);
108 printf("%*s", num
- ret
, "");
109 g_new_line_count
= 0; \
112 static void __attribute__((format(printf
, 1, 2)))
113 pr_out_tty(const char *fmt
, ...)
117 if (!isatty(STDOUT_FILENO
))
124 static void __pr_out_indent_inc(void)
126 if (g_indent_level
+ INDENT_STR_STEP
> INDENT_STR_MAXLEN
)
128 g_indent_level
+= INDENT_STR_STEP
;
129 memset(g_indent_str
, ' ', sizeof(g_indent_str
));
130 g_indent_str
[g_indent_level
] = '\0';
133 static void __pr_out_indent_dec(void)
135 if (g_indent_level
- INDENT_STR_STEP
< 0)
137 g_indent_level
-= INDENT_STR_STEP
;
138 g_indent_str
[g_indent_level
] = '\0';
141 static void __pr_out_newline(void)
143 if (g_new_line_count
< 1) {
145 g_indent_newline
= true;
150 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
151 mnl_cb_t data_cb
, void *data
)
155 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
157 pr_err("devlink answers: %s\n", strerror(errno
));
163 static void dummy_signal_handler(int signum
)
167 static int _mnlg_socket_recv_run_intr(struct mnlg_socket
*nlg
,
168 mnl_cb_t data_cb
, void *data
)
170 struct sigaction act
, oact
;
173 act
.sa_handler
= dummy_signal_handler
;
174 sigemptyset(&act
.sa_mask
);
175 act
.sa_flags
= SA_NODEFER
;
177 sigaction(SIGINT
, &act
, &oact
);
178 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
179 sigaction(SIGINT
, &oact
, NULL
);
180 if (err
< 0 && errno
!= EINTR
) {
181 pr_err("devlink answers: %s\n", strerror(errno
));
187 static int _mnlg_socket_send(struct mnlg_socket
*nlg
,
188 const struct nlmsghdr
*nlh
)
192 err
= mnlg_socket_send(nlg
, nlh
);
194 pr_err("Failed to call mnlg_socket_send\n");
200 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
201 const struct nlmsghdr
*nlh
,
202 mnl_cb_t data_cb
, void *data
)
206 err
= _mnlg_socket_send(nlg
, nlh
);
209 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
212 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
213 const char *group_name
)
217 err
= mnlg_socket_group_add(nlg
, group_name
);
219 pr_err("Failed to call mnlg_socket_group_add\n");
226 struct list_head list
;
233 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
234 const char *dev_name
,
238 struct ifname_map
*ifname_map
;
240 ifname_map
= calloc(1, sizeof(*ifname_map
));
243 ifname_map
->bus_name
= strdup(bus_name
);
244 ifname_map
->dev_name
= strdup(dev_name
);
245 ifname_map
->port_index
= port_index
;
246 ifname_map
->ifname
= strdup(ifname
);
247 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
248 !ifname_map
->ifname
) {
249 free(ifname_map
->ifname
);
250 free(ifname_map
->dev_name
);
251 free(ifname_map
->bus_name
);
258 static void ifname_map_free(struct ifname_map
*ifname_map
)
260 free(ifname_map
->ifname
);
261 free(ifname_map
->dev_name
);
262 free(ifname_map
->bus_name
);
266 #define DL_OPT_HANDLE BIT(0)
267 #define DL_OPT_HANDLEP BIT(1)
268 #define DL_OPT_PORT_TYPE BIT(2)
269 #define DL_OPT_PORT_COUNT BIT(3)
270 #define DL_OPT_SB BIT(4)
271 #define DL_OPT_SB_POOL BIT(5)
272 #define DL_OPT_SB_SIZE BIT(6)
273 #define DL_OPT_SB_TYPE BIT(7)
274 #define DL_OPT_SB_THTYPE BIT(8)
275 #define DL_OPT_SB_TH BIT(9)
276 #define DL_OPT_SB_TC BIT(10)
277 #define DL_OPT_ESWITCH_MODE BIT(11)
278 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
279 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
280 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
281 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
282 #define DL_OPT_RESOURCE_PATH BIT(16)
283 #define DL_OPT_RESOURCE_SIZE BIT(17)
284 #define DL_OPT_PARAM_NAME BIT(18)
285 #define DL_OPT_PARAM_VALUE BIT(19)
286 #define DL_OPT_PARAM_CMODE BIT(20)
287 #define DL_OPT_HANDLE_REGION BIT(21)
288 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
289 #define DL_OPT_REGION_ADDRESS BIT(23)
290 #define DL_OPT_REGION_LENGTH BIT(24)
291 #define DL_OPT_FLASH_FILE_NAME BIT(25)
292 #define DL_OPT_FLASH_COMPONENT BIT(26)
293 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
294 #define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(28)
295 #define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(29)
296 #define DL_OPT_TRAP_NAME BIT(30)
297 #define DL_OPT_TRAP_ACTION BIT(31)
298 #define DL_OPT_TRAP_GROUP_NAME BIT(32)
299 #define DL_OPT_NETNS BIT(33)
300 #define DL_OPT_TRAP_POLICER_ID BIT(34)
301 #define DL_OPT_TRAP_POLICER_RATE BIT(35)
302 #define DL_OPT_TRAP_POLICER_BURST BIT(36)
303 #define DL_OPT_HEALTH_REPORTER_AUTO_DUMP BIT(37)
304 #define DL_OPT_PORT_FUNCTION_HW_ADDR BIT(38)
307 uint64_t present
; /* flags of present items */
311 enum devlink_port_type port_type
;
314 uint16_t sb_pool_index
;
315 uint32_t sb_pool_size
;
316 enum devlink_sb_pool_type sb_pool_type
;
317 enum devlink_sb_threshold_type sb_pool_thtype
;
318 uint32_t sb_threshold
;
319 uint16_t sb_tc_index
;
320 enum devlink_eswitch_mode eswitch_mode
;
321 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
322 const char *dpipe_table_name
;
323 bool dpipe_counters_enabled
;
324 enum devlink_eswitch_encap_mode eswitch_encap_mode
;
325 const char *resource_path
;
326 uint64_t resource_size
;
327 uint32_t resource_id
;
328 bool resource_id_valid
;
329 const char *param_name
;
330 const char *param_value
;
331 enum devlink_param_cmode cmode
;
333 uint32_t region_snapshot_id
;
334 uint64_t region_address
;
335 uint64_t region_length
;
336 const char *flash_file_name
;
337 const char *flash_component
;
338 const char *reporter_name
;
339 uint64_t reporter_graceful_period
;
340 bool reporter_auto_recover
;
341 bool reporter_auto_dump
;
342 const char *trap_name
;
343 const char *trap_group_name
;
344 enum devlink_trap_action trap_action
;
347 uint32_t trap_policer_id
;
348 uint64_t trap_policer_rate
;
349 uint64_t trap_policer_burst
;
350 char port_function_hw_addr
[MAX_ADDR_LEN
];
351 uint32_t port_function_hw_addr_len
;
355 struct mnlg_socket
*nlg
;
356 struct list_head ifname_map_list
;
373 static int dl_argc(struct dl
*dl
)
378 static char *dl_argv(struct dl
*dl
)
380 if (dl_argc(dl
) == 0)
385 static void dl_arg_inc(struct dl
*dl
)
387 if (dl_argc(dl
) == 0)
393 static void dl_arg_dec(struct dl
*dl
)
399 static char *dl_argv_next(struct dl
*dl
)
403 if (dl_argc(dl
) == 0)
411 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
413 if (index
>= dl_argc(dl
))
415 return dl
->argv
[index
];
418 static int strcmpx(const char *str1
, const char *str2
)
420 if (strlen(str1
) > strlen(str2
))
422 return strncmp(str1
, str2
, strlen(str1
));
425 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
427 if (dl_argc(dl
) == 0)
429 return strcmpx(dl_argv(dl
), pattern
) == 0;
432 static bool dl_no_arg(struct dl
*dl
)
434 return dl_argc(dl
) == 0;
437 static void __pr_out_indent_newline(struct dl
*dl
)
439 if (!g_indent_newline
&& !dl
->json_output
)
443 static bool is_binary_eol(int i
)
448 static void pr_out_binary_value(struct dl
*dl
, uint8_t *data
, uint32_t len
)
454 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
456 pr_out("%02x ", data
[i
]);
458 if (!dl
->json_output
&& is_binary_eol(i
))
461 if (!dl
->json_output
&& !is_binary_eol(i
))
465 static void pr_out_name(struct dl
*dl
, const char *name
)
467 __pr_out_indent_newline(dl
);
469 print_string(PRINT_JSON
, name
, NULL
, NULL
);
474 static void pr_out_u64(struct dl
*dl
, const char *name
, uint64_t val
)
476 __pr_out_indent_newline(dl
);
477 if (val
== (uint64_t) -1)
478 return print_string_name_value(name
, "unlimited");
481 print_u64(PRINT_JSON
, name
, NULL
, val
);
483 pr_out("%s %"PRIu64
, name
, val
);
486 static void pr_out_section_start(struct dl
*dl
, const char *name
)
488 if (dl
->json_output
) {
489 open_json_object(NULL
);
490 open_json_object(name
);
494 static void pr_out_section_end(struct dl
*dl
)
496 if (dl
->json_output
) {
497 if (dl
->arr_last
.present
)
498 close_json_array(PRINT_JSON
, NULL
);
504 static void pr_out_array_start(struct dl
*dl
, const char *name
)
506 if (dl
->json_output
) {
507 open_json_array(PRINT_JSON
, name
);
509 __pr_out_indent_inc();
512 __pr_out_indent_inc();
517 static void pr_out_array_end(struct dl
*dl
)
519 if (dl
->json_output
) {
520 close_json_array(PRINT_JSON
, NULL
);
522 __pr_out_indent_dec();
523 __pr_out_indent_dec();
527 static void pr_out_object_start(struct dl
*dl
, const char *name
)
529 if (dl
->json_output
) {
530 open_json_object(name
);
532 __pr_out_indent_inc();
535 __pr_out_indent_inc();
540 static void pr_out_object_end(struct dl
*dl
)
542 if (dl
->json_output
) {
545 __pr_out_indent_dec();
546 __pr_out_indent_dec();
550 static void pr_out_entry_start(struct dl
*dl
)
553 open_json_object(NULL
);
556 static void pr_out_entry_end(struct dl
*dl
)
564 static void check_indent_newline(struct dl
*dl
)
566 __pr_out_indent_newline(dl
);
568 if (g_indent_newline
&& !is_json_context()) {
569 printf("%s", g_indent_str
);
570 g_indent_newline
= false;
572 g_new_line_count
= 0;
575 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
576 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
577 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
578 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
579 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
580 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
581 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
582 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
583 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
584 [DEVLINK_ATTR_PORT_LANES
] = MNL_TYPE_U32
,
585 [DEVLINK_ATTR_PORT_SPLITTABLE
] = MNL_TYPE_U8
,
586 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
587 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
588 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
589 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
590 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
591 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
592 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
593 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
594 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
595 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
596 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
597 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
598 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
599 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
600 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
601 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
602 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
603 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
604 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
605 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
606 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
607 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
608 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
609 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
610 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
611 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
612 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
613 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
614 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
615 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
616 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
617 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
618 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
619 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
620 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
621 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
622 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
623 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
624 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
625 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
626 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
627 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
628 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
629 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
630 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
631 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
632 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
633 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
634 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
635 [DEVLINK_ATTR_PARAM
] = MNL_TYPE_NESTED
,
636 [DEVLINK_ATTR_PARAM_NAME
] = MNL_TYPE_STRING
,
637 [DEVLINK_ATTR_PARAM_TYPE
] = MNL_TYPE_U8
,
638 [DEVLINK_ATTR_PARAM_VALUES_LIST
] = MNL_TYPE_NESTED
,
639 [DEVLINK_ATTR_PARAM_VALUE
] = MNL_TYPE_NESTED
,
640 [DEVLINK_ATTR_PARAM_VALUE_CMODE
] = MNL_TYPE_U8
,
641 [DEVLINK_ATTR_REGION_NAME
] = MNL_TYPE_STRING
,
642 [DEVLINK_ATTR_REGION_SIZE
] = MNL_TYPE_U64
,
643 [DEVLINK_ATTR_REGION_SNAPSHOTS
] = MNL_TYPE_NESTED
,
644 [DEVLINK_ATTR_REGION_SNAPSHOT
] = MNL_TYPE_NESTED
,
645 [DEVLINK_ATTR_REGION_SNAPSHOT_ID
] = MNL_TYPE_U32
,
646 [DEVLINK_ATTR_REGION_CHUNKS
] = MNL_TYPE_NESTED
,
647 [DEVLINK_ATTR_REGION_CHUNK
] = MNL_TYPE_NESTED
,
648 [DEVLINK_ATTR_REGION_CHUNK_DATA
] = MNL_TYPE_BINARY
,
649 [DEVLINK_ATTR_REGION_CHUNK_ADDR
] = MNL_TYPE_U64
,
650 [DEVLINK_ATTR_REGION_CHUNK_LEN
] = MNL_TYPE_U64
,
651 [DEVLINK_ATTR_INFO_DRIVER_NAME
] = MNL_TYPE_STRING
,
652 [DEVLINK_ATTR_INFO_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
653 [DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
654 [DEVLINK_ATTR_INFO_VERSION_FIXED
] = MNL_TYPE_NESTED
,
655 [DEVLINK_ATTR_INFO_VERSION_RUNNING
] = MNL_TYPE_NESTED
,
656 [DEVLINK_ATTR_INFO_VERSION_STORED
] = MNL_TYPE_NESTED
,
657 [DEVLINK_ATTR_INFO_VERSION_NAME
] = MNL_TYPE_STRING
,
658 [DEVLINK_ATTR_INFO_VERSION_VALUE
] = MNL_TYPE_STRING
,
659 [DEVLINK_ATTR_HEALTH_REPORTER
] = MNL_TYPE_NESTED
,
660 [DEVLINK_ATTR_HEALTH_REPORTER_NAME
] = MNL_TYPE_STRING
,
661 [DEVLINK_ATTR_HEALTH_REPORTER_STATE
] = MNL_TYPE_U8
,
662 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] = MNL_TYPE_U64
,
663 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] = MNL_TYPE_U64
,
664 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
] = MNL_TYPE_U64
,
665 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] = MNL_TYPE_U64
,
666 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
] = MNL_TYPE_STRING
,
667 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
] = MNL_TYPE_STRING
,
668 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
] = MNL_TYPE_U64
,
669 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
] = MNL_TYPE_U64
,
670 [DEVLINK_ATTR_STATS
] = MNL_TYPE_NESTED
,
671 [DEVLINK_ATTR_TRAP_NAME
] = MNL_TYPE_STRING
,
672 [DEVLINK_ATTR_TRAP_ACTION
] = MNL_TYPE_U8
,
673 [DEVLINK_ATTR_TRAP_TYPE
] = MNL_TYPE_U8
,
674 [DEVLINK_ATTR_TRAP_GENERIC
] = MNL_TYPE_FLAG
,
675 [DEVLINK_ATTR_TRAP_METADATA
] = MNL_TYPE_NESTED
,
676 [DEVLINK_ATTR_TRAP_GROUP_NAME
] = MNL_TYPE_STRING
,
677 [DEVLINK_ATTR_RELOAD_FAILED
] = MNL_TYPE_U8
,
678 [DEVLINK_ATTR_TRAP_POLICER_ID
] = MNL_TYPE_U32
,
679 [DEVLINK_ATTR_TRAP_POLICER_RATE
] = MNL_TYPE_U64
,
680 [DEVLINK_ATTR_TRAP_POLICER_BURST
] = MNL_TYPE_U64
,
683 static const enum mnl_attr_data_type
684 devlink_stats_policy
[DEVLINK_ATTR_STATS_MAX
+ 1] = {
685 [DEVLINK_ATTR_STATS_RX_PACKETS
] = MNL_TYPE_U64
,
686 [DEVLINK_ATTR_STATS_RX_BYTES
] = MNL_TYPE_U64
,
687 [DEVLINK_ATTR_STATS_RX_DROPPED
] = MNL_TYPE_U64
,
690 static int attr_cb(const struct nlattr
*attr
, void *data
)
692 const struct nlattr
**tb
= data
;
695 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
698 type
= mnl_attr_get_type(attr
);
699 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
706 static int attr_stats_cb(const struct nlattr
*attr
, void *data
)
708 const struct nlattr
**tb
= data
;
711 /* Allow the tool to work on top of newer kernels that might contain
714 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_STATS_MAX
) < 0)
717 type
= mnl_attr_get_type(attr
);
718 if (mnl_attr_validate(attr
, devlink_stats_policy
[type
]) < 0)
725 static const enum mnl_attr_data_type
726 devlink_function_policy
[DEVLINK_PORT_FUNCTION_ATTR_MAX
+ 1] = {
727 [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
] = MNL_TYPE_BINARY
,
730 static int function_attr_cb(const struct nlattr
*attr
, void *data
)
732 const struct nlattr
**tb
= data
;
735 /* Allow the tool to work on top of newer kernels that might contain
738 if (mnl_attr_type_valid(attr
, DEVLINK_PORT_FUNCTION_ATTR_MAX
) < 0)
741 type
= mnl_attr_get_type(attr
);
742 if (mnl_attr_validate(attr
, devlink_function_policy
[type
]) < 0)
749 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
751 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
752 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
753 struct dl
*dl
= data
;
754 struct ifname_map
*ifname_map
;
755 const char *bus_name
;
756 const char *dev_name
;
757 uint32_t port_ifindex
;
758 const char *port_ifname
;
760 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
761 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
762 !tb
[DEVLINK_ATTR_PORT_INDEX
])
765 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
768 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
769 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
770 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
771 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
772 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
773 port_ifindex
, port_ifname
);
776 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
781 static void ifname_map_fini(struct dl
*dl
)
783 struct ifname_map
*ifname_map
, *tmp
;
785 list_for_each_entry_safe(ifname_map
, tmp
,
786 &dl
->ifname_map_list
, list
) {
787 list_del(&ifname_map
->list
);
788 ifname_map_free(ifname_map
);
792 static int ifname_map_init(struct dl
*dl
)
794 struct nlmsghdr
*nlh
;
797 INIT_LIST_HEAD(&dl
->ifname_map_list
);
799 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
800 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
802 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
810 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
811 char **p_bus_name
, char **p_dev_name
,
812 uint32_t *p_port_index
)
814 struct ifname_map
*ifname_map
;
816 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
817 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
818 *p_bus_name
= ifname_map
->bus_name
;
819 *p_dev_name
= ifname_map
->dev_name
;
820 *p_port_index
= ifname_map
->port_index
;
827 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
828 const char *dev_name
, uint32_t port_index
,
831 struct ifname_map
*ifname_map
;
833 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
834 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
835 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
836 port_index
== ifname_map
->port_index
) {
837 *p_ifname
= ifname_map
->ifname
;
844 static unsigned int strslashcount(char *str
)
846 unsigned int count
= 0;
849 while ((pos
= strchr(pos
, '/'))) {
856 static int strslashrsplit(char *str
, char **before
, char **after
)
860 slash
= strrchr(str
, '/');
869 static int strtouint64_t(const char *str
, uint64_t *p_val
)
872 unsigned long long int val
;
874 val
= strtoull(str
, &endptr
, 10);
875 if (endptr
== str
|| *endptr
!= '\0')
883 static int strtouint32_t(const char *str
, uint32_t *p_val
)
886 unsigned long int val
;
888 val
= strtoul(str
, &endptr
, 10);
889 if (endptr
== str
|| *endptr
!= '\0')
897 static int strtouint16_t(const char *str
, uint16_t *p_val
)
900 unsigned long int val
;
902 val
= strtoul(str
, &endptr
, 10);
903 if (endptr
== str
|| *endptr
!= '\0')
911 static int strtouint8_t(const char *str
, uint8_t *p_val
)
914 unsigned long int val
;
916 val
= strtoul(str
, &endptr
, 10);
917 if (endptr
== str
|| *endptr
!= '\0')
925 static int strtobool(const char *str
, bool *p_val
)
929 if (!strcmp(str
, "true") || !strcmp(str
, "1") ||
930 !strcmp(str
, "enable"))
932 else if (!strcmp(str
, "false") || !strcmp(str
, "0") ||
933 !strcmp(str
, "disable"))
941 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
943 strslashrsplit(str
, p_bus_name
, p_dev_name
);
947 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
949 char *str
= dl_argv_next(dl
);
952 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
955 if (strslashcount(str
) != 1) {
956 pr_err("Wrong devlink identification string format.\n");
957 pr_err("Expected \"bus_name/dev_name\".\n");
960 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
963 static int __dl_argv_handle_port(char *str
,
964 char **p_bus_name
, char **p_dev_name
,
965 uint32_t *p_port_index
)
971 err
= strslashrsplit(str
, &handlestr
, &portstr
);
973 pr_err("Port identification \"%s\" is invalid\n", str
);
976 err
= strtouint32_t(portstr
, p_port_index
);
978 pr_err("Port index \"%s\" is not a number or not within range\n",
982 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
984 pr_err("Port identification \"%s\" is invalid\n", str
);
990 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
991 char **p_bus_name
, char **p_dev_name
,
992 uint32_t *p_port_index
)
996 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
999 pr_err("Netdevice \"%s\" not found\n", str
);
1005 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
1006 char **p_dev_name
, uint32_t *p_port_index
)
1008 char *str
= dl_argv_next(dl
);
1009 unsigned int slash_count
;
1012 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
1015 slash_count
= strslashcount(str
);
1016 switch (slash_count
) {
1018 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
1019 p_dev_name
, p_port_index
);
1021 return __dl_argv_handle_port(str
, p_bus_name
,
1022 p_dev_name
, p_port_index
);
1024 pr_err("Wrong port identification string format.\n");
1025 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1030 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
1031 char **p_dev_name
, uint32_t *p_port_index
,
1032 uint64_t *p_handle_bit
)
1034 char *str
= dl_argv_next(dl
);
1035 unsigned int slash_count
;
1039 pr_err("One of following identifications expected:\n"
1040 "Devlink identification (\"bus_name/dev_name\")\n"
1041 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
1044 slash_count
= strslashcount(str
);
1045 if (slash_count
== 1) {
1046 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
1049 *p_handle_bit
= DL_OPT_HANDLE
;
1050 } else if (slash_count
== 2) {
1051 err
= __dl_argv_handle_port(str
, p_bus_name
,
1052 p_dev_name
, p_port_index
);
1055 *p_handle_bit
= DL_OPT_HANDLEP
;
1056 } else if (slash_count
== 0) {
1057 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
1058 p_dev_name
, p_port_index
);
1061 *p_handle_bit
= DL_OPT_HANDLEP
;
1063 pr_err("Wrong port identification string format.\n");
1064 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1070 static int __dl_argv_handle_region(char *str
, char **p_bus_name
,
1071 char **p_dev_name
, char **p_region
)
1076 err
= strslashrsplit(str
, &handlestr
, p_region
);
1078 pr_err("Region identification \"%s\" is invalid\n", str
);
1081 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
1083 pr_err("Region identification \"%s\" is invalid\n", str
);
1089 static int dl_argv_handle_region(struct dl
*dl
, char **p_bus_name
,
1090 char **p_dev_name
, char **p_region
)
1092 char *str
= dl_argv_next(dl
);
1093 unsigned int slash_count
;
1096 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
1100 slash_count
= strslashcount(str
);
1101 if (slash_count
!= 2) {
1102 pr_err("Wrong region identification string format.\n");
1103 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
1107 return __dl_argv_handle_region(str
, p_bus_name
, p_dev_name
, p_region
);
1110 static int dl_argv_uint64_t(struct dl
*dl
, uint64_t *p_val
)
1112 char *str
= dl_argv_next(dl
);
1116 pr_err("Unsigned number argument expected\n");
1120 err
= strtouint64_t(str
, p_val
);
1122 pr_err("\"%s\" is not a number or not within range\n", str
);
1128 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
1130 char *str
= dl_argv_next(dl
);
1134 pr_err("Unsigned number argument expected\n");
1138 err
= strtouint32_t(str
, p_val
);
1140 pr_err("\"%s\" is not a number or not within range\n", str
);
1146 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
1148 char *str
= dl_argv_next(dl
);
1152 pr_err("Unsigned number argument expected\n");
1156 err
= strtouint16_t(str
, p_val
);
1158 pr_err("\"%s\" is not a number or not within range\n", str
);
1164 static int dl_argv_bool(struct dl
*dl
, bool *p_val
)
1166 char *str
= dl_argv_next(dl
);
1170 pr_err("Boolean argument expected\n");
1174 err
= strtobool(str
, p_val
);
1176 pr_err("\"%s\" is not a valid boolean value\n", str
);
1182 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
1184 const char *str
= dl_argv_next(dl
);
1187 pr_err("String parameter expected\n");
1194 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
1196 if (strcmp(typestr
, "auto") == 0) {
1197 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
1198 } else if (strcmp(typestr
, "eth") == 0) {
1199 *p_type
= DEVLINK_PORT_TYPE_ETH
;
1200 } else if (strcmp(typestr
, "ib") == 0) {
1201 *p_type
= DEVLINK_PORT_TYPE_IB
;
1203 pr_err("Unknown port type \"%s\"\n", typestr
);
1209 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
1211 if (strcmp(typestr
, "ingress") == 0) {
1212 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
1213 } else if (strcmp(typestr
, "egress") == 0) {
1214 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
1216 pr_err("Unknown pool type \"%s\"\n", typestr
);
1222 static int threshold_type_get(const char *typestr
,
1223 enum devlink_sb_threshold_type
*p_type
)
1225 if (strcmp(typestr
, "static") == 0) {
1226 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
1227 } else if (strcmp(typestr
, "dynamic") == 0) {
1228 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
1230 pr_err("Unknown threshold type \"%s\"\n", typestr
);
1236 static int eswitch_mode_get(const char *typestr
,
1237 enum devlink_eswitch_mode
*p_mode
)
1239 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
1240 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
1241 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
1242 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
1244 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
1250 static int eswitch_inline_mode_get(const char *typestr
,
1251 enum devlink_eswitch_inline_mode
*p_mode
)
1253 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
1254 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
1255 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
1256 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
1257 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
1258 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
1259 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
1260 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
1262 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
1269 eswitch_encap_mode_get(const char *typestr
,
1270 enum devlink_eswitch_encap_mode
*p_encap_mode
)
1272 /* The initial implementation incorrectly accepted "enable"/"disable".
1273 * Carry it to maintain backward compatibility.
1275 if (strcmp(typestr
, "disable") == 0 ||
1276 strcmp(typestr
, ESWITCH_ENCAP_MODE_NONE
) == 0) {
1277 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_NONE
;
1278 } else if (strcmp(typestr
, "enable") == 0 ||
1279 strcmp(typestr
, ESWITCH_ENCAP_MODE_BASIC
) == 0) {
1280 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_BASIC
;
1282 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
1288 static int param_cmode_get(const char *cmodestr
,
1289 enum devlink_param_cmode
*cmode
)
1291 if (strcmp(cmodestr
, PARAM_CMODE_RUNTIME_STR
) == 0) {
1292 *cmode
= DEVLINK_PARAM_CMODE_RUNTIME
;
1293 } else if (strcmp(cmodestr
, PARAM_CMODE_DRIVERINIT_STR
) == 0) {
1294 *cmode
= DEVLINK_PARAM_CMODE_DRIVERINIT
;
1295 } else if (strcmp(cmodestr
, PARAM_CMODE_PERMANENT_STR
) == 0) {
1296 *cmode
= DEVLINK_PARAM_CMODE_PERMANENT
;
1298 pr_err("Unknown configuration mode \"%s\"\n", cmodestr
);
1304 static int trap_action_get(const char *actionstr
,
1305 enum devlink_trap_action
*p_action
)
1307 if (strcmp(actionstr
, "drop") == 0) {
1308 *p_action
= DEVLINK_TRAP_ACTION_DROP
;
1309 } else if (strcmp(actionstr
, "trap") == 0) {
1310 *p_action
= DEVLINK_TRAP_ACTION_TRAP
;
1311 } else if (strcmp(actionstr
, "mirror") == 0) {
1312 *p_action
= DEVLINK_TRAP_ACTION_MIRROR
;
1314 pr_err("Unknown trap action \"%s\"\n", actionstr
);
1320 static int hw_addr_parse(const char *addrstr
, char *hw_addr
, uint32_t *len
)
1324 alen
= ll_addr_a2n(hw_addr
, MAX_ADDR_LEN
, addrstr
);
1331 struct dl_args_metadata
{
1333 char err_msg
[DL_ARGS_REQUIRED_MAX_ERR_LEN
];
1336 static const struct dl_args_metadata dl_args_required
[] = {
1337 {DL_OPT_PORT_TYPE
, "Port type not set."},
1338 {DL_OPT_PORT_COUNT
, "Port split count option expected."},
1339 {DL_OPT_SB_POOL
, "Pool index option expected."},
1340 {DL_OPT_SB_SIZE
, "Pool size option expected."},
1341 {DL_OPT_SB_TYPE
, "Pool type option expected."},
1342 {DL_OPT_SB_THTYPE
, "Pool threshold type option expected."},
1343 {DL_OPT_SB_TH
, "Threshold option expected."},
1344 {DL_OPT_SB_TC
, "TC index option expected."},
1345 {DL_OPT_ESWITCH_MODE
, "E-Switch mode option expected."},
1346 {DL_OPT_ESWITCH_INLINE_MODE
, "E-Switch inline-mode option expected."},
1347 {DL_OPT_DPIPE_TABLE_NAME
, "Dpipe table name expected."},
1348 {DL_OPT_DPIPE_TABLE_COUNTERS
, "Dpipe table counter state expected."},
1349 {DL_OPT_ESWITCH_ENCAP_MODE
, "E-Switch encapsulation option expected."},
1350 {DL_OPT_RESOURCE_PATH
, "Resource path expected."},
1351 {DL_OPT_RESOURCE_SIZE
, "Resource size expected."},
1352 {DL_OPT_PARAM_NAME
, "Parameter name expected."},
1353 {DL_OPT_PARAM_VALUE
, "Value to set expected."},
1354 {DL_OPT_PARAM_CMODE
, "Configuration mode expected."},
1355 {DL_OPT_REGION_SNAPSHOT_ID
, "Region snapshot id expected."},
1356 {DL_OPT_REGION_ADDRESS
, "Region address value expected."},
1357 {DL_OPT_REGION_LENGTH
, "Region length value expected."},
1358 {DL_OPT_HEALTH_REPORTER_NAME
, "Reporter's name is expected."},
1359 {DL_OPT_TRAP_NAME
, "Trap's name is expected."},
1360 {DL_OPT_TRAP_GROUP_NAME
, "Trap group's name is expected."},
1361 {DL_OPT_PORT_FUNCTION_HW_ADDR
, "Port function's hardware address is expected."},
1364 static int dl_args_finding_required_validate(uint64_t o_required
,
1370 for (i
= 0; i
< ARRAY_SIZE(dl_args_required
); i
++) {
1371 o_flag
= dl_args_required
[i
].o_flag
;
1372 if ((o_required
& o_flag
) && !(o_found
& o_flag
)) {
1373 pr_err("%s\n", dl_args_required
[i
].err_msg
);
1377 if (o_required
& ~o_found
) {
1378 pr_err("BUG: unknown argument required but not found\n");
1384 static int dl_argv_parse(struct dl
*dl
, uint64_t o_required
,
1385 uint64_t o_optional
)
1387 struct dl_opts
*opts
= &dl
->opts
;
1388 uint64_t o_all
= o_required
| o_optional
;
1389 uint64_t o_found
= 0;
1392 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
1393 uint64_t handle_bit
;
1395 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
1396 &opts
->port_index
, &handle_bit
);
1399 o_required
&= ~(DL_OPT_HANDLE
| DL_OPT_HANDLEP
) | handle_bit
;
1400 o_found
|= handle_bit
;
1401 } else if (o_required
& DL_OPT_HANDLE
) {
1402 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
1405 o_found
|= DL_OPT_HANDLE
;
1406 } else if (o_required
& DL_OPT_HANDLEP
) {
1407 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
1411 o_found
|= DL_OPT_HANDLEP
;
1412 } else if (o_required
& DL_OPT_HANDLE_REGION
) {
1413 err
= dl_argv_handle_region(dl
, &opts
->bus_name
,
1415 &opts
->region_name
);
1418 o_found
|= DL_OPT_HANDLE_REGION
;
1421 while (dl_argc(dl
)) {
1422 if (dl_argv_match(dl
, "type") &&
1423 (o_all
& DL_OPT_PORT_TYPE
)) {
1424 const char *typestr
;
1427 err
= dl_argv_str(dl
, &typestr
);
1430 err
= port_type_get(typestr
, &opts
->port_type
);
1433 o_found
|= DL_OPT_PORT_TYPE
;
1434 } else if (dl_argv_match(dl
, "count") &&
1435 (o_all
& DL_OPT_PORT_COUNT
)) {
1437 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
1440 o_found
|= DL_OPT_PORT_COUNT
;
1441 } else if (dl_argv_match(dl
, "sb") &&
1442 (o_all
& DL_OPT_SB
)) {
1444 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
1447 o_found
|= DL_OPT_SB
;
1448 } else if (dl_argv_match(dl
, "pool") &&
1449 (o_all
& DL_OPT_SB_POOL
)) {
1451 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
1454 o_found
|= DL_OPT_SB_POOL
;
1455 } else if (dl_argv_match(dl
, "size") &&
1456 (o_all
& DL_OPT_SB_SIZE
)) {
1458 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
1461 o_found
|= DL_OPT_SB_SIZE
;
1462 } else if (dl_argv_match(dl
, "type") &&
1463 (o_all
& DL_OPT_SB_TYPE
)) {
1464 const char *typestr
;
1467 err
= dl_argv_str(dl
, &typestr
);
1470 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
1473 o_found
|= DL_OPT_SB_TYPE
;
1474 } else if (dl_argv_match(dl
, "thtype") &&
1475 (o_all
& DL_OPT_SB_THTYPE
)) {
1476 const char *typestr
;
1479 err
= dl_argv_str(dl
, &typestr
);
1482 err
= threshold_type_get(typestr
,
1483 &opts
->sb_pool_thtype
);
1486 o_found
|= DL_OPT_SB_THTYPE
;
1487 } else if (dl_argv_match(dl
, "th") &&
1488 (o_all
& DL_OPT_SB_TH
)) {
1490 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
1493 o_found
|= DL_OPT_SB_TH
;
1494 } else if (dl_argv_match(dl
, "tc") &&
1495 (o_all
& DL_OPT_SB_TC
)) {
1497 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
1500 o_found
|= DL_OPT_SB_TC
;
1501 } else if (dl_argv_match(dl
, "mode") &&
1502 (o_all
& DL_OPT_ESWITCH_MODE
)) {
1503 const char *typestr
;
1506 err
= dl_argv_str(dl
, &typestr
);
1509 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
1512 o_found
|= DL_OPT_ESWITCH_MODE
;
1513 } else if (dl_argv_match(dl
, "inline-mode") &&
1514 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1515 const char *typestr
;
1518 err
= dl_argv_str(dl
, &typestr
);
1521 err
= eswitch_inline_mode_get(
1522 typestr
, &opts
->eswitch_inline_mode
);
1525 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
1526 } else if (dl_argv_match(dl
, "name") &&
1527 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
1529 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
1532 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
1533 } else if ((dl_argv_match(dl
, "counters") ||
1534 dl_argv_match(dl
, "counters_enabled")) &&
1535 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1537 err
= dl_argv_bool(dl
, &opts
->dpipe_counters_enabled
);
1540 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
1541 } else if ((dl_argv_match(dl
, "encap") || /* Original incorrect implementation */
1542 dl_argv_match(dl
, "encap-mode")) &&
1543 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1544 const char *typestr
;
1547 err
= dl_argv_str(dl
, &typestr
);
1550 err
= eswitch_encap_mode_get(typestr
,
1551 &opts
->eswitch_encap_mode
);
1554 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
1555 } else if (dl_argv_match(dl
, "path") &&
1556 (o_all
& DL_OPT_RESOURCE_PATH
)) {
1558 err
= dl_argv_str(dl
, &opts
->resource_path
);
1561 o_found
|= DL_OPT_RESOURCE_PATH
;
1562 } else if (dl_argv_match(dl
, "size") &&
1563 (o_all
& DL_OPT_RESOURCE_SIZE
)) {
1565 err
= dl_argv_uint64_t(dl
, &opts
->resource_size
);
1568 o_found
|= DL_OPT_RESOURCE_SIZE
;
1569 } else if (dl_argv_match(dl
, "name") &&
1570 (o_all
& DL_OPT_PARAM_NAME
)) {
1572 err
= dl_argv_str(dl
, &opts
->param_name
);
1575 o_found
|= DL_OPT_PARAM_NAME
;
1576 } else if (dl_argv_match(dl
, "value") &&
1577 (o_all
& DL_OPT_PARAM_VALUE
)) {
1579 err
= dl_argv_str(dl
, &opts
->param_value
);
1582 o_found
|= DL_OPT_PARAM_VALUE
;
1583 } else if (dl_argv_match(dl
, "cmode") &&
1584 (o_all
& DL_OPT_PARAM_CMODE
)) {
1585 const char *cmodestr
;
1588 err
= dl_argv_str(dl
, &cmodestr
);
1591 err
= param_cmode_get(cmodestr
, &opts
->cmode
);
1594 o_found
|= DL_OPT_PARAM_CMODE
;
1595 } else if (dl_argv_match(dl
, "snapshot") &&
1596 (o_all
& DL_OPT_REGION_SNAPSHOT_ID
)) {
1598 err
= dl_argv_uint32_t(dl
, &opts
->region_snapshot_id
);
1601 o_found
|= DL_OPT_REGION_SNAPSHOT_ID
;
1602 } else if (dl_argv_match(dl
, "address") &&
1603 (o_all
& DL_OPT_REGION_ADDRESS
)) {
1605 err
= dl_argv_uint64_t(dl
, &opts
->region_address
);
1608 o_found
|= DL_OPT_REGION_ADDRESS
;
1609 } else if (dl_argv_match(dl
, "length") &&
1610 (o_all
& DL_OPT_REGION_LENGTH
)) {
1612 err
= dl_argv_uint64_t(dl
, &opts
->region_length
);
1615 o_found
|= DL_OPT_REGION_LENGTH
;
1616 } else if (dl_argv_match(dl
, "file") &&
1617 (o_all
& DL_OPT_FLASH_FILE_NAME
)) {
1619 err
= dl_argv_str(dl
, &opts
->flash_file_name
);
1622 o_found
|= DL_OPT_FLASH_FILE_NAME
;
1623 } else if (dl_argv_match(dl
, "component") &&
1624 (o_all
& DL_OPT_FLASH_COMPONENT
)) {
1626 err
= dl_argv_str(dl
, &opts
->flash_component
);
1629 o_found
|= DL_OPT_FLASH_COMPONENT
;
1630 } else if (dl_argv_match(dl
, "reporter") &&
1631 (o_all
& DL_OPT_HEALTH_REPORTER_NAME
)) {
1633 err
= dl_argv_str(dl
, &opts
->reporter_name
);
1636 o_found
|= DL_OPT_HEALTH_REPORTER_NAME
;
1637 } else if (dl_argv_match(dl
, "grace_period") &&
1638 (o_all
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)) {
1640 err
= dl_argv_uint64_t(dl
,
1641 &opts
->reporter_graceful_period
);
1644 o_found
|= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
;
1645 } else if (dl_argv_match(dl
, "auto_recover") &&
1646 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)) {
1648 err
= dl_argv_bool(dl
, &opts
->reporter_auto_recover
);
1651 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
;
1652 } else if (dl_argv_match(dl
, "auto_dump") &&
1653 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_DUMP
)) {
1655 err
= dl_argv_bool(dl
, &opts
->reporter_auto_dump
);
1658 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_DUMP
;
1659 } else if (dl_argv_match(dl
, "trap") &&
1660 (o_all
& DL_OPT_TRAP_NAME
)) {
1662 err
= dl_argv_str(dl
, &opts
->trap_name
);
1665 o_found
|= DL_OPT_TRAP_NAME
;
1666 } else if (dl_argv_match(dl
, "group") &&
1667 (o_all
& DL_OPT_TRAP_GROUP_NAME
)) {
1669 err
= dl_argv_str(dl
, &opts
->trap_group_name
);
1672 o_found
|= DL_OPT_TRAP_GROUP_NAME
;
1673 } else if (dl_argv_match(dl
, "action") &&
1674 (o_all
& DL_OPT_TRAP_ACTION
)) {
1675 const char *actionstr
;
1678 err
= dl_argv_str(dl
, &actionstr
);
1681 err
= trap_action_get(actionstr
, &opts
->trap_action
);
1684 o_found
|= DL_OPT_TRAP_ACTION
;
1685 } else if (dl_argv_match(dl
, "netns") &&
1686 (o_all
& DL_OPT_NETNS
)) {
1687 const char *netns_str
;
1690 err
= dl_argv_str(dl
, &netns_str
);
1693 opts
->netns
= netns_get_fd(netns_str
);
1694 if ((int)opts
->netns
< 0) {
1696 err
= dl_argv_uint32_t(dl
, &opts
->netns
);
1699 opts
->netns_is_pid
= true;
1701 o_found
|= DL_OPT_NETNS
;
1702 } else if (dl_argv_match(dl
, "policer") &&
1703 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1705 err
= dl_argv_uint32_t(dl
, &opts
->trap_policer_id
);
1708 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1709 } else if (dl_argv_match(dl
, "nopolicer") &&
1710 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1712 opts
->trap_policer_id
= 0;
1713 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1714 } else if (dl_argv_match(dl
, "rate") &&
1715 (o_all
& DL_OPT_TRAP_POLICER_RATE
)) {
1717 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_rate
);
1720 o_found
|= DL_OPT_TRAP_POLICER_RATE
;
1721 } else if (dl_argv_match(dl
, "burst") &&
1722 (o_all
& DL_OPT_TRAP_POLICER_BURST
)) {
1724 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_burst
);
1727 o_found
|= DL_OPT_TRAP_POLICER_BURST
;
1728 } else if (dl_argv_match(dl
, "hw_addr") &&
1729 (o_all
& DL_OPT_PORT_FUNCTION_HW_ADDR
)) {
1730 const char *addrstr
;
1733 err
= dl_argv_str(dl
, &addrstr
);
1736 err
= hw_addr_parse(addrstr
, opts
->port_function_hw_addr
,
1737 &opts
->port_function_hw_addr_len
);
1740 o_found
|= DL_OPT_PORT_FUNCTION_HW_ADDR
;
1743 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
1748 opts
->present
= o_found
;
1750 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
1752 opts
->present
|= DL_OPT_SB
;
1755 return dl_args_finding_required_validate(o_required
, o_found
);
1759 dl_function_attr_put(struct nlmsghdr
*nlh
, const struct dl_opts
*opts
)
1761 struct nlattr
*nest
;
1763 nest
= mnl_attr_nest_start(nlh
, DEVLINK_ATTR_PORT_FUNCTION
);
1764 mnl_attr_put(nlh
, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
,
1765 opts
->port_function_hw_addr_len
,
1766 opts
->port_function_hw_addr
);
1767 mnl_attr_nest_end(nlh
, nest
);
1770 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1772 struct dl_opts
*opts
= &dl
->opts
;
1774 if (opts
->present
& DL_OPT_HANDLE
) {
1775 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1776 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1777 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1778 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1779 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1780 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1782 } else if (opts
->present
& DL_OPT_HANDLE_REGION
) {
1783 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1784 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1785 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_REGION_NAME
,
1788 if (opts
->present
& DL_OPT_PORT_TYPE
)
1789 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1791 if (opts
->present
& DL_OPT_PORT_COUNT
)
1792 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1794 if (opts
->present
& DL_OPT_SB
)
1795 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1797 if (opts
->present
& DL_OPT_SB_POOL
)
1798 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1799 opts
->sb_pool_index
);
1800 if (opts
->present
& DL_OPT_SB_SIZE
)
1801 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1802 opts
->sb_pool_size
);
1803 if (opts
->present
& DL_OPT_SB_TYPE
)
1804 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1805 opts
->sb_pool_type
);
1806 if (opts
->present
& DL_OPT_SB_THTYPE
)
1807 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1808 opts
->sb_pool_thtype
);
1809 if (opts
->present
& DL_OPT_SB_TH
)
1810 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1811 opts
->sb_threshold
);
1812 if (opts
->present
& DL_OPT_SB_TC
)
1813 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1815 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1816 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1817 opts
->eswitch_mode
);
1818 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1819 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1820 opts
->eswitch_inline_mode
);
1821 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1822 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1823 opts
->dpipe_table_name
);
1824 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1825 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1826 opts
->dpipe_counters_enabled
);
1827 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1828 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1829 opts
->eswitch_encap_mode
);
1830 if ((opts
->present
& DL_OPT_RESOURCE_PATH
) && opts
->resource_id_valid
)
1831 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_ID
,
1833 if (opts
->present
& DL_OPT_RESOURCE_SIZE
)
1834 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_SIZE
,
1835 opts
->resource_size
);
1836 if (opts
->present
& DL_OPT_PARAM_NAME
)
1837 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_NAME
,
1839 if (opts
->present
& DL_OPT_PARAM_CMODE
)
1840 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_CMODE
,
1842 if (opts
->present
& DL_OPT_REGION_SNAPSHOT_ID
)
1843 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_REGION_SNAPSHOT_ID
,
1844 opts
->region_snapshot_id
);
1845 if (opts
->present
& DL_OPT_REGION_ADDRESS
)
1846 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_ADDR
,
1847 opts
->region_address
);
1848 if (opts
->present
& DL_OPT_REGION_LENGTH
)
1849 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_LEN
,
1850 opts
->region_length
);
1851 if (opts
->present
& DL_OPT_FLASH_FILE_NAME
)
1852 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME
,
1853 opts
->flash_file_name
);
1854 if (opts
->present
& DL_OPT_FLASH_COMPONENT
)
1855 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
,
1856 opts
->flash_component
);
1857 if (opts
->present
& DL_OPT_HEALTH_REPORTER_NAME
)
1858 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
1859 opts
->reporter_name
);
1860 if (opts
->present
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)
1861 mnl_attr_put_u64(nlh
,
1862 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
,
1863 opts
->reporter_graceful_period
);
1864 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)
1865 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
,
1866 opts
->reporter_auto_recover
);
1867 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_DUMP
)
1868 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
,
1869 opts
->reporter_auto_dump
);
1870 if (opts
->present
& DL_OPT_TRAP_NAME
)
1871 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_NAME
,
1873 if (opts
->present
& DL_OPT_TRAP_GROUP_NAME
)
1874 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_GROUP_NAME
,
1875 opts
->trap_group_name
);
1876 if (opts
->present
& DL_OPT_TRAP_ACTION
)
1877 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_TRAP_ACTION
,
1879 if (opts
->present
& DL_OPT_NETNS
)
1880 mnl_attr_put_u32(nlh
,
1881 opts
->netns_is_pid
? DEVLINK_ATTR_NETNS_PID
:
1882 DEVLINK_ATTR_NETNS_FD
,
1884 if (opts
->present
& DL_OPT_TRAP_POLICER_ID
)
1885 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_TRAP_POLICER_ID
,
1886 opts
->trap_policer_id
);
1887 if (opts
->present
& DL_OPT_TRAP_POLICER_RATE
)
1888 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_RATE
,
1889 opts
->trap_policer_rate
);
1890 if (opts
->present
& DL_OPT_TRAP_POLICER_BURST
)
1891 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_BURST
,
1892 opts
->trap_policer_burst
);
1893 if (opts
->present
& DL_OPT_PORT_FUNCTION_HW_ADDR
)
1894 dl_function_attr_put(nlh
, opts
);
1897 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1898 uint64_t o_required
, uint64_t o_optional
)
1902 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1905 dl_opts_put(nlh
, dl
);
1909 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1911 struct dl_opts
*opts
= &dl
->opts
;
1912 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1913 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1914 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1915 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1917 if (opts
->present
& DL_OPT_HANDLE
&&
1918 attr_bus_name
&& attr_dev_name
) {
1919 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1920 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1922 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1923 strcmp(dev_name
, opts
->dev_name
) != 0)
1926 if (opts
->present
& DL_OPT_HANDLEP
&&
1927 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1928 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1929 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1930 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1932 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1933 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1934 port_index
!= opts
->port_index
)
1937 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1938 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1940 if (sb_index
!= opts
->sb_index
)
1946 static void cmd_dev_help(void)
1948 pr_err("Usage: devlink dev show [ DEV ]\n");
1949 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1950 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1951 pr_err(" [ encap-mode { none | basic } ]\n");
1952 pr_err(" devlink dev eswitch show DEV\n");
1953 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1954 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1955 pr_err(" devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
1956 pr_err(" devlink dev info [ DEV ]\n");
1957 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1960 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1961 const char *dev_name
)
1963 if (!dl
->arr_last
.present
)
1965 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1966 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1969 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1970 const char *dev_name
)
1972 dl
->arr_last
.present
= true;
1973 free(dl
->arr_last
.dev_name
);
1974 free(dl
->arr_last
.bus_name
);
1975 dl
->arr_last
.bus_name
= strdup(bus_name
);
1976 dl
->arr_last
.dev_name
= strdup(dev_name
);
1979 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1980 const char *dev_name
)
1982 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1985 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1986 const char *dev_name
)
1988 return dl
->arr_last
.present
&&
1989 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1992 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1993 bool content
, bool array
)
1995 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1996 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1999 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
2001 if (dl
->json_output
) {
2003 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
2004 close_json_array(PRINT_JSON
, NULL
);
2005 if (should_arr_last_handle_start(dl
, bus_name
,
2007 open_json_array(PRINT_JSON
, buf
);
2008 open_json_object(NULL
);
2009 arr_last_handle_set(dl
, bus_name
, dev_name
);
2011 open_json_object(NULL
);
2014 open_json_object(buf
);
2018 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
2019 __pr_out_indent_dec();
2020 if (should_arr_last_handle_start(dl
, bus_name
,
2022 pr_out("%s%s", buf
, content
? ":" : "");
2024 __pr_out_indent_inc();
2025 arr_last_handle_set(dl
, bus_name
, dev_name
);
2028 pr_out("%s%s", buf
, content
? ":" : "");
2033 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
2035 __pr_out_handle_start(dl
, tb
, true, true);
2038 static void pr_out_handle_end(struct dl
*dl
)
2040 if (dl
->json_output
)
2041 close_json_object();
2046 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
2048 __pr_out_handle_start(dl
, tb
, false, false);
2049 pr_out_handle_end(dl
);
2052 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
2053 const char *dev_name
, uint32_t port_index
)
2055 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
2056 dl
->arr_last
.port_index
== port_index
;
2059 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
2060 const char *dev_name
, uint32_t port_index
)
2062 arr_last_handle_set(dl
, bus_name
, dev_name
);
2063 dl
->arr_last
.port_index
= port_index
;
2066 static bool should_arr_last_port_handle_start(struct dl
*dl
,
2067 const char *bus_name
,
2068 const char *dev_name
,
2069 uint32_t port_index
)
2071 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
2074 static bool should_arr_last_port_handle_end(struct dl
*dl
,
2075 const char *bus_name
,
2076 const char *dev_name
,
2077 uint32_t port_index
)
2079 return dl
->arr_last
.present
&&
2080 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
2083 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
2084 const char *dev_name
,
2085 uint32_t port_index
, bool try_nice
,
2088 static char buf
[64];
2089 char *ifname
= NULL
;
2091 if (dl
->no_nice_names
|| !try_nice
||
2092 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
2093 port_index
, &ifname
) != 0)
2094 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
2096 sprintf(buf
, "%s", ifname
);
2098 if (dl
->json_output
) {
2100 if (should_arr_last_port_handle_end(dl
, bus_name
,
2103 close_json_array(PRINT_JSON
, NULL
);
2104 if (should_arr_last_port_handle_start(dl
, bus_name
,
2107 open_json_array(PRINT_JSON
, buf
);
2108 open_json_object(NULL
);
2109 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
2112 open_json_object(NULL
);
2115 open_json_object(buf
);
2119 if (should_arr_last_port_handle_end(dl
, bus_name
, dev_name
, port_index
))
2120 __pr_out_indent_dec();
2121 if (should_arr_last_port_handle_start(dl
, bus_name
,
2122 dev_name
, port_index
)) {
2125 __pr_out_indent_inc();
2126 arr_last_port_handle_set(dl
, bus_name
, dev_name
, port_index
);
2134 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
2136 const char *bus_name
;
2137 const char *dev_name
;
2138 uint32_t port_index
;
2140 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2141 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2142 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
2143 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
2146 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
2148 const char *bus_name
;
2149 const char *dev_name
;
2150 uint32_t port_index
;
2152 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2153 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2154 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
2155 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
2158 static void pr_out_port_handle_end(struct dl
*dl
)
2160 if (dl
->json_output
)
2161 close_json_object();
2166 static void pr_out_region_chunk_start(struct dl
*dl
, uint64_t addr
)
2168 if (dl
->json_output
) {
2169 print_uint(PRINT_JSON
, "address", NULL
, addr
);
2170 open_json_array(PRINT_JSON
, "data");
2174 static void pr_out_region_chunk_end(struct dl
*dl
)
2176 if (dl
->json_output
)
2177 close_json_array(PRINT_JSON
, NULL
);
2180 static void pr_out_region_chunk(struct dl
*dl
, uint8_t *data
, uint32_t len
,
2183 static uint64_t align_val
;
2186 pr_out_region_chunk_start(dl
, addr
);
2188 if (!dl
->json_output
)
2189 if (!(align_val
% 16))
2190 pr_out("%s%016"PRIx64
" ",
2191 align_val
? "\n" : "",
2196 if (dl
->json_output
)
2197 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
2199 pr_out("%02x ", data
[i
]);
2204 pr_out_region_chunk_end(dl
);
2207 static void pr_out_stats(struct dl
*dl
, struct nlattr
*nla_stats
)
2209 struct nlattr
*tb
[DEVLINK_ATTR_STATS_MAX
+ 1] = {};
2215 err
= mnl_attr_parse_nested(nla_stats
, attr_stats_cb
, tb
);
2216 if (err
!= MNL_CB_OK
)
2219 pr_out_object_start(dl
, "stats");
2220 pr_out_object_start(dl
, "rx");
2221 if (tb
[DEVLINK_ATTR_STATS_RX_BYTES
])
2222 pr_out_u64(dl
, "bytes",
2223 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_BYTES
]));
2224 if (tb
[DEVLINK_ATTR_STATS_RX_PACKETS
])
2225 pr_out_u64(dl
, "packets",
2226 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_PACKETS
]));
2227 if (tb
[DEVLINK_ATTR_STATS_RX_DROPPED
])
2228 pr_out_u64(dl
, "dropped",
2229 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_DROPPED
]));
2230 pr_out_object_end(dl
);
2231 pr_out_object_end(dl
);
2234 static const char *param_cmode_name(uint8_t cmode
)
2237 case DEVLINK_PARAM_CMODE_RUNTIME
:
2238 return PARAM_CMODE_RUNTIME_STR
;
2239 case DEVLINK_PARAM_CMODE_DRIVERINIT
:
2240 return PARAM_CMODE_DRIVERINIT_STR
;
2241 case DEVLINK_PARAM_CMODE_PERMANENT
:
2242 return PARAM_CMODE_PERMANENT_STR
;
2243 default: return "<unknown type>";
2247 static const char *eswitch_mode_name(uint32_t mode
)
2250 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
2251 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
2252 default: return "<unknown mode>";
2256 static const char *eswitch_inline_mode_name(uint32_t mode
)
2259 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
2260 return ESWITCH_INLINE_MODE_NONE
;
2261 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
2262 return ESWITCH_INLINE_MODE_LINK
;
2263 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
2264 return ESWITCH_INLINE_MODE_NETWORK
;
2265 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
2266 return ESWITCH_INLINE_MODE_TRANSPORT
;
2268 return "<unknown mode>";
2272 static const char *eswitch_encap_mode_name(uint32_t mode
)
2275 case DEVLINK_ESWITCH_ENCAP_MODE_NONE
:
2276 return ESWITCH_ENCAP_MODE_NONE
;
2277 case DEVLINK_ESWITCH_ENCAP_MODE_BASIC
:
2278 return ESWITCH_ENCAP_MODE_BASIC
;
2280 return "<unknown mode>";
2284 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
2286 __pr_out_handle_start(dl
, tb
, true, false);
2288 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
]) {
2289 check_indent_newline(dl
);
2290 print_string(PRINT_ANY
, "mode", "mode %s",
2291 eswitch_mode_name(mnl_attr_get_u16(
2292 tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
2294 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
]) {
2295 check_indent_newline(dl
);
2296 print_string(PRINT_ANY
, "inline-mode", "inline-mode %s",
2297 eswitch_inline_mode_name(mnl_attr_get_u8(
2298 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
2300 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
2301 check_indent_newline(dl
);
2302 print_string(PRINT_ANY
, "encap-mode", "encap-mode %s",
2303 eswitch_encap_mode_name(mnl_attr_get_u8(
2304 tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
])));
2307 pr_out_handle_end(dl
);
2310 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2312 struct dl
*dl
= data
;
2313 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2314 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2316 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2317 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2318 return MNL_CB_ERROR
;
2319 pr_out_eswitch(dl
, tb
);
2323 static int cmd_dev_eswitch_show(struct dl
*dl
)
2325 struct nlmsghdr
*nlh
;
2328 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
2329 NLM_F_REQUEST
| NLM_F_ACK
);
2331 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2335 pr_out_section_start(dl
, "dev");
2336 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
2337 pr_out_section_end(dl
);
2341 static int cmd_dev_eswitch_set(struct dl
*dl
)
2343 struct nlmsghdr
*nlh
;
2346 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
2347 NLM_F_REQUEST
| NLM_F_ACK
);
2349 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
2350 DL_OPT_ESWITCH_MODE
|
2351 DL_OPT_ESWITCH_INLINE_MODE
|
2352 DL_OPT_ESWITCH_ENCAP_MODE
);
2357 if (dl
->opts
.present
== 1) {
2358 pr_err("Need to set at least one option\n");
2362 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2365 static int cmd_dev_eswitch(struct dl
*dl
)
2367 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2370 } else if (dl_argv_match(dl
, "set")) {
2372 return cmd_dev_eswitch_set(dl
);
2373 } else if (dl_argv_match(dl
, "show")) {
2375 return cmd_dev_eswitch_show(dl
);
2377 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2381 struct param_val_conv
{
2387 static bool param_val_conv_exists(const struct param_val_conv
*param_val_conv
,
2388 uint32_t len
, const char *name
)
2392 for (i
= 0; i
< len
; i
++)
2393 if (!strcmp(param_val_conv
[i
].name
, name
))
2400 param_val_conv_uint_get(const struct param_val_conv
*param_val_conv
,
2401 uint32_t len
, const char *name
, const char *vstr
,
2406 for (i
= 0; i
< len
; i
++)
2407 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2408 !strcmp(param_val_conv
[i
].vstr
, vstr
)) {
2409 *vuint
= param_val_conv
[i
].vuint
;
2417 param_val_conv_str_get(const struct param_val_conv
*param_val_conv
,
2418 uint32_t len
, const char *name
, uint32_t vuint
,
2423 for (i
= 0; i
< len
; i
++)
2424 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2425 param_val_conv
[i
].vuint
== vuint
) {
2426 *vstr
= param_val_conv
[i
].vstr
;
2433 static const struct param_val_conv param_val_conv
[] = {
2435 .name
= "fw_load_policy",
2437 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER
,
2440 .name
= "fw_load_policy",
2442 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH
,
2445 .name
= "fw_load_policy",
2447 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK
,
2450 .name
= "reset_dev_on_drv_probe",
2452 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN
,
2455 .name
= "fw_load_policy",
2457 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN
,
2460 .name
= "reset_dev_on_drv_probe",
2462 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS
,
2465 .name
= "reset_dev_on_drv_probe",
2467 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER
,
2470 .name
= "reset_dev_on_drv_probe",
2472 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK
,
2476 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2478 static void pr_out_param_value(struct dl
*dl
, const char *nla_name
,
2479 int nla_type
, struct nlattr
*nl
)
2481 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2482 struct nlattr
*val_attr
;
2487 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_value
);
2488 if (err
!= MNL_CB_OK
)
2491 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2492 (nla_type
!= MNL_TYPE_FLAG
&&
2493 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2496 check_indent_newline(dl
);
2497 print_string(PRINT_ANY
, "cmode", "cmode %s",
2498 param_cmode_name(mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
])));
2500 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2502 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2508 err
= param_val_conv_str_get(param_val_conv
,
2511 mnl_attr_get_u8(val_attr
),
2515 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2517 print_uint(PRINT_ANY
, "value", " value %u",
2518 mnl_attr_get_u8(val_attr
));
2523 err
= param_val_conv_str_get(param_val_conv
,
2526 mnl_attr_get_u16(val_attr
),
2530 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2532 print_uint(PRINT_ANY
, "value", " value %u",
2533 mnl_attr_get_u16(val_attr
));
2538 err
= param_val_conv_str_get(param_val_conv
,
2541 mnl_attr_get_u32(val_attr
),
2545 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2547 print_uint(PRINT_ANY
, "value", " value %u",
2548 mnl_attr_get_u32(val_attr
));
2551 case MNL_TYPE_STRING
:
2552 print_string(PRINT_ANY
, "value", " value %s",
2553 mnl_attr_get_str(val_attr
));
2556 print_bool(PRINT_ANY
, "value", " value %s", val_attr
);
2561 static void pr_out_param(struct dl
*dl
, struct nlattr
**tb
, bool array
)
2563 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2564 struct nlattr
*param_value_attr
;
2565 const char *nla_name
;
2569 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2570 if (err
!= MNL_CB_OK
)
2572 if (!nla_param
[DEVLINK_ATTR_PARAM_NAME
] ||
2573 !nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2574 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2578 pr_out_handle_start_arr(dl
, tb
);
2580 __pr_out_handle_start(dl
, tb
, true, false);
2582 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2584 nla_name
= mnl_attr_get_str(nla_param
[DEVLINK_ATTR_PARAM_NAME
]);
2585 check_indent_newline(dl
);
2586 print_string(PRINT_ANY
, "name", "name %s ", nla_name
);
2587 if (!nla_param
[DEVLINK_ATTR_PARAM_GENERIC
])
2588 print_string(PRINT_ANY
, "type", "type %s", "driver-specific");
2590 print_string(PRINT_ANY
, "type", "type %s", "generic");
2592 pr_out_array_start(dl
, "values");
2593 mnl_attr_for_each_nested(param_value_attr
,
2594 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2595 pr_out_entry_start(dl
);
2596 pr_out_param_value(dl
, nla_name
, nla_type
, param_value_attr
);
2597 pr_out_entry_end(dl
);
2599 pr_out_array_end(dl
);
2600 pr_out_handle_end(dl
);
2603 static int cmd_dev_param_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2605 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2606 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2607 struct dl
*dl
= data
;
2609 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2610 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2611 !tb
[DEVLINK_ATTR_PARAM
])
2612 return MNL_CB_ERROR
;
2613 pr_out_param(dl
, tb
, true);
2629 static int cmd_dev_param_set_cb(const struct nlmsghdr
*nlh
, void *data
)
2631 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2632 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2633 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2634 struct nlattr
*param_value_attr
;
2635 enum devlink_param_cmode cmode
;
2636 struct param_ctx
*ctx
= data
;
2637 struct dl
*dl
= ctx
->dl
;
2641 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2642 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2643 !tb
[DEVLINK_ATTR_PARAM
])
2644 return MNL_CB_ERROR
;
2646 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2647 if (err
!= MNL_CB_OK
)
2648 return MNL_CB_ERROR
;
2650 if (!nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2651 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2652 return MNL_CB_ERROR
;
2654 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2655 mnl_attr_for_each_nested(param_value_attr
,
2656 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2657 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2658 struct nlattr
*val_attr
;
2660 err
= mnl_attr_parse_nested(param_value_attr
,
2661 attr_cb
, nla_value
);
2662 if (err
!= MNL_CB_OK
)
2663 return MNL_CB_ERROR
;
2665 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2666 (nla_type
!= MNL_TYPE_FLAG
&&
2667 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2668 return MNL_CB_ERROR
;
2670 cmode
= mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
]);
2671 if (cmode
== dl
->opts
.cmode
) {
2672 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2675 ctx
->value
.vu8
= mnl_attr_get_u8(val_attr
);
2678 ctx
->value
.vu16
= mnl_attr_get_u16(val_attr
);
2681 ctx
->value
.vu32
= mnl_attr_get_u32(val_attr
);
2683 case MNL_TYPE_STRING
:
2684 ctx
->value
.vstr
= mnl_attr_get_str(val_attr
);
2687 ctx
->value
.vbool
= val_attr
? true : false;
2693 ctx
->nla_type
= nla_type
;
2697 static int cmd_dev_param_set(struct dl
*dl
)
2699 struct param_ctx ctx
= {};
2700 struct nlmsghdr
*nlh
;
2708 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
|
2710 DL_OPT_PARAM_VALUE
|
2711 DL_OPT_PARAM_CMODE
, 0);
2715 /* Get value type */
2716 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
,
2717 NLM_F_REQUEST
| NLM_F_ACK
);
2718 dl_opts_put(nlh
, dl
);
2721 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_set_cb
, &ctx
);
2725 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_SET
,
2726 NLM_F_REQUEST
| NLM_F_ACK
);
2727 dl_opts_put(nlh
, dl
);
2729 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2730 dl
->opts
.param_name
);
2732 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_TYPE
, ctx
.nla_type
);
2733 switch (ctx
.nla_type
) {
2736 err
= param_val_conv_uint_get(param_val_conv
,
2738 dl
->opts
.param_name
,
2739 dl
->opts
.param_value
,
2743 err
= strtouint8_t(dl
->opts
.param_value
, &val_u8
);
2746 goto err_param_value_parse
;
2747 if (val_u8
== ctx
.value
.vu8
)
2749 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u8
);
2753 err
= param_val_conv_uint_get(param_val_conv
,
2755 dl
->opts
.param_name
,
2756 dl
->opts
.param_value
,
2760 err
= strtouint16_t(dl
->opts
.param_value
, &val_u16
);
2763 goto err_param_value_parse
;
2764 if (val_u16
== ctx
.value
.vu16
)
2766 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u16
);
2770 err
= param_val_conv_uint_get(param_val_conv
,
2772 dl
->opts
.param_name
,
2773 dl
->opts
.param_value
,
2776 err
= strtouint32_t(dl
->opts
.param_value
, &val_u32
);
2778 goto err_param_value_parse
;
2779 if (val_u32
== ctx
.value
.vu32
)
2781 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u32
);
2784 err
= strtobool(dl
->opts
.param_value
, &val_bool
);
2786 goto err_param_value_parse
;
2787 if (val_bool
== ctx
.value
.vbool
)
2790 mnl_attr_put(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2793 case MNL_TYPE_STRING
:
2794 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2795 dl
->opts
.param_value
);
2796 if (!strcmp(dl
->opts
.param_value
, ctx
.value
.vstr
))
2800 printf("Value type not supported\n");
2803 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2805 err_param_value_parse
:
2806 pr_err("Value \"%s\" is not a number or not within range\n",
2807 dl
->opts
.param_value
);
2811 static int cmd_dev_param_show(struct dl
*dl
)
2813 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2814 struct nlmsghdr
*nlh
;
2817 if (dl_argc(dl
) == 0)
2818 flags
|= NLM_F_DUMP
;
2820 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
, flags
);
2822 if (dl_argc(dl
) > 0) {
2823 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
|
2824 DL_OPT_PARAM_NAME
, 0);
2829 pr_out_section_start(dl
, "param");
2830 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_show_cb
, dl
);
2831 pr_out_section_end(dl
);
2835 static int cmd_dev_param(struct dl
*dl
)
2837 if (dl_argv_match(dl
, "help")) {
2840 } else if (dl_argv_match(dl
, "show") ||
2841 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2843 return cmd_dev_param_show(dl
);
2844 } else if (dl_argv_match(dl
, "set")) {
2846 return cmd_dev_param_set(dl
);
2848 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2851 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2853 struct dl
*dl
= data
;
2854 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2855 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2856 uint8_t reload_failed
= 0;
2858 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2859 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2860 return MNL_CB_ERROR
;
2862 if (tb
[DEVLINK_ATTR_RELOAD_FAILED
])
2863 reload_failed
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_RELOAD_FAILED
]);
2865 if (reload_failed
) {
2866 __pr_out_handle_start(dl
, tb
, true, false);
2867 check_indent_newline(dl
);
2868 print_bool(PRINT_ANY
, "reload_failed", "reload_failed %s", true);
2869 pr_out_handle_end(dl
);
2871 pr_out_handle(dl
, tb
);
2877 static int cmd_dev_show(struct dl
*dl
)
2879 struct nlmsghdr
*nlh
;
2880 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2883 if (dl_argc(dl
) == 0)
2884 flags
|= NLM_F_DUMP
;
2886 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
2888 if (dl_argc(dl
) > 0) {
2889 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2894 pr_out_section_start(dl
, "dev");
2895 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
2896 pr_out_section_end(dl
);
2900 static int cmd_dev_reload(struct dl
*dl
)
2902 struct nlmsghdr
*nlh
;
2905 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2910 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RELOAD
,
2911 NLM_F_REQUEST
| NLM_F_ACK
);
2913 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_NETNS
);
2917 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2920 static void pr_out_versions_single(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2921 const char *name
, int type
)
2923 struct nlattr
*version
;
2925 mnl_attr_for_each(version
, nlh
, sizeof(struct genlmsghdr
)) {
2926 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2927 const char *ver_value
;
2928 const char *ver_name
;
2931 if (mnl_attr_get_type(version
) != type
)
2934 err
= mnl_attr_parse_nested(version
, attr_cb
, tb
);
2935 if (err
!= MNL_CB_OK
)
2938 if (!tb
[DEVLINK_ATTR_INFO_VERSION_NAME
] ||
2939 !tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
])
2943 pr_out_object_start(dl
, name
);
2947 ver_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_NAME
]);
2948 ver_value
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
]);
2950 check_indent_newline(dl
);
2951 print_string_name_value(ver_name
, ver_value
);
2952 if (!dl
->json_output
)
2957 pr_out_object_end(dl
);
2960 static void pr_out_info(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2961 struct nlattr
**tb
, bool has_versions
)
2963 __pr_out_handle_start(dl
, tb
, true, false);
2965 __pr_out_indent_inc();
2966 if (tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
]) {
2967 struct nlattr
*nla_drv
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
];
2969 if (!dl
->json_output
)
2971 check_indent_newline(dl
);
2972 print_string(PRINT_ANY
, "driver", "driver %s",
2973 mnl_attr_get_str(nla_drv
));
2976 if (tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
]) {
2977 struct nlattr
*nla_sn
= tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
];
2979 if (!dl
->json_output
)
2981 check_indent_newline(dl
);
2982 print_string(PRINT_ANY
, "serial_number", "serial_number %s",
2983 mnl_attr_get_str(nla_sn
));
2986 if (tb
[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER
]) {
2987 struct nlattr
*nla_bsn
= tb
[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER
];
2989 if (!dl
->json_output
)
2991 check_indent_newline(dl
);
2992 print_string(PRINT_ANY
, "board.serial_number", "board.serial_number %s",
2993 mnl_attr_get_str(nla_bsn
));
2995 __pr_out_indent_dec();
2998 pr_out_object_start(dl
, "versions");
3000 pr_out_versions_single(dl
, nlh
, "fixed",
3001 DEVLINK_ATTR_INFO_VERSION_FIXED
);
3002 pr_out_versions_single(dl
, nlh
, "running",
3003 DEVLINK_ATTR_INFO_VERSION_RUNNING
);
3004 pr_out_versions_single(dl
, nlh
, "stored",
3005 DEVLINK_ATTR_INFO_VERSION_STORED
);
3007 pr_out_object_end(dl
);
3010 pr_out_handle_end(dl
);
3013 static int cmd_versions_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3015 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3016 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3017 bool has_versions
, has_info
;
3018 struct dl
*dl
= data
;
3020 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3022 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
3023 return MNL_CB_ERROR
;
3025 has_versions
= tb
[DEVLINK_ATTR_INFO_VERSION_FIXED
] ||
3026 tb
[DEVLINK_ATTR_INFO_VERSION_RUNNING
] ||
3027 tb
[DEVLINK_ATTR_INFO_VERSION_STORED
];
3028 has_info
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
] ||
3029 tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
] ||
3030 tb
[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER
] ||
3034 pr_out_info(dl
, nlh
, tb
, has_versions
);
3039 static int cmd_dev_info(struct dl
*dl
)
3041 struct nlmsghdr
*nlh
;
3042 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3045 if (dl_argv_match(dl
, "help")) {
3050 if (dl_argc(dl
) == 0)
3051 flags
|= NLM_F_DUMP
;
3053 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_INFO_GET
, flags
);
3055 if (dl_argc(dl
) > 0) {
3056 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
3061 pr_out_section_start(dl
, "info");
3062 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_versions_show_cb
, dl
);
3063 pr_out_section_end(dl
);
3067 struct cmd_dev_flash_status_ctx
{
3070 char *last_component
;
3071 uint8_t not_first
:1,
3077 static int nullstrcmp(const char *str1
, const char *str2
)
3080 return strcmp(str1
, str2
);
3083 return str1
? 1 : -1;
3086 static int cmd_dev_flash_status_cb(const struct nlmsghdr
*nlh
, void *data
)
3088 struct cmd_dev_flash_status_ctx
*ctx
= data
;
3089 struct dl_opts
*opts
= &ctx
->dl
->opts
;
3090 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3091 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3092 const char *component
= NULL
;
3093 uint64_t done
= 0, total
= 0;
3094 const char *msg
= NULL
;
3095 const char *bus_name
;
3096 const char *dev_name
;
3098 if (genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_STATUS
&&
3099 genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_END
)
3102 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3103 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
3104 return MNL_CB_ERROR
;
3105 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
3106 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
3107 if (strcmp(bus_name
, opts
->bus_name
) ||
3108 strcmp(dev_name
, opts
->dev_name
))
3109 return MNL_CB_ERROR
;
3111 if (genl
->cmd
== DEVLINK_CMD_FLASH_UPDATE_END
&& ctx
->not_first
) {
3113 free(ctx
->last_msg
);
3114 free(ctx
->last_component
);
3115 ctx
->received_end
= 1;
3119 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
])
3120 msg
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]);
3121 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
])
3122 component
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]);
3123 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
3124 done
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]);
3125 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
3126 total
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]);
3128 if (!nullstrcmp(msg
, ctx
->last_msg
) &&
3129 !nullstrcmp(component
, ctx
->last_component
) &&
3130 ctx
->last_pc
&& ctx
->not_first
) {
3131 pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3136 pr_out("[%s] ", component
);
3137 free(ctx
->last_component
);
3138 ctx
->last_component
= strdup(component
);
3142 free(ctx
->last_msg
);
3143 ctx
->last_msg
= strdup(msg
);
3147 pr_out_tty(" %3lu%%", (done
* 100) / total
);
3158 static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx
*ctx
,
3159 struct mnlg_socket
*nlg_ntf
,
3162 int nlfd
= mnlg_socket_get_fd(nlg_ntf
);
3169 for (i
= 0; i
< 3; i
++)
3171 FD_SET(pipe_r
, &fds
[0]);
3173 FD_SET(nlfd
, &fds
[0]);
3177 while (select(fdmax
, &fds
[0], &fds
[1], &fds
[2], NULL
) < 0) {
3180 pr_err("select() failed\n");
3183 if (FD_ISSET(nlfd
, &fds
[0])) {
3184 err
= _mnlg_socket_recv_run(nlg_ntf
,
3185 cmd_dev_flash_status_cb
, ctx
);
3189 if (FD_ISSET(pipe_r
, &fds
[0])) {
3190 err
= read(pipe_r
, &err2
, sizeof(err2
));
3192 pr_err("Failed to read pipe\n");
3197 ctx
->flash_done
= 1;
3203 static int cmd_dev_flash(struct dl
*dl
)
3205 struct cmd_dev_flash_status_ctx ctx
= {.dl
= dl
,};
3206 struct mnlg_socket
*nlg_ntf
;
3207 struct nlmsghdr
*nlh
;
3213 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3218 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_FLASH_UPDATE
,
3219 NLM_F_REQUEST
| NLM_F_ACK
);
3221 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_FLASH_FILE_NAME
,
3222 DL_OPT_FLASH_COMPONENT
);
3226 nlg_ntf
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
3230 err
= _mnlg_socket_group_add(nlg_ntf
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
3234 err
= pipe(pipe_fds
);
3237 pipe_r
= pipe_fds
[0];
3238 pipe_w
= pipe_fds
[1];
3246 /* In child, just execute the flash and pass returned
3247 * value through pipe once it is done.
3252 err
= _mnlg_socket_send(dl
->nlg
, nlh
);
3253 cc
= write(pipe_w
, &err
, sizeof(err
));
3255 exit(cc
!= sizeof(err
));
3260 err
= cmd_dev_flash_fds_process(&ctx
, nlg_ntf
, pipe_r
);
3263 } while (!ctx
.flash_done
|| (ctx
.not_first
&& !ctx
.received_end
));
3265 err
= _mnlg_socket_recv_run(dl
->nlg
, NULL
, NULL
);
3268 mnlg_socket_close(nlg_ntf
);
3272 static int cmd_dev(struct dl
*dl
)
3274 if (dl_argv_match(dl
, "help")) {
3277 } else if (dl_argv_match(dl
, "show") ||
3278 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3280 return cmd_dev_show(dl
);
3281 } else if (dl_argv_match(dl
, "eswitch")) {
3283 return cmd_dev_eswitch(dl
);
3284 } else if (dl_argv_match(dl
, "reload")) {
3286 return cmd_dev_reload(dl
);
3287 } else if (dl_argv_match(dl
, "param")) {
3289 return cmd_dev_param(dl
);
3290 } else if (dl_argv_match(dl
, "info")) {
3292 return cmd_dev_info(dl
);
3293 } else if (dl_argv_match(dl
, "flash")) {
3295 return cmd_dev_flash(dl
);
3297 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3301 static void cmd_port_help(void)
3303 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3304 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3305 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3306 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3307 pr_err(" devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3308 pr_err(" devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
3311 static const char *port_type_name(uint32_t type
)
3314 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
3315 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
3316 case DEVLINK_PORT_TYPE_ETH
: return "eth";
3317 case DEVLINK_PORT_TYPE_IB
: return "ib";
3318 default: return "<unknown type>";
3322 static const char *port_flavour_name(uint16_t flavour
)
3325 case DEVLINK_PORT_FLAVOUR_PHYSICAL
:
3327 case DEVLINK_PORT_FLAVOUR_CPU
:
3329 case DEVLINK_PORT_FLAVOUR_DSA
:
3331 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3333 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3335 case DEVLINK_PORT_FLAVOUR_VIRTUAL
:
3338 return "<unknown flavour>";
3342 static void pr_out_port_pfvf_num(struct dl
*dl
, struct nlattr
**tb
)
3346 if (tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]) {
3347 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]);
3348 print_uint(PRINT_ANY
, "pfnum", " pfnum %u", fn_num
);
3350 if (tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]) {
3351 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]);
3352 print_uint(PRINT_ANY
, "vfnum", " vfnum %u", fn_num
);
3356 static void pr_out_port_function(struct dl
*dl
, struct nlattr
**tb_port
)
3358 struct nlattr
*tb
[DEVLINK_PORT_FUNCTION_ATTR_MAX
+ 1] = {};
3359 unsigned char *data
;
3360 SPRINT_BUF(hw_addr
);
3364 if (!tb_port
[DEVLINK_ATTR_PORT_FUNCTION
])
3367 err
= mnl_attr_parse_nested(tb_port
[DEVLINK_ATTR_PORT_FUNCTION
],
3368 function_attr_cb
, tb
);
3369 if (err
!= MNL_CB_OK
)
3372 if (!tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
])
3375 len
= mnl_attr_get_payload_len(tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
]);
3376 data
= mnl_attr_get_payload(tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
]);
3378 pr_out_object_start(dl
, "function");
3379 check_indent_newline(dl
);
3380 print_string(PRINT_ANY
, "hw_addr", "hw_addr %s",
3381 ll_addr_n2a(data
, len
, 0, hw_addr
, sizeof(hw_addr
)));
3382 if (!dl
->json_output
)
3383 __pr_out_indent_dec();
3384 pr_out_object_end(dl
);
3387 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
3389 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
3390 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
3392 pr_out_port_handle_start(dl
, tb
, false);
3393 check_indent_newline(dl
);
3395 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
3397 print_string(PRINT_ANY
, "type", "type %s",
3398 port_type_name(port_type
));
3400 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
3402 if (port_type
!= des_port_type
)
3403 print_string(PRINT_ANY
, "des_type", " des_type %s",
3404 port_type_name(des_port_type
));
3407 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]) {
3408 print_string(PRINT_ANY
, "netdev", " netdev %s",
3409 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
3411 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]) {
3412 print_string(PRINT_ANY
, "ibdev", " ibdev %s",
3413 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
3415 if (tb
[DEVLINK_ATTR_PORT_FLAVOUR
]) {
3416 uint16_t port_flavour
=
3417 mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_FLAVOUR
]);
3419 print_string(PRINT_ANY
, "flavour", " flavour %s",
3420 port_flavour_name(port_flavour
));
3422 switch (port_flavour
) {
3423 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3424 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3425 pr_out_port_pfvf_num(dl
, tb
);
3431 if (tb
[DEVLINK_ATTR_PORT_NUMBER
]) {
3432 uint32_t port_number
;
3434 port_number
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_NUMBER
]);
3435 print_uint(PRINT_ANY
, "port", " port %u", port_number
);
3437 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
3438 print_uint(PRINT_ANY
, "split_group", " split_group %u",
3439 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
3440 if (tb
[DEVLINK_ATTR_PORT_SPLITTABLE
])
3441 print_bool(PRINT_ANY
, "splittable", " splittable %s",
3442 mnl_attr_get_u8(tb
[DEVLINK_ATTR_PORT_SPLITTABLE
]));
3443 if (tb
[DEVLINK_ATTR_PORT_LANES
])
3444 print_uint(PRINT_ANY
, "lanes", " lanes %u",
3445 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_LANES
]));
3447 pr_out_port_function(dl
, tb
);
3448 pr_out_port_handle_end(dl
);
3451 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3453 struct dl
*dl
= data
;
3454 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3455 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3457 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3458 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3459 !tb
[DEVLINK_ATTR_PORT_INDEX
])
3460 return MNL_CB_ERROR
;
3461 pr_out_port(dl
, tb
);
3465 static int cmd_port_show(struct dl
*dl
)
3467 struct nlmsghdr
*nlh
;
3468 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3471 if (dl_argc(dl
) == 0)
3472 flags
|= NLM_F_DUMP
;
3474 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
3476 if (dl_argc(dl
) > 0) {
3477 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3482 pr_out_section_start(dl
, "port");
3483 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
3484 pr_out_section_end(dl
);
3488 static int cmd_port_set(struct dl
*dl
)
3490 struct nlmsghdr
*nlh
;
3493 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
3494 NLM_F_REQUEST
| NLM_F_ACK
);
3496 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
3500 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3503 static int cmd_port_split(struct dl
*dl
)
3505 struct nlmsghdr
*nlh
;
3508 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
3509 NLM_F_REQUEST
| NLM_F_ACK
);
3511 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
3515 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3518 static int cmd_port_unsplit(struct dl
*dl
)
3520 struct nlmsghdr
*nlh
;
3523 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
3524 NLM_F_REQUEST
| NLM_F_ACK
);
3526 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3530 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3533 static void cmd_port_function_help(void)
3535 pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3538 static int cmd_port_function_set(struct dl
*dl
)
3540 struct nlmsghdr
*nlh
;
3543 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
, NLM_F_REQUEST
| NLM_F_ACK
);
3545 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_FUNCTION_HW_ADDR
, 0);
3549 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3552 static int cmd_port_function(struct dl
*dl
)
3554 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3555 cmd_port_function_help();
3557 } else if (dl_argv_match(dl
, "set")) {
3559 return cmd_port_function_set(dl
);
3561 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3565 static int cmd_health(struct dl
*dl
);
3566 static int __cmd_health_show(struct dl
*dl
, bool show_device
, bool show_port
);
3568 static int cmd_port(struct dl
*dl
)
3570 if (dl_argv_match(dl
, "help")) {
3573 } else if (dl_argv_match(dl
, "show") ||
3574 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3576 return cmd_port_show(dl
);
3577 } else if (dl_argv_match(dl
, "set")) {
3579 return cmd_port_set(dl
);
3580 } else if (dl_argv_match(dl
, "split")) {
3582 return cmd_port_split(dl
);
3583 } else if (dl_argv_match(dl
, "unsplit")) {
3585 return cmd_port_unsplit(dl
);
3586 } else if (dl_argv_match(dl
, "function")) {
3588 return cmd_port_function(dl
);
3589 } else if (dl_argv_match(dl
, "health")) {
3591 if (dl_argv_match(dl
, "list") || dl_no_arg(dl
)
3592 || (dl_argv_match(dl
, "show") && dl_argc(dl
) == 1)) {
3594 return __cmd_health_show(dl
, false, true);
3596 return cmd_health(dl
);
3599 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3603 static void cmd_sb_help(void)
3605 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
3606 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
3607 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
3608 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
3609 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3610 pr_err(" pool POOL_INDEX ]\n");
3611 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3612 pr_err(" pool POOL_INDEX th THRESHOLD\n");
3613 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3614 pr_err(" type { ingress | egress } ]\n");
3615 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3616 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
3617 pr_err(" th THRESHOLD\n");
3618 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
3619 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
3620 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
3623 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
3625 pr_out_handle_start_arr(dl
, tb
);
3626 check_indent_newline(dl
);
3627 print_uint(PRINT_ANY
, "sb", "sb %u",
3628 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3629 print_uint(PRINT_ANY
, "size", " size %u",
3630 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
3631 print_uint(PRINT_ANY
, "ing_pools", " ing_pools %u",
3632 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
3633 print_uint(PRINT_ANY
, "eg_pools", " eg_pools %u",
3634 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
3635 print_uint(PRINT_ANY
, "ing_tcs", " ing_tcs %u",
3636 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
3637 print_uint(PRINT_ANY
, "eg_tcs", " eg_tcs %u",
3638 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
3639 pr_out_handle_end(dl
);
3642 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3644 struct dl
*dl
= data
;
3645 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3646 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3648 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3649 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3650 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
3651 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
3652 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
3653 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
3654 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
3655 return MNL_CB_ERROR
;
3660 static int cmd_sb_show(struct dl
*dl
)
3662 struct nlmsghdr
*nlh
;
3663 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3666 if (dl_argc(dl
) == 0)
3667 flags
|= NLM_F_DUMP
;
3669 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
3671 if (dl_argc(dl
) > 0) {
3672 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3677 pr_out_section_start(dl
, "sb");
3678 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
3679 pr_out_section_end(dl
);
3683 static const char *pool_type_name(uint8_t type
)
3686 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
3687 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
3688 default: return "<unknown type>";
3692 static const char *threshold_type_name(uint8_t type
)
3695 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
3696 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
3697 default: return "<unknown type>";
3701 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
3703 pr_out_handle_start_arr(dl
, tb
);
3704 check_indent_newline(dl
);
3705 print_uint(PRINT_ANY
, "sb", "sb %u",
3706 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3707 print_uint(PRINT_ANY
, "pool", " pool %u",
3708 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3709 print_string(PRINT_ANY
, "type", " type %s",
3710 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3711 print_uint(PRINT_ANY
, "size", " size %u",
3712 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
3713 print_string(PRINT_ANY
, "thtype", " thtype %s",
3714 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
3715 if (tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
])
3716 print_uint(PRINT_ANY
, "cell_size", " cell size %u",
3717 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
]));
3718 pr_out_handle_end(dl
);
3721 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3723 struct dl
*dl
= data
;
3724 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3725 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3727 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3728 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3729 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3730 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
3731 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
3732 return MNL_CB_ERROR
;
3733 pr_out_sb_pool(dl
, tb
);
3737 static int cmd_sb_pool_show(struct dl
*dl
)
3739 struct nlmsghdr
*nlh
;
3740 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3743 if (dl_argc(dl
) == 0)
3744 flags
|= NLM_F_DUMP
;
3746 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
3748 if (dl_argc(dl
) > 0) {
3749 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
3755 pr_out_section_start(dl
, "pool");
3756 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
3757 pr_out_section_end(dl
);
3761 static int cmd_sb_pool_set(struct dl
*dl
)
3763 struct nlmsghdr
*nlh
;
3766 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
3767 NLM_F_REQUEST
| NLM_F_ACK
);
3769 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
3770 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
3774 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3777 static int cmd_sb_pool(struct dl
*dl
)
3779 if (dl_argv_match(dl
, "help")) {
3782 } else if (dl_argv_match(dl
, "show") ||
3783 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3785 return cmd_sb_pool_show(dl
);
3786 } else if (dl_argv_match(dl
, "set")) {
3788 return cmd_sb_pool_set(dl
);
3790 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3794 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
3796 pr_out_port_handle_start_arr(dl
, tb
, true);
3797 check_indent_newline(dl
);
3798 print_uint(PRINT_ANY
, "sb", "sb %u",
3799 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3800 print_uint(PRINT_ANY
, "pool", " pool %u",
3801 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3802 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3803 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3804 pr_out_port_handle_end(dl
);
3807 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3809 struct dl
*dl
= data
;
3810 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3811 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3813 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3814 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3815 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3816 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3817 return MNL_CB_ERROR
;
3818 pr_out_sb_port_pool(dl
, tb
);
3822 static int cmd_sb_port_pool_show(struct dl
*dl
)
3824 struct nlmsghdr
*nlh
;
3825 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3828 if (dl_argc(dl
) == 0)
3829 flags
|= NLM_F_DUMP
;
3831 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3833 if (dl_argc(dl
) > 0) {
3834 err
= dl_argv_parse_put(nlh
, dl
,
3835 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
3841 pr_out_section_start(dl
, "port_pool");
3842 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
3843 pr_out_section_end(dl
);
3847 static int cmd_sb_port_pool_set(struct dl
*dl
)
3849 struct nlmsghdr
*nlh
;
3852 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
3853 NLM_F_REQUEST
| NLM_F_ACK
);
3855 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
3856 DL_OPT_SB_TH
, DL_OPT_SB
);
3860 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3863 static int cmd_sb_port_pool(struct dl
*dl
)
3865 if (dl_argv_match(dl
, "help")) {
3868 } else if (dl_argv_match(dl
, "show") ||
3869 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3871 return cmd_sb_port_pool_show(dl
);
3872 } else if (dl_argv_match(dl
, "set")) {
3874 return cmd_sb_port_pool_set(dl
);
3876 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3880 static int cmd_sb_port(struct dl
*dl
)
3882 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3885 } else if (dl_argv_match(dl
, "pool")) {
3887 return cmd_sb_port_pool(dl
);
3889 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3893 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
3895 pr_out_port_handle_start_arr(dl
, tb
, true);
3896 check_indent_newline(dl
);
3897 print_uint(PRINT_ANY
, "sb", "sb %u",
3898 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3899 print_uint(PRINT_ANY
, "tc", " tc %u",
3900 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
3901 print_string(PRINT_ANY
, "type", " type %s",
3902 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3903 print_uint(PRINT_ANY
, "pool", " pool %u",
3904 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3905 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3906 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3907 pr_out_port_handle_end(dl
);
3910 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3912 struct dl
*dl
= data
;
3913 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3914 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3916 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3917 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3918 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3919 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3920 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3921 return MNL_CB_ERROR
;
3922 pr_out_sb_tc_bind(dl
, tb
);
3926 static int cmd_sb_tc_bind_show(struct dl
*dl
)
3928 struct nlmsghdr
*nlh
;
3929 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3932 if (dl_argc(dl
) == 0)
3933 flags
|= NLM_F_DUMP
;
3935 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3937 if (dl_argc(dl
) > 0) {
3938 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3939 DL_OPT_SB_TYPE
, DL_OPT_SB
);
3944 pr_out_section_start(dl
, "tc_bind");
3945 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
3946 pr_out_section_end(dl
);
3950 static int cmd_sb_tc_bind_set(struct dl
*dl
)
3952 struct nlmsghdr
*nlh
;
3955 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
3956 NLM_F_REQUEST
| NLM_F_ACK
);
3958 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3959 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
3964 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3967 static int cmd_sb_tc_bind(struct dl
*dl
)
3969 if (dl_argv_match(dl
, "help")) {
3972 } else if (dl_argv_match(dl
, "show") ||
3973 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3975 return cmd_sb_tc_bind_show(dl
);
3976 } else if (dl_argv_match(dl
, "set")) {
3978 return cmd_sb_tc_bind_set(dl
);
3980 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3984 static int cmd_sb_tc(struct dl
*dl
)
3986 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3989 } else if (dl_argv_match(dl
, "bind")) {
3991 return cmd_sb_tc_bind(dl
);
3993 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3998 struct list_head list
;
4002 uint32_t bound_pool_index
;
4006 struct list_head list
;
4009 uint32_t port_index
;
4011 struct list_head pool_list
;
4012 struct list_head ing_tc_list
;
4013 struct list_head eg_tc_list
;
4019 struct list_head port_list
;
4022 static struct occ_item
*occ_item_alloc(void)
4024 return calloc(1, sizeof(struct occ_item
));
4027 static void occ_item_free(struct occ_item
*occ_item
)
4032 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
4034 struct occ_port
*occ_port
;
4036 occ_port
= calloc(1, sizeof(*occ_port
));
4039 occ_port
->port_index
= port_index
;
4040 INIT_LIST_HEAD(&occ_port
->pool_list
);
4041 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
4042 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
4046 static void occ_port_free(struct occ_port
*occ_port
)
4048 struct occ_item
*occ_item
, *tmp
;
4050 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
4051 occ_item_free(occ_item
);
4052 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
4053 occ_item_free(occ_item
);
4054 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
4055 occ_item_free(occ_item
);
4058 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
4060 struct occ_show
*occ_show
;
4062 occ_show
= calloc(1, sizeof(*occ_show
));
4066 INIT_LIST_HEAD(&occ_show
->port_list
);
4070 static void occ_show_free(struct occ_show
*occ_show
)
4072 struct occ_port
*occ_port
, *tmp
;
4074 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
4075 occ_port_free(occ_port
);
4078 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
4081 struct occ_port
*occ_port
;
4082 uint32_t port_index
;
4084 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
4086 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
4087 if (occ_port
->port_index
== port_index
)
4090 occ_port
= occ_port_alloc(port_index
);
4093 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
4097 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
4100 struct occ_item
*occ_item
;
4103 pr_out_sp(7, " %s:", label
);
4104 list_for_each_entry(occ_item
, list
, list
) {
4105 if ((i
- 1) % 4 == 0 && i
!= 1)
4108 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
4109 occ_item
->bound_pool_index
);
4111 pr_out_sp(7, "%2u:", occ_item
->index
);
4112 pr_out_sp(21, "%10u/%u", occ_item
->cur
, occ_item
->max
);
4116 if ((i
- 1) % 4 != 0)
4120 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
4121 struct list_head
*list
,
4124 struct occ_item
*occ_item
;
4127 open_json_object(label
);
4128 list_for_each_entry(occ_item
, list
, list
) {
4129 sprintf(buf
, "%u", occ_item
->index
);
4130 open_json_object(buf
);
4132 print_uint(PRINT_JSON
, "bound_pool", NULL
,
4133 occ_item
->bound_pool_index
);
4134 print_uint(PRINT_JSON
, "current", NULL
, occ_item
->cur
);
4135 print_uint(PRINT_JSON
, "max", NULL
, occ_item
->max
);
4136 close_json_object();
4138 close_json_object();
4141 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
4143 if (dl
->json_output
) {
4144 pr_out_json_occ_show_item_list(dl
, "pool",
4145 &occ_port
->pool_list
, false);
4146 pr_out_json_occ_show_item_list(dl
, "itc",
4147 &occ_port
->ing_tc_list
, true);
4148 pr_out_json_occ_show_item_list(dl
, "etc",
4149 &occ_port
->eg_tc_list
, true);
4152 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
4153 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
4154 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
4158 static void pr_out_occ_show(struct occ_show
*occ_show
)
4160 struct dl
*dl
= occ_show
->dl
;
4161 struct dl_opts
*opts
= &dl
->opts
;
4162 struct occ_port
*occ_port
;
4164 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
4165 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
4166 occ_port
->port_index
, true, false);
4167 pr_out_occ_show_port(dl
, occ_port
);
4168 pr_out_port_handle_end(dl
);
4172 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
4175 struct occ_port
*occ_port
;
4176 struct occ_item
*occ_item
;
4178 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
4181 occ_port
= occ_port_get(occ_show
, tb
);
4183 occ_show
->err
= -ENOMEM
;
4187 occ_item
= occ_item_alloc();
4189 occ_show
->err
= -ENOMEM
;
4192 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4193 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4194 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4195 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
4198 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4200 struct occ_show
*occ_show
= data
;
4201 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4202 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4204 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4205 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4206 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4207 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4208 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4209 return MNL_CB_ERROR
;
4210 cmd_sb_occ_port_pool_process(occ_show
, tb
);
4214 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
4217 struct occ_port
*occ_port
;
4218 struct occ_item
*occ_item
;
4221 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
4224 occ_port
= occ_port_get(occ_show
, tb
);
4226 occ_show
->err
= -ENOMEM
;
4230 occ_item
= occ_item_alloc();
4232 occ_show
->err
= -ENOMEM
;
4235 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
4236 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4237 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4238 occ_item
->bound_pool_index
=
4239 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4240 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
4241 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
4242 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
4243 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
4244 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
4246 occ_item_free(occ_item
);
4249 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4251 struct occ_show
*occ_show
= data
;
4252 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4253 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4255 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4256 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4257 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4258 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
4259 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4260 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4261 return MNL_CB_ERROR
;
4262 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
4266 static int cmd_sb_occ_show(struct dl
*dl
)
4268 struct nlmsghdr
*nlh
;
4269 struct occ_show
*occ_show
;
4270 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
4273 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
4277 occ_show
= occ_show_alloc(dl
);
4281 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
4283 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4284 cmd_sb_occ_port_pool_process_cb
, occ_show
);
4288 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
4290 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4291 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
4295 pr_out_section_start(dl
, "occupancy");
4296 pr_out_occ_show(occ_show
);
4297 pr_out_section_end(dl
);
4300 occ_show_free(occ_show
);
4304 static int cmd_sb_occ_snapshot(struct dl
*dl
)
4306 struct nlmsghdr
*nlh
;
4309 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
4310 NLM_F_REQUEST
| NLM_F_ACK
);
4312 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4316 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4319 static int cmd_sb_occ_clearmax(struct dl
*dl
)
4321 struct nlmsghdr
*nlh
;
4324 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
4325 NLM_F_REQUEST
| NLM_F_ACK
);
4327 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4331 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4334 static int cmd_sb_occ(struct dl
*dl
)
4336 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4339 } else if (dl_argv_match(dl
, "show") ||
4340 dl_argv_match(dl
, "list")) {
4342 return cmd_sb_occ_show(dl
);
4343 } else if (dl_argv_match(dl
, "snapshot")) {
4345 return cmd_sb_occ_snapshot(dl
);
4346 } else if (dl_argv_match(dl
, "clearmax")) {
4348 return cmd_sb_occ_clearmax(dl
);
4350 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4354 static int cmd_sb(struct dl
*dl
)
4356 if (dl_argv_match(dl
, "help")) {
4359 } else if (dl_argv_match(dl
, "show") ||
4360 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
4362 return cmd_sb_show(dl
);
4363 } else if (dl_argv_match(dl
, "pool")) {
4365 return cmd_sb_pool(dl
);
4366 } else if (dl_argv_match(dl
, "port")) {
4368 return cmd_sb_port(dl
);
4369 } else if (dl_argv_match(dl
, "tc")) {
4371 return cmd_sb_tc(dl
);
4372 } else if (dl_argv_match(dl
, "occupancy")) {
4374 return cmd_sb_occ(dl
);
4376 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4380 static const char *cmd_name(uint8_t cmd
)
4383 case DEVLINK_CMD_UNSPEC
: return "unspec";
4384 case DEVLINK_CMD_GET
: return "get";
4385 case DEVLINK_CMD_SET
: return "set";
4386 case DEVLINK_CMD_NEW
: return "new";
4387 case DEVLINK_CMD_DEL
: return "del";
4388 case DEVLINK_CMD_PORT_GET
: return "get";
4389 case DEVLINK_CMD_PORT_SET
: return "set";
4390 case DEVLINK_CMD_PORT_NEW
: return "new";
4391 case DEVLINK_CMD_PORT_DEL
: return "del";
4392 case DEVLINK_CMD_PARAM_GET
: return "get";
4393 case DEVLINK_CMD_PARAM_SET
: return "set";
4394 case DEVLINK_CMD_PARAM_NEW
: return "new";
4395 case DEVLINK_CMD_PARAM_DEL
: return "del";
4396 case DEVLINK_CMD_REGION_GET
: return "get";
4397 case DEVLINK_CMD_REGION_SET
: return "set";
4398 case DEVLINK_CMD_REGION_NEW
: return "new";
4399 case DEVLINK_CMD_REGION_DEL
: return "del";
4400 case DEVLINK_CMD_FLASH_UPDATE
: return "begin";
4401 case DEVLINK_CMD_FLASH_UPDATE_END
: return "end";
4402 case DEVLINK_CMD_FLASH_UPDATE_STATUS
: return "status";
4403 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
: return "status";
4404 case DEVLINK_CMD_TRAP_GET
: return "get";
4405 case DEVLINK_CMD_TRAP_SET
: return "set";
4406 case DEVLINK_CMD_TRAP_NEW
: return "new";
4407 case DEVLINK_CMD_TRAP_DEL
: return "del";
4408 case DEVLINK_CMD_TRAP_GROUP_GET
: return "get";
4409 case DEVLINK_CMD_TRAP_GROUP_SET
: return "set";
4410 case DEVLINK_CMD_TRAP_GROUP_NEW
: return "new";
4411 case DEVLINK_CMD_TRAP_GROUP_DEL
: return "del";
4412 case DEVLINK_CMD_TRAP_POLICER_GET
: return "get";
4413 case DEVLINK_CMD_TRAP_POLICER_SET
: return "set";
4414 case DEVLINK_CMD_TRAP_POLICER_NEW
: return "new";
4415 case DEVLINK_CMD_TRAP_POLICER_DEL
: return "del";
4416 default: return "<unknown cmd>";
4420 static const char *cmd_obj(uint8_t cmd
)
4423 case DEVLINK_CMD_UNSPEC
: return "unspec";
4424 case DEVLINK_CMD_GET
:
4425 case DEVLINK_CMD_SET
:
4426 case DEVLINK_CMD_NEW
:
4427 case DEVLINK_CMD_DEL
:
4429 case DEVLINK_CMD_PORT_GET
:
4430 case DEVLINK_CMD_PORT_SET
:
4431 case DEVLINK_CMD_PORT_NEW
:
4432 case DEVLINK_CMD_PORT_DEL
:
4434 case DEVLINK_CMD_PARAM_GET
:
4435 case DEVLINK_CMD_PARAM_SET
:
4436 case DEVLINK_CMD_PARAM_NEW
:
4437 case DEVLINK_CMD_PARAM_DEL
:
4439 case DEVLINK_CMD_REGION_GET
:
4440 case DEVLINK_CMD_REGION_SET
:
4441 case DEVLINK_CMD_REGION_NEW
:
4442 case DEVLINK_CMD_REGION_DEL
:
4444 case DEVLINK_CMD_FLASH_UPDATE
:
4445 case DEVLINK_CMD_FLASH_UPDATE_END
:
4446 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4448 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4450 case DEVLINK_CMD_TRAP_GET
:
4451 case DEVLINK_CMD_TRAP_SET
:
4452 case DEVLINK_CMD_TRAP_NEW
:
4453 case DEVLINK_CMD_TRAP_DEL
:
4455 case DEVLINK_CMD_TRAP_GROUP_GET
:
4456 case DEVLINK_CMD_TRAP_GROUP_SET
:
4457 case DEVLINK_CMD_TRAP_GROUP_NEW
:
4458 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4459 return "trap-group";
4460 case DEVLINK_CMD_TRAP_POLICER_GET
:
4461 case DEVLINK_CMD_TRAP_POLICER_SET
:
4462 case DEVLINK_CMD_TRAP_POLICER_NEW
:
4463 case DEVLINK_CMD_TRAP_POLICER_DEL
:
4464 return "trap-policer";
4465 default: return "<unknown obj>";
4469 static void pr_out_mon_header(uint8_t cmd
)
4471 if (!is_json_context()) {
4472 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
4474 open_json_object(NULL
);
4475 print_string(PRINT_JSON
, "command", NULL
, cmd_name(cmd
));
4476 open_json_object(cmd_obj(cmd
));
4480 static void pr_out_mon_footer(void)
4482 if (is_json_context()) {
4483 close_json_object();
4484 close_json_object();
4488 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
4490 const char *obj
= cmd_obj(cmd
);
4491 unsigned int index
= 0;
4492 const char *cur_obj
;
4496 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4497 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
4503 static void pr_out_flash_update(struct dl
*dl
, struct nlattr
**tb
)
4505 __pr_out_handle_start(dl
, tb
, true, false);
4507 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]) {
4508 check_indent_newline(dl
);
4509 print_string(PRINT_ANY
, "msg", "msg %s",
4510 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]));
4512 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]) {
4513 check_indent_newline(dl
);
4514 print_string(PRINT_ANY
, "component", "component %s",
4515 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]));
4518 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
4519 pr_out_u64(dl
, "done",
4520 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]));
4522 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
4523 pr_out_u64(dl
, "total",
4524 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]));
4526 pr_out_handle_end(dl
);
4529 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
);
4530 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
,
4531 bool show_device
, bool show_port
);
4532 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4533 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4534 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4536 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
4538 struct dl
*dl
= data
;
4539 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4540 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4541 uint8_t cmd
= genl
->cmd
;
4543 if (!cmd_filter_check(dl
, cmd
))
4547 case DEVLINK_CMD_GET
: /* fall through */
4548 case DEVLINK_CMD_SET
: /* fall through */
4549 case DEVLINK_CMD_NEW
: /* fall through */
4550 case DEVLINK_CMD_DEL
:
4551 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4552 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4553 return MNL_CB_ERROR
;
4554 pr_out_mon_header(genl
->cmd
);
4555 pr_out_handle(dl
, tb
);
4556 pr_out_mon_footer();
4558 case DEVLINK_CMD_PORT_GET
: /* fall through */
4559 case DEVLINK_CMD_PORT_SET
: /* fall through */
4560 case DEVLINK_CMD_PORT_NEW
: /* fall through */
4561 case DEVLINK_CMD_PORT_DEL
:
4562 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4563 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4564 !tb
[DEVLINK_ATTR_PORT_INDEX
])
4565 return MNL_CB_ERROR
;
4566 pr_out_mon_header(genl
->cmd
);
4567 pr_out_port(dl
, tb
);
4568 pr_out_mon_footer();
4570 case DEVLINK_CMD_PARAM_GET
: /* fall through */
4571 case DEVLINK_CMD_PARAM_SET
: /* fall through */
4572 case DEVLINK_CMD_PARAM_NEW
: /* fall through */
4573 case DEVLINK_CMD_PARAM_DEL
:
4574 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4575 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4576 !tb
[DEVLINK_ATTR_PARAM
])
4577 return MNL_CB_ERROR
;
4578 pr_out_mon_header(genl
->cmd
);
4579 pr_out_param(dl
, tb
, false);
4580 pr_out_mon_footer();
4582 case DEVLINK_CMD_REGION_GET
: /* fall through */
4583 case DEVLINK_CMD_REGION_SET
: /* fall through */
4584 case DEVLINK_CMD_REGION_NEW
: /* fall through */
4585 case DEVLINK_CMD_REGION_DEL
:
4586 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4587 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4588 !tb
[DEVLINK_ATTR_REGION_NAME
])
4589 return MNL_CB_ERROR
;
4590 pr_out_mon_header(genl
->cmd
);
4591 pr_out_region(dl
, tb
);
4592 pr_out_mon_footer();
4594 case DEVLINK_CMD_FLASH_UPDATE
: /* fall through */
4595 case DEVLINK_CMD_FLASH_UPDATE_END
: /* fall through */
4596 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4597 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4598 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4599 return MNL_CB_ERROR
;
4600 pr_out_mon_header(genl
->cmd
);
4601 pr_out_flash_update(dl
, tb
);
4602 pr_out_mon_footer();
4604 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4605 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4606 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4607 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
4608 return MNL_CB_ERROR
;
4609 pr_out_mon_header(genl
->cmd
);
4610 pr_out_health(dl
, tb
, true, true);
4611 pr_out_mon_footer();
4613 case DEVLINK_CMD_TRAP_GET
: /* fall through */
4614 case DEVLINK_CMD_TRAP_SET
: /* fall through */
4615 case DEVLINK_CMD_TRAP_NEW
: /* fall through */
4616 case DEVLINK_CMD_TRAP_DEL
:
4617 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4618 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4619 !tb
[DEVLINK_ATTR_TRAP_NAME
] ||
4620 !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
4621 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
4622 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4623 !tb
[DEVLINK_ATTR_TRAP_METADATA
] ||
4624 !tb
[DEVLINK_ATTR_STATS
])
4625 return MNL_CB_ERROR
;
4626 pr_out_mon_header(genl
->cmd
);
4627 pr_out_trap(dl
, tb
, false);
4628 pr_out_mon_footer();
4630 case DEVLINK_CMD_TRAP_GROUP_GET
: /* fall through */
4631 case DEVLINK_CMD_TRAP_GROUP_SET
: /* fall through */
4632 case DEVLINK_CMD_TRAP_GROUP_NEW
: /* fall through */
4633 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4634 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4635 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4636 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4637 !tb
[DEVLINK_ATTR_STATS
])
4638 return MNL_CB_ERROR
;
4639 pr_out_mon_header(genl
->cmd
);
4640 pr_out_trap_group(dl
, tb
, false);
4641 pr_out_mon_footer();
4643 case DEVLINK_CMD_TRAP_POLICER_GET
: /* fall through */
4644 case DEVLINK_CMD_TRAP_POLICER_SET
: /* fall through */
4645 case DEVLINK_CMD_TRAP_POLICER_NEW
: /* fall through */
4646 case DEVLINK_CMD_TRAP_POLICER_DEL
: /* fall through */
4647 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4648 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4649 !tb
[DEVLINK_ATTR_TRAP_POLICER_ID
] ||
4650 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
4651 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
4652 return MNL_CB_ERROR
;
4653 pr_out_mon_header(genl
->cmd
);
4654 pr_out_trap_policer(dl
, tb
, false);
4660 static int cmd_mon_show(struct dl
*dl
)
4663 unsigned int index
= 0;
4664 const char *cur_obj
;
4666 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4667 if (strcmp(cur_obj
, "all") != 0 &&
4668 strcmp(cur_obj
, "dev") != 0 &&
4669 strcmp(cur_obj
, "port") != 0 &&
4670 strcmp(cur_obj
, "health") != 0 &&
4671 strcmp(cur_obj
, "trap") != 0 &&
4672 strcmp(cur_obj
, "trap-group") != 0 &&
4673 strcmp(cur_obj
, "trap-policer") != 0) {
4674 pr_err("Unknown object \"%s\"\n", cur_obj
);
4678 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
4681 open_json_object(NULL
);
4682 open_json_array(PRINT_JSON
, "mon");
4683 err
= _mnlg_socket_recv_run_intr(dl
->nlg
, cmd_mon_show_cb
, dl
);
4684 close_json_array(PRINT_JSON
, NULL
);
4685 close_json_object();
4691 static void cmd_mon_help(void)
4693 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
4694 "where OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
4697 static int cmd_mon(struct dl
*dl
)
4699 if (dl_argv_match(dl
, "help")) {
4703 return cmd_mon_show(dl
);
4706 struct dpipe_field
{
4709 unsigned int bitwidth
;
4710 enum devlink_dpipe_field_mapping_type mapping_type
;
4713 struct dpipe_header
{
4714 struct list_head list
;
4717 struct dpipe_field
*fields
;
4718 unsigned int fields_count
;
4721 struct dpipe_table
{
4722 struct list_head list
;
4724 unsigned int resource_id
;
4725 bool resource_valid
;
4728 struct dpipe_tables
{
4729 struct list_head table_list
;
4739 enum devlink_resource_unit unit
;
4744 struct list_head list
;
4745 struct list_head resource_list
;
4746 struct resource
*parent
;
4750 struct list_head resource_list
;
4753 struct resource_ctx
{
4756 struct resources
*resources
;
4757 struct dpipe_tables
*tables
;
4758 bool print_resources
;
4759 bool pending_change
;
4762 static struct resource
*resource_alloc(void)
4764 struct resource
*resource
;
4766 resource
= calloc(1, sizeof(struct resource
));
4769 INIT_LIST_HEAD(&resource
->resource_list
);
4773 static void resource_free(struct resource
*resource
)
4775 struct resource
*child_resource
, *tmp
;
4777 list_for_each_entry_safe(child_resource
, tmp
, &resource
->resource_list
,
4779 free(child_resource
->name
);
4780 resource_free(child_resource
);
4785 static struct resources
*resources_alloc(void)
4787 struct resources
*resources
;
4789 resources
= calloc(1, sizeof(struct resources
));
4792 INIT_LIST_HEAD(&resources
->resource_list
);
4796 static void resources_free(struct resources
*resources
)
4798 struct resource
*resource
, *tmp
;
4800 list_for_each_entry_safe(resource
, tmp
, &resources
->resource_list
, list
)
4801 resource_free(resource
);
4804 static int resource_ctx_init(struct resource_ctx
*ctx
, struct dl
*dl
)
4806 ctx
->resources
= resources_alloc();
4807 if (!ctx
->resources
)
4813 static void resource_ctx_fini(struct resource_ctx
*ctx
)
4815 resources_free(ctx
->resources
);
4821 struct list_head global_headers
;
4822 struct list_head local_headers
;
4823 struct dpipe_tables
*tables
;
4824 struct resources
*resources
;
4829 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
4831 struct dpipe_header
*header
;
4833 header
= calloc(1, sizeof(struct dpipe_header
));
4836 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
4837 if (!header
->fields
)
4838 goto err_fields_alloc
;
4839 header
->fields_count
= fields_count
;
4847 static void dpipe_header_free(struct dpipe_header
*header
)
4849 free(header
->fields
);
4853 static void dpipe_header_clear(struct dpipe_header
*header
)
4855 struct dpipe_field
*field
;
4858 for (i
= 0; i
< header
->fields_count
; i
++) {
4859 field
= &header
->fields
[i
];
4865 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
4866 struct dpipe_header
*header
, bool global
)
4869 list_add(&header
->list
, &ctx
->global_headers
);
4871 list_add(&header
->list
, &ctx
->local_headers
);
4874 static void dpipe_header_del(struct dpipe_header
*header
)
4876 list_del(&header
->list
);
4879 static struct dpipe_table
*dpipe_table_alloc(void)
4881 return calloc(1, sizeof(struct dpipe_table
));
4884 static void dpipe_table_free(struct dpipe_table
*table
)
4889 static struct dpipe_tables
*dpipe_tables_alloc(void)
4891 struct dpipe_tables
*tables
;
4893 tables
= calloc(1, sizeof(struct dpipe_tables
));
4896 INIT_LIST_HEAD(&tables
->table_list
);
4900 static void dpipe_tables_free(struct dpipe_tables
*tables
)
4902 struct dpipe_table
*table
, *tmp
;
4904 list_for_each_entry_safe(table
, tmp
, &tables
->table_list
, list
)
4905 dpipe_table_free(table
);
4909 static int dpipe_ctx_init(struct dpipe_ctx
*ctx
, struct dl
*dl
)
4911 ctx
->tables
= dpipe_tables_alloc();
4916 INIT_LIST_HEAD(&ctx
->global_headers
);
4917 INIT_LIST_HEAD(&ctx
->local_headers
);
4921 static void dpipe_ctx_fini(struct dpipe_ctx
*ctx
)
4923 struct dpipe_header
*header
, *tmp
;
4925 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
4927 dpipe_header_del(header
);
4928 dpipe_header_clear(header
);
4929 dpipe_header_free(header
);
4931 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
4933 dpipe_header_del(header
);
4934 dpipe_header_clear(header
);
4935 dpipe_header_free(header
);
4937 dpipe_tables_free(ctx
->tables
);
4940 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
4941 uint32_t header_id
, bool global
)
4943 struct list_head
*header_list
;
4944 struct dpipe_header
*header
;
4947 header_list
= &ctx
->global_headers
;
4949 header_list
= &ctx
->local_headers
;
4950 list_for_each_entry(header
, header_list
, list
) {
4951 if (header
->id
!= header_id
)
4953 return header
->name
;
4958 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
4960 uint32_t field_id
, bool global
)
4962 struct list_head
*header_list
;
4963 struct dpipe_header
*header
;
4966 header_list
= &ctx
->global_headers
;
4968 header_list
= &ctx
->local_headers
;
4969 list_for_each_entry(header
, header_list
, list
) {
4970 if (header
->id
!= header_id
)
4972 return header
->fields
[field_id
].name
;
4978 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
4980 switch (mapping_type
) {
4981 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
4983 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
4991 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
4992 uint32_t field_id
, bool global
)
4994 enum devlink_dpipe_field_mapping_type mapping_type
;
4995 struct list_head
*header_list
;
4996 struct dpipe_header
*header
;
4999 header_list
= &ctx
->global_headers
;
5001 header_list
= &ctx
->local_headers
;
5002 list_for_each_entry(header
, header_list
, list
) {
5003 if (header
->id
!= header_id
)
5005 mapping_type
= header
->fields
[field_id
].mapping_type
;
5006 return dpipe_field_mapping_e2s(mapping_type
);
5011 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
5012 struct dpipe_field
*fields
,
5013 unsigned int field_count
)
5015 struct dpipe_field
*field
;
5018 for (i
= 0; i
< field_count
; i
++) {
5020 pr_out_entry_start(ctx
->dl
);
5021 check_indent_newline(ctx
->dl
);
5022 print_string(PRINT_ANY
, "name", "name %s", field
->name
);
5023 if (ctx
->dl
->verbose
)
5024 print_uint(PRINT_ANY
, "id", " id %u", field
->id
);
5025 print_uint(PRINT_ANY
, "bitwidth", " bitwidth %u", field
->bitwidth
);
5026 if (field
->mapping_type
) {
5027 print_string(PRINT_ANY
, "mapping_type", " mapping_type %s",
5028 dpipe_field_mapping_e2s(field
->mapping_type
));
5030 pr_out_entry_end(ctx
->dl
);
5035 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
5036 struct dpipe_header
*header
, bool global
)
5038 pr_out_handle_start_arr(ctx
->dl
, tb
);
5039 check_indent_newline(ctx
->dl
);
5040 print_string(PRINT_ANY
, "name", "name %s", header
->name
);
5041 if (ctx
->dl
->verbose
) {
5042 print_uint(PRINT_ANY
, "id", " id %u", header
->id
);
5043 print_bool(PRINT_ANY
, "global", " global %s", global
);
5045 pr_out_array_start(ctx
->dl
, "field");
5046 pr_out_dpipe_fields(ctx
, header
->fields
,
5047 header
->fields_count
);
5048 pr_out_array_end(ctx
->dl
);
5049 pr_out_handle_end(ctx
->dl
);
5052 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
5055 struct dpipe_header
*header
;
5057 list_for_each_entry(header
, &ctx
->local_headers
, list
)
5058 pr_out_dpipe_header(ctx
, tb
, header
, false);
5060 list_for_each_entry(header
, &ctx
->global_headers
, list
)
5061 pr_out_dpipe_header(ctx
, tb
, header
, true);
5064 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
5066 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
5070 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
5071 if (err
!= MNL_CB_OK
)
5073 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
5074 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
5075 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
5076 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
5079 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
5080 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5081 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
5082 field
->name
= strdup(name
);
5085 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
5089 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
5090 struct dpipe_field
*fields
)
5092 struct nlattr
*nla_field
;
5096 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
5097 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
5105 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
5107 struct nlattr
*nla_field
;
5108 unsigned int count
= 0;
5110 mnl_attr_for_each_nested(nla_field
, nla_fields
)
5115 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5117 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
5118 struct dpipe_header
*header
;
5119 unsigned int fields_count
;
5120 const char *header_name
;
5124 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
5125 if (err
!= MNL_CB_OK
)
5128 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
5129 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5130 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
5133 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
5134 header
= dpipe_header_alloc(fields_count
);
5138 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
5139 header
->name
= strdup(header_name
);
5140 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5141 header
->fields_count
= fields_count
;
5142 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5144 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
5148 dpipe_header_add(ctx
, header
, global
);
5152 dpipe_header_free(header
);
5156 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5158 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
5159 struct nlattr
*nla_header
;
5162 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
5163 err
= dpipe_header_get(ctx
, nla_header
);
5170 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
5172 struct dpipe_ctx
*ctx
= data
;
5173 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5174 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5177 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5178 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5179 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
5180 return MNL_CB_ERROR
;
5181 err
= dpipe_headers_get(ctx
, tb
);
5184 return MNL_CB_ERROR
;
5187 if (ctx
->print_headers
)
5188 pr_out_dpipe_headers(ctx
, tb
);
5192 static int cmd_dpipe_headers_show(struct dl
*dl
)
5194 struct nlmsghdr
*nlh
;
5195 struct dpipe_ctx ctx
= {};
5196 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5199 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5201 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
5205 err
= dpipe_ctx_init(&ctx
, dl
);
5209 ctx
.print_headers
= true;
5211 pr_out_section_start(dl
, "header");
5212 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5214 pr_err("error get headers %s\n", strerror(ctx
.err
));
5215 pr_out_section_end(dl
);
5217 dpipe_ctx_fini(&ctx
);
5221 static void cmd_dpipe_help(void)
5223 pr_err("Usage: devlink dpipe table show DEV [ name TABLE_NAME ]\n");
5224 pr_err(" devlink dpipe table set DEV name TABLE_NAME\n");
5225 pr_err(" [ counters_enabled { true | false } ]\n");
5226 pr_err(" devlink dpipe table dump DEV name TABLE_NAME\n");
5227 pr_err(" devlink dpipe header show DEV\n");
5230 static int cmd_dpipe_header(struct dl
*dl
)
5232 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5235 } else if (dl_argv_match(dl
, "show")) {
5237 return cmd_dpipe_headers_show(dl
);
5239 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5244 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
5246 switch (action_type
) {
5247 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
5248 return "field_modify";
5254 struct dpipe_op_info
{
5260 struct dpipe_action
{
5261 struct dpipe_op_info info
;
5265 static void pr_out_dpipe_action(struct dpipe_action
*action
,
5266 struct dpipe_ctx
*ctx
)
5268 struct dpipe_op_info
*op_info
= &action
->info
;
5269 const char *mapping
;
5271 check_indent_newline(ctx
->dl
);
5272 print_string(PRINT_ANY
, "type", "type %s",
5273 dpipe_action_type_e2s(action
->type
));
5274 print_string(PRINT_ANY
, "header", " header %s",
5275 dpipe_header_id2s(ctx
, op_info
->header_id
,
5276 op_info
->header_global
));
5277 print_string(PRINT_ANY
, "field", " field %s",
5278 dpipe_field_id2s(ctx
, op_info
->header_id
,
5280 op_info
->header_global
));
5281 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5283 op_info
->header_global
);
5285 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5288 static int dpipe_action_parse(struct dpipe_action
*action
, struct nlattr
*nl
)
5290 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
5293 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
5294 if (err
!= MNL_CB_OK
)
5297 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
5298 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5299 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5300 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5304 action
->type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
5305 action
->info
.header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5306 action
->info
.field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5307 action
->info
.header_global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5312 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
5313 struct nlattr
*nla_actions
)
5315 struct nlattr
*nla_action
;
5316 struct dpipe_action action
;
5318 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
5319 pr_out_entry_start(ctx
->dl
);
5320 if (dpipe_action_parse(&action
, nla_action
))
5321 goto err_action_parse
;
5322 pr_out_dpipe_action(&action
, ctx
);
5323 pr_out_entry_end(ctx
->dl
);
5328 pr_out_entry_end(ctx
->dl
);
5333 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
5335 switch (match_type
) {
5336 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
5337 return "field_exact";
5343 struct dpipe_match
{
5344 struct dpipe_op_info info
;
5348 static void pr_out_dpipe_match(struct dpipe_match
*match
,
5349 struct dpipe_ctx
*ctx
)
5351 struct dpipe_op_info
*op_info
= &match
->info
;
5352 const char *mapping
;
5354 check_indent_newline(ctx
->dl
);
5355 print_string(PRINT_ANY
, "type", "type %s",
5356 dpipe_match_type_e2s(match
->type
));
5357 print_string(PRINT_ANY
, "header", " header %s",
5358 dpipe_header_id2s(ctx
, op_info
->header_id
,
5359 op_info
->header_global
));
5360 print_string(PRINT_ANY
, "field", " field %s",
5361 dpipe_field_id2s(ctx
, op_info
->header_id
,
5363 op_info
->header_global
));
5364 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5366 op_info
->header_global
);
5368 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5371 static int dpipe_match_parse(struct dpipe_match
*match
,
5375 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
5378 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
5379 if (err
!= MNL_CB_OK
)
5382 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
5383 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5384 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5385 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5389 match
->type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
5390 match
->info
.header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5391 match
->info
.field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5392 match
->info
.header_global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5397 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
5398 struct nlattr
*nla_matches
)
5400 struct nlattr
*nla_match
;
5401 struct dpipe_match match
;
5403 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
5404 pr_out_entry_start(ctx
->dl
);
5405 if (dpipe_match_parse(&match
, nla_match
))
5406 goto err_match_parse
;
5407 pr_out_dpipe_match(&match
, ctx
);
5408 pr_out_entry_end(ctx
->dl
);
5413 pr_out_entry_end(ctx
->dl
);
5417 static struct resource
*
5418 resource_find(struct resources
*resources
, struct resource
*resource
,
5419 uint64_t resource_id
)
5421 struct list_head
*list_head
;
5424 list_head
= &resources
->resource_list
;
5426 list_head
= &resource
->resource_list
;
5428 list_for_each_entry(resource
, list_head
, list
) {
5429 struct resource
*child_resource
;
5431 if (resource
->id
== resource_id
)
5434 child_resource
= resource_find(resources
, resource
,
5437 return child_resource
;
5443 resource_path_print(struct dl
*dl
, struct resources
*resources
,
5444 uint64_t resource_id
)
5446 struct resource
*resource
, *parent_resource
;
5447 const char del
[] = "/";
5451 resource
= resource_find(resources
, NULL
, resource_id
);
5455 for (parent_resource
= resource
; parent_resource
;
5456 parent_resource
= parent_resource
->parent
)
5457 path_len
+= strlen(parent_resource
->name
) + 1;
5460 path
= calloc(1, path_len
);
5464 path
+= path_len
- 1;
5465 for (parent_resource
= resource
; parent_resource
;
5466 parent_resource
= parent_resource
->parent
) {
5467 path
-= strlen(parent_resource
->name
);
5468 memcpy(path
, parent_resource
->name
,
5469 strlen(parent_resource
->name
));
5470 path
-= strlen(del
);
5471 memcpy(path
, del
, strlen(del
));
5473 check_indent_newline(dl
);
5474 print_string(PRINT_ANY
, "resource_path", "resource_path %s", path
);
5478 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5480 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
5481 struct dpipe_table
*table
;
5482 uint32_t resource_units
;
5483 bool counters_enabled
;
5484 bool resource_valid
;
5488 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
5489 if (err
!= MNL_CB_OK
)
5492 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
5493 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
5494 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
5495 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
5496 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
5500 table
= dpipe_table_alloc();
5504 table
->name
= strdup(mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]));
5505 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
5506 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
5508 resource_valid
= nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
] &&
5510 if (resource_valid
) {
5511 table
->resource_id
= mnl_attr_get_u64(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
]);
5512 table
->resource_valid
= true;
5515 list_add_tail(&table
->list
, &ctx
->tables
->table_list
);
5516 if (!ctx
->print_tables
)
5519 check_indent_newline(ctx
->dl
);
5520 print_string(PRINT_ANY
, "name", "name %s", table
->name
);
5521 print_uint(PRINT_ANY
, "size", " size %u", size
);
5522 print_bool(PRINT_ANY
, "counters_enabled", " counters_enabled %s", counters_enabled
);
5524 if (resource_valid
) {
5525 resource_units
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS
]);
5526 resource_path_print(ctx
->dl
, ctx
->resources
,
5527 table
->resource_id
);
5528 print_uint(PRINT_ANY
, "resource_units", " resource_units %u",
5532 pr_out_array_start(ctx
->dl
, "match");
5533 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
5534 goto err_matches_show
;
5535 pr_out_array_end(ctx
->dl
);
5537 pr_out_array_start(ctx
->dl
, "action");
5538 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
5539 goto err_actions_show
;
5540 pr_out_array_end(ctx
->dl
);
5546 pr_out_array_end(ctx
->dl
);
5550 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5552 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
5553 struct nlattr
*nla_table
;
5555 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
5556 if (ctx
->print_tables
)
5557 pr_out_handle_start_arr(ctx
->dl
, tb
);
5558 if (dpipe_table_show(ctx
, nla_table
))
5559 goto err_table_show
;
5560 if (ctx
->print_tables
)
5561 pr_out_handle_end(ctx
->dl
);
5566 if (ctx
->print_tables
)
5567 pr_out_handle_end(ctx
->dl
);
5571 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5573 struct dpipe_ctx
*ctx
= data
;
5574 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5575 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5577 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5578 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5579 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
5580 return MNL_CB_ERROR
;
5582 if (dpipe_tables_show(ctx
, tb
))
5583 return MNL_CB_ERROR
;
5587 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
);
5589 static int cmd_dpipe_table_show(struct dl
*dl
)
5591 struct nlmsghdr
*nlh
;
5592 struct dpipe_ctx dpipe_ctx
= {};
5593 struct resource_ctx resource_ctx
= {};
5594 uint16_t flags
= NLM_F_REQUEST
;
5597 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
5601 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5603 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5607 dpipe_ctx
.print_tables
= true;
5609 dl_opts_put(nlh
, dl
);
5610 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
,
5613 pr_err("error get headers %s\n", strerror(dpipe_ctx
.err
));
5614 goto err_headers_get
;
5617 err
= resource_ctx_init(&resource_ctx
, dl
);
5619 goto err_resource_ctx_init
;
5621 resource_ctx
.print_resources
= false;
5622 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
, flags
);
5623 dl_opts_put(nlh
, dl
);
5624 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
5627 dpipe_ctx
.resources
= resource_ctx
.resources
;
5629 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5630 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
5631 dl_opts_put(nlh
, dl
);
5633 pr_out_section_start(dl
, "table");
5634 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, &dpipe_ctx
);
5635 pr_out_section_end(dl
);
5637 resource_ctx_fini(&resource_ctx
);
5638 dpipe_ctx_fini(&dpipe_ctx
);
5641 err_resource_ctx_init
:
5643 dpipe_ctx_fini(&dpipe_ctx
);
5647 static int cmd_dpipe_table_set(struct dl
*dl
)
5649 struct nlmsghdr
*nlh
;
5652 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
5653 NLM_F_REQUEST
| NLM_F_ACK
);
5655 err
= dl_argv_parse_put(nlh
, dl
,
5656 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
5657 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
5661 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5664 enum dpipe_value_type
{
5665 DPIPE_VALUE_TYPE_VALUE
,
5666 DPIPE_VALUE_TYPE_MASK
,
5670 dpipe_value_type_e2s(enum dpipe_value_type type
)
5673 case DPIPE_VALUE_TYPE_VALUE
:
5675 case DPIPE_VALUE_TYPE_MASK
:
5676 return "value_mask";
5682 struct dpipe_field_printer
{
5683 unsigned int field_id
;
5684 void (*printer
)(struct dpipe_ctx
*, enum dpipe_value_type
, void *);
5687 struct dpipe_header_printer
{
5688 struct dpipe_field_printer
*printers
;
5689 unsigned int printers_count
;
5690 unsigned int header_id
;
5693 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx
*ctx
,
5694 enum dpipe_value_type type
,
5697 struct in_addr ip_addr
;
5699 ip_addr
.s_addr
= htonl(*(uint32_t *)value
);
5700 check_indent_newline(ctx
->dl
);
5701 print_string_name_value(dpipe_value_type_e2s(type
), inet_ntoa(ip_addr
));
5705 dpipe_field_printer_ethernet_addr(struct dpipe_ctx
*ctx
,
5706 enum dpipe_value_type type
,
5709 check_indent_newline(ctx
->dl
);
5710 print_string_name_value(dpipe_value_type_e2s(type
),
5711 ether_ntoa((struct ether_addr
*)value
));
5714 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx
*ctx
,
5715 enum dpipe_value_type type
,
5718 char str
[INET6_ADDRSTRLEN
];
5720 inet_ntop(AF_INET6
, value
, str
, INET6_ADDRSTRLEN
);
5721 check_indent_newline(ctx
->dl
);
5722 print_string_name_value(dpipe_value_type_e2s(type
), str
);
5725 static struct dpipe_field_printer dpipe_field_printers_ipv4
[] = {
5727 .printer
= dpipe_field_printer_ipv4_addr
,
5728 .field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
,
5732 static struct dpipe_header_printer dpipe_header_printer_ipv4
= {
5733 .printers
= dpipe_field_printers_ipv4
,
5734 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv4
),
5735 .header_id
= DEVLINK_DPIPE_HEADER_IPV4
,
5738 static struct dpipe_field_printer dpipe_field_printers_ethernet
[] = {
5740 .printer
= dpipe_field_printer_ethernet_addr
,
5741 .field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
,
5745 static struct dpipe_header_printer dpipe_header_printer_ethernet
= {
5746 .printers
= dpipe_field_printers_ethernet
,
5747 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ethernet
),
5748 .header_id
= DEVLINK_DPIPE_HEADER_ETHERNET
,
5751 static struct dpipe_field_printer dpipe_field_printers_ipv6
[] = {
5753 .printer
= dpipe_field_printer_ipv6_addr
,
5754 .field_id
= DEVLINK_DPIPE_FIELD_IPV6_DST_IP
,
5758 static struct dpipe_header_printer dpipe_header_printer_ipv6
= {
5759 .printers
= dpipe_field_printers_ipv6
,
5760 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv6
),
5761 .header_id
= DEVLINK_DPIPE_HEADER_IPV6
,
5764 static struct dpipe_header_printer
*dpipe_header_printers
[] = {
5765 &dpipe_header_printer_ipv4
,
5766 &dpipe_header_printer_ethernet
,
5767 &dpipe_header_printer_ipv6
,
5770 static int dpipe_print_prot_header(struct dpipe_ctx
*ctx
,
5771 struct dpipe_op_info
*info
,
5772 enum dpipe_value_type type
,
5775 unsigned int header_printers_count
= ARRAY_SIZE(dpipe_header_printers
);
5776 struct dpipe_header_printer
*header_printer
;
5777 struct dpipe_field_printer
*field_printer
;
5778 unsigned int field_printers_count
;
5782 for (i
= 0; i
< header_printers_count
; i
++) {
5783 header_printer
= dpipe_header_printers
[i
];
5784 if (header_printer
->header_id
!= info
->header_id
)
5786 field_printers_count
= header_printer
->printers_count
;
5787 for (j
= 0; j
< field_printers_count
; j
++) {
5788 field_printer
= &header_printer
->printers
[j
];
5789 if (field_printer
->field_id
!= info
->field_id
)
5791 field_printer
->printer(ctx
, type
, value
);
5799 static void __pr_out_entry_value(struct dpipe_ctx
*ctx
,
5801 unsigned int value_len
,
5802 struct dpipe_op_info
*info
,
5803 enum dpipe_value_type type
)
5805 if (info
->header_global
&&
5806 !dpipe_print_prot_header(ctx
, info
, type
, value
))
5809 if (value_len
== sizeof(uint32_t)) {
5810 uint32_t *value_32
= value
;
5812 check_indent_newline(ctx
->dl
);
5813 print_uint_name_value(dpipe_value_type_e2s(type
), *value_32
);
5817 static void pr_out_dpipe_entry_value(struct dpipe_ctx
*ctx
,
5818 struct nlattr
**nla_match_value
,
5819 struct dpipe_op_info
*info
)
5821 void *value
, *value_mask
;
5822 uint32_t value_mapping
;
5826 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
5827 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
5829 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5830 value
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5833 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
5834 check_indent_newline(ctx
->dl
);
5835 print_uint(PRINT_ANY
, "mapping_value", "mapping_value %u", value_mapping
);
5839 value_mask
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5840 __pr_out_entry_value(ctx
, value_mask
, value_len
, info
,
5841 DPIPE_VALUE_TYPE_MASK
);
5844 __pr_out_entry_value(ctx
, value
, value_len
, info
, DPIPE_VALUE_TYPE_VALUE
);
5847 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
5850 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5851 struct dpipe_match match
;
5854 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
5855 if (err
!= MNL_CB_OK
)
5858 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
5859 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5863 pr_out_entry_start(ctx
->dl
);
5864 if (dpipe_match_parse(&match
,
5865 nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
5866 goto err_match_parse
;
5867 pr_out_dpipe_match(&match
, ctx
);
5868 pr_out_dpipe_entry_value(ctx
, nla_match_value
, &match
.info
);
5869 pr_out_entry_end(ctx
->dl
);
5874 pr_out_entry_end(ctx
->dl
);
5878 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
5881 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5882 struct dpipe_action action
;
5885 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
5886 if (err
!= MNL_CB_OK
)
5889 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
5890 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5894 pr_out_entry_start(ctx
->dl
);
5895 if (dpipe_action_parse(&action
,
5896 nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
5897 goto err_action_parse
;
5898 pr_out_dpipe_action(&action
, ctx
);
5899 pr_out_dpipe_entry_value(ctx
, nla_action_value
, &action
.info
);
5900 pr_out_entry_end(ctx
->dl
);
5905 pr_out_entry_end(ctx
->dl
);
5910 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
5911 struct nlattr
*nla_action_values
)
5913 struct nlattr
*nla_action_value
;
5915 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
5916 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
5923 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
5924 struct nlattr
*nla_match_values
)
5926 struct nlattr
*nla_match_value
;
5928 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
5929 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
5935 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5937 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
5938 uint32_t entry_index
;
5942 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
5943 if (err
!= MNL_CB_OK
)
5946 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
5947 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
5948 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
5952 check_indent_newline(ctx
->dl
);
5953 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
5954 print_uint(PRINT_ANY
, "index", "index %u", entry_index
);
5956 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
5957 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
5958 print_uint(PRINT_ANY
, "counter", " counter %u", counter
);
5961 pr_out_array_start(ctx
->dl
, "match_value");
5962 if (dpipe_tables_match_values_show(ctx
,
5963 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
5964 goto err_match_values_show
;
5965 pr_out_array_end(ctx
->dl
);
5967 pr_out_array_start(ctx
->dl
, "action_value");
5968 if (dpipe_tables_action_values_show(ctx
,
5969 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
5970 goto err_action_values_show
;
5971 pr_out_array_end(ctx
->dl
);
5974 err_action_values_show
:
5975 err_match_values_show
:
5976 pr_out_array_end(ctx
->dl
);
5980 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5982 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
5983 struct nlattr
*nla_entry
;
5985 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
5986 pr_out_handle_start_arr(ctx
->dl
, tb
);
5987 if (dpipe_entry_show(ctx
, nla_entry
))
5988 goto err_entry_show
;
5989 pr_out_handle_end(ctx
->dl
);
5994 pr_out_handle_end(ctx
->dl
);
5998 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
6000 struct dpipe_ctx
*ctx
= data
;
6001 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6002 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6004 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6005 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6006 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
6007 return MNL_CB_ERROR
;
6009 if (dpipe_table_entries_show(ctx
, tb
))
6010 return MNL_CB_ERROR
;
6014 static int cmd_dpipe_table_dump(struct dl
*dl
)
6016 struct nlmsghdr
*nlh
;
6017 struct dpipe_ctx ctx
= {};
6018 uint16_t flags
= NLM_F_REQUEST
;
6021 err
= dpipe_ctx_init(&ctx
, dl
);
6025 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
6029 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
6030 dl_opts_put(nlh
, dl
);
6031 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
6033 pr_err("error get headers %s\n", strerror(ctx
.err
));
6037 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6038 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
6039 dl_opts_put(nlh
, dl
);
6041 pr_out_section_start(dl
, "table_entry");
6042 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, &ctx
);
6043 pr_out_section_end(dl
);
6045 dpipe_ctx_fini(&ctx
);
6049 static int cmd_dpipe_table(struct dl
*dl
)
6051 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6054 } else if (dl_argv_match(dl
, "show")) {
6056 return cmd_dpipe_table_show(dl
);
6057 } else if (dl_argv_match(dl
, "set")) {
6059 return cmd_dpipe_table_set(dl
);
6060 } else if (dl_argv_match(dl
, "dump")) {
6062 return cmd_dpipe_table_dump(dl
);
6064 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6068 static int cmd_dpipe(struct dl
*dl
)
6070 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6073 } else if (dl_argv_match(dl
, "header")) {
6075 return cmd_dpipe_header(dl
);
6076 } else if (dl_argv_match(dl
, "table")) {
6078 return cmd_dpipe_table(dl
);
6080 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6085 resource_parse(struct resource_ctx
*ctx
, struct resource
*resource
,
6086 struct nlattr
**nla_resource
)
6088 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
] ||
6089 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
] ||
6090 !nla_resource
[DEVLINK_ATTR_RESOURCE_ID
] ||
6091 !nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
] ||
6092 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
] ||
6093 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
] ||
6094 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]) {
6098 resource
->name
= strdup(mnl_attr_get_str(nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
]));
6099 resource
->size
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
]);
6100 resource
->id
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_ID
]);
6101 resource
->unit
= mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
]);
6102 resource
->size_min
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
]);
6103 resource
->size_max
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
]);
6104 resource
->size_gran
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]);
6106 if (nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
])
6107 resource
->size_new
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
]);
6109 resource
->size_new
= resource
->size
;
6111 if (nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]) {
6112 resource
->size_occ
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]);
6113 resource
->occ_valid
= true;
6116 if (resource
->size_new
!= resource
->size
)
6117 ctx
->pending_change
= true;
6123 resource_get(struct resource_ctx
*ctx
, struct resource
*resource
,
6124 struct resource
*parent_resource
, struct nlattr
*nl
)
6126 struct nlattr
*nla_resource
[DEVLINK_ATTR_MAX
+ 1] = {};
6127 struct nlattr
*nla_child_resource
;
6128 struct nlattr
*nla_resources
;
6138 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_resource
);
6139 if (err
!= MNL_CB_OK
)
6142 err
= resource_parse(ctx
, resource
, nla_resource
);
6146 resource
->parent
= parent_resource
;
6147 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
])
6150 resource
->size_valid
= !!mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_VALID
]);
6151 nla_resources
= nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
];
6153 mnl_attr_for_each_nested(nla_child_resource
, nla_resources
) {
6154 struct resource
*child_resource
;
6155 struct list_head
*list
;
6157 child_resource
= resource_alloc();
6158 if (!child_resource
)
6162 list
= &ctx
->resources
->resource_list
;
6164 list
= &resource
->resource_list
;
6166 list_add_tail(&child_resource
->list
, list
);
6167 err
= resource_get(ctx
, child_resource
, resource
,
6168 nla_child_resource
);
6176 static const char *resource_unit_str_get(enum devlink_resource_unit unit
)
6179 case DEVLINK_RESOURCE_UNIT_ENTRY
: return "entry";
6180 default: return "<unknown unit>";
6184 static void resource_show(struct resource
*resource
,
6185 struct resource_ctx
*ctx
)
6187 struct resource
*child_resource
;
6188 struct dpipe_table
*table
;
6189 struct dl
*dl
= ctx
->dl
;
6192 check_indent_newline(dl
);
6193 print_string(PRINT_ANY
, "name", "name %s", resource
->name
);
6195 resource_path_print(dl
, ctx
->resources
, resource
->id
);
6196 pr_out_u64(dl
, "size", resource
->size
);
6197 if (resource
->size
!= resource
->size_new
)
6198 pr_out_u64(dl
, "size_new", resource
->size_new
);
6199 if (resource
->occ_valid
)
6200 print_uint(PRINT_ANY
, "occ", " occ %u", resource
->size_occ
);
6201 print_string(PRINT_ANY
, "unit", " unit %s",
6202 resource_unit_str_get(resource
->unit
));
6204 if (resource
->size_min
!= resource
->size_max
) {
6205 print_uint(PRINT_ANY
, "size_min", " size_min %u",
6206 resource
->size_min
);
6207 pr_out_u64(dl
, "size_max", resource
->size_max
);
6208 print_uint(PRINT_ANY
, "size_gran", " size_gran %u",
6209 resource
->size_gran
);
6212 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
)
6213 if (table
->resource_id
== resource
->id
&&
6214 table
->resource_valid
)
6218 pr_out_array_start(dl
, "dpipe_tables");
6220 print_string(PRINT_ANY
, "dpipe_tables", " dpipe_tables none",
6223 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
) {
6224 if (table
->resource_id
!= resource
->id
||
6225 !table
->resource_valid
)
6227 pr_out_entry_start(dl
);
6228 check_indent_newline(dl
);
6229 print_string(PRINT_ANY
, "table_name", "table_name %s",
6231 pr_out_entry_end(dl
);
6234 pr_out_array_end(dl
);
6236 if (list_empty(&resource
->resource_list
))
6239 if (ctx
->pending_change
) {
6240 check_indent_newline(dl
);
6241 print_string(PRINT_ANY
, "size_valid", "size_valid %s",
6242 resource
->size_valid
? "true" : "false");
6244 pr_out_array_start(dl
, "resources");
6245 list_for_each_entry(child_resource
, &resource
->resource_list
, list
) {
6246 pr_out_entry_start(dl
);
6247 resource_show(child_resource
, ctx
);
6248 pr_out_entry_end(dl
);
6250 pr_out_array_end(dl
);
6254 resources_show(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6256 struct resources
*resources
= ctx
->resources
;
6257 struct resource
*resource
;
6259 list_for_each_entry(resource
, &resources
->resource_list
, list
) {
6260 pr_out_handle_start_arr(ctx
->dl
, tb
);
6261 resource_show(resource
, ctx
);
6262 pr_out_handle_end(ctx
->dl
);
6266 static int resources_get(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6268 return resource_get(ctx
, NULL
, NULL
, tb
[DEVLINK_ATTR_RESOURCE_LIST
]);
6271 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
6273 struct resource_ctx
*ctx
= data
;
6274 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6275 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6278 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6279 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6280 !tb
[DEVLINK_ATTR_RESOURCE_LIST
])
6281 return MNL_CB_ERROR
;
6283 err
= resources_get(ctx
, tb
);
6286 return MNL_CB_ERROR
;
6289 if (ctx
->print_resources
)
6290 resources_show(ctx
, tb
);
6295 static int cmd_resource_show(struct dl
*dl
)
6297 struct nlmsghdr
*nlh
;
6298 struct dpipe_ctx dpipe_ctx
= {};
6299 struct resource_ctx resource_ctx
= {};
6302 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, 0);
6306 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
,
6308 dl_opts_put(nlh
, dl
);
6310 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
6314 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
,
6317 pr_err("error get tables %s\n", strerror(dpipe_ctx
.err
));
6321 err
= resource_ctx_init(&resource_ctx
, dl
);
6325 resource_ctx
.print_resources
= true;
6326 resource_ctx
.tables
= dpipe_ctx
.tables
;
6327 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6328 NLM_F_REQUEST
| NLM_F_ACK
);
6329 dl_opts_put(nlh
, dl
);
6330 pr_out_section_start(dl
, "resources");
6331 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
6333 pr_out_section_end(dl
);
6334 resource_ctx_fini(&resource_ctx
);
6336 dpipe_ctx_fini(&dpipe_ctx
);
6340 static void cmd_resource_help(void)
6342 pr_err("Usage: devlink resource show DEV\n"
6343 " devlink resource set DEV path PATH size SIZE\n");
6346 static struct resource
*
6347 resource_find_by_name(struct list_head
*list
, char *name
)
6349 struct resource
*resource
;
6351 list_for_each_entry(resource
, list
, list
) {
6352 if (!strcmp(resource
->name
, name
))
6359 resource_path_parse(struct resource_ctx
*ctx
, const char *resource_path
,
6360 uint32_t *p_resource_id
, bool *p_resource_valid
)
6362 struct resource
*resource
;
6363 uint32_t resource_id
= 0;
6364 char *resource_path_dup
;
6365 struct list_head
*list
;
6366 const char del
[] = "/";
6367 char *resource_name
;
6369 resource_path_dup
= strdup(resource_path
);
6370 list
= &ctx
->resources
->resource_list
;
6371 resource_name
= strtok(resource_path_dup
, del
);
6372 while (resource_name
!= NULL
) {
6373 resource
= resource_find_by_name(list
, resource_name
);
6375 goto err_resource_lookup
;
6377 list
= &resource
->resource_list
;
6378 resource_name
= strtok(NULL
, del
);
6379 resource_id
= resource
->id
;
6381 free(resource_path_dup
);
6382 *p_resource_valid
= true;
6383 *p_resource_id
= resource_id
;
6386 err_resource_lookup
:
6387 free(resource_path_dup
);
6391 static int cmd_resource_set(struct dl
*dl
)
6393 struct nlmsghdr
*nlh
;
6394 struct resource_ctx ctx
= {};
6397 err
= resource_ctx_init(&ctx
, dl
);
6401 ctx
.print_resources
= false;
6402 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_RESOURCE_PATH
|
6403 DL_OPT_RESOURCE_SIZE
, 0);
6407 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6409 dl_opts_put(nlh
, dl
);
6410 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
, &ctx
);
6412 pr_err("error getting resources %s\n", strerror(ctx
.err
));
6416 err
= resource_path_parse(&ctx
, dl
->opts
.resource_path
,
6417 &dl
->opts
.resource_id
,
6418 &dl
->opts
.resource_id_valid
);
6420 pr_err("error parsing resource path %s\n", strerror(-err
));
6424 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_SET
,
6425 NLM_F_REQUEST
| NLM_F_ACK
);
6427 dl_opts_put(nlh
, dl
);
6428 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6430 resource_ctx_fini(&ctx
);
6434 static int cmd_resource(struct dl
*dl
)
6436 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6437 cmd_resource_help();
6439 } else if (dl_argv_match(dl
, "show")) {
6441 return cmd_resource_show(dl
);
6442 } else if (dl_argv_match(dl
, "set")) {
6444 return cmd_resource_set(dl
);
6446 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6450 static void pr_out_region_handle_start(struct dl
*dl
, struct nlattr
**tb
)
6452 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
6453 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
6454 const char *region_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_REGION_NAME
]);
6457 sprintf(buf
, "%s/%s/%s", bus_name
, dev_name
, region_name
);
6458 if (dl
->json_output
)
6459 open_json_object(buf
);
6464 static void pr_out_region_handle_end(struct dl
*dl
)
6466 if (dl
->json_output
)
6467 close_json_object();
6472 static void pr_out_region_snapshots_start(struct dl
*dl
, bool array
)
6474 __pr_out_indent_newline(dl
);
6475 if (dl
->json_output
)
6476 open_json_array(PRINT_JSON
, "snapshot");
6478 pr_out("snapshot %s", array
? "[" : "");
6481 static void pr_out_region_snapshots_end(struct dl
*dl
, bool array
)
6483 if (dl
->json_output
)
6484 close_json_array(PRINT_JSON
, NULL
);
6489 static void pr_out_region_snapshots_id(struct dl
*dl
, struct nlattr
**tb
, int index
)
6491 uint32_t snapshot_id
;
6493 if (!tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6496 snapshot_id
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
]);
6498 if (dl
->json_output
)
6499 print_uint(PRINT_JSON
, NULL
, NULL
, snapshot_id
);
6501 pr_out("%s%u", index
? " " : "", snapshot_id
);
6504 static void pr_out_snapshots(struct dl
*dl
, struct nlattr
**tb
)
6506 struct nlattr
*tb_snapshot
[DEVLINK_ATTR_MAX
+ 1] = {};
6507 struct nlattr
*nla_sanpshot
;
6510 pr_out_region_snapshots_start(dl
, true);
6511 mnl_attr_for_each_nested(nla_sanpshot
, tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
]) {
6512 err
= mnl_attr_parse_nested(nla_sanpshot
, attr_cb
, tb_snapshot
);
6513 if (err
!= MNL_CB_OK
)
6515 pr_out_region_snapshots_id(dl
, tb_snapshot
, index
++);
6517 pr_out_region_snapshots_end(dl
, true);
6520 static void pr_out_snapshot(struct dl
*dl
, struct nlattr
**tb
)
6522 pr_out_region_snapshots_start(dl
, false);
6523 pr_out_region_snapshots_id(dl
, tb
, 0);
6524 pr_out_region_snapshots_end(dl
, false);
6527 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
)
6529 pr_out_region_handle_start(dl
, tb
);
6531 if (tb
[DEVLINK_ATTR_REGION_SIZE
])
6532 pr_out_u64(dl
, "size",
6533 mnl_attr_get_u64(tb
[DEVLINK_ATTR_REGION_SIZE
]));
6535 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
])
6536 pr_out_snapshots(dl
, tb
);
6538 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6539 pr_out_snapshot(dl
, tb
);
6541 pr_out_region_handle_end(dl
);
6544 static int cmd_region_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6546 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6547 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6548 struct dl
*dl
= data
;
6550 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6551 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6552 !tb
[DEVLINK_ATTR_REGION_NAME
] || !tb
[DEVLINK_ATTR_REGION_SIZE
])
6553 return MNL_CB_ERROR
;
6555 pr_out_region(dl
, tb
);
6560 static int cmd_region_show(struct dl
*dl
)
6562 struct nlmsghdr
*nlh
;
6563 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6566 if (dl_argc(dl
) == 0)
6567 flags
|= NLM_F_DUMP
;
6569 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_GET
, flags
);
6571 if (dl_argc(dl
) > 0) {
6572 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
, 0);
6577 pr_out_section_start(dl
, "regions");
6578 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_show_cb
, dl
);
6579 pr_out_section_end(dl
);
6583 static int cmd_region_snapshot_del(struct dl
*dl
)
6585 struct nlmsghdr
*nlh
;
6588 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_DEL
,
6589 NLM_F_REQUEST
| NLM_F_ACK
);
6591 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6592 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6596 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6599 static int cmd_region_read_cb(const struct nlmsghdr
*nlh
, void *data
)
6601 struct nlattr
*nla_entry
, *nla_chunk_data
, *nla_chunk_addr
;
6602 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6603 struct nlattr
*tb_field
[DEVLINK_ATTR_MAX
+ 1] = {};
6604 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6605 struct dl
*dl
= data
;
6608 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6609 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6610 !tb
[DEVLINK_ATTR_REGION_CHUNKS
])
6611 return MNL_CB_ERROR
;
6613 mnl_attr_for_each_nested(nla_entry
, tb
[DEVLINK_ATTR_REGION_CHUNKS
]) {
6614 err
= mnl_attr_parse_nested(nla_entry
, attr_cb
, tb_field
);
6615 if (err
!= MNL_CB_OK
)
6616 return MNL_CB_ERROR
;
6618 nla_chunk_data
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_DATA
];
6619 if (!nla_chunk_data
)
6622 nla_chunk_addr
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_ADDR
];
6623 if (!nla_chunk_addr
)
6626 pr_out_region_chunk(dl
, mnl_attr_get_payload(nla_chunk_data
),
6627 mnl_attr_get_payload_len(nla_chunk_data
),
6628 mnl_attr_get_u64(nla_chunk_addr
));
6633 static int cmd_region_dump(struct dl
*dl
)
6635 struct nlmsghdr
*nlh
;
6638 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6639 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6641 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6642 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6646 pr_out_section_start(dl
, "dump");
6647 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6648 pr_out_section_end(dl
);
6649 if (!dl
->json_output
)
6654 static int cmd_region_read(struct dl
*dl
)
6656 struct nlmsghdr
*nlh
;
6659 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6660 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6662 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6663 DL_OPT_REGION_ADDRESS
| DL_OPT_REGION_LENGTH
|
6664 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6668 pr_out_section_start(dl
, "read");
6669 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6670 pr_out_section_end(dl
);
6671 if (!dl
->json_output
)
6676 static int cmd_region_snapshot_new_cb(const struct nlmsghdr
*nlh
, void *data
)
6678 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6679 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6680 struct dl
*dl
= data
;
6682 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6683 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6684 !tb
[DEVLINK_ATTR_REGION_NAME
] ||
6685 !tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6686 return MNL_CB_ERROR
;
6688 pr_out_region(dl
, tb
);
6693 static int cmd_region_snapshot_new(struct dl
*dl
)
6695 struct nlmsghdr
*nlh
;
6698 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_NEW
,
6699 NLM_F_REQUEST
| NLM_F_ACK
);
6701 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
,
6702 DL_OPT_REGION_SNAPSHOT_ID
);
6706 pr_out_section_start(dl
, "regions");
6707 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_snapshot_new_cb
, dl
);
6708 pr_out_section_end(dl
);
6712 static void cmd_region_help(void)
6714 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
6715 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
6716 pr_err(" devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
6717 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
6718 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
6721 static int cmd_region(struct dl
*dl
)
6723 if (dl_no_arg(dl
)) {
6724 return cmd_region_show(dl
);
6725 } else if (dl_argv_match(dl
, "help")) {
6728 } else if (dl_argv_match(dl
, "show")) {
6730 return cmd_region_show(dl
);
6731 } else if (dl_argv_match(dl
, "del")) {
6733 return cmd_region_snapshot_del(dl
);
6734 } else if (dl_argv_match(dl
, "dump")) {
6736 return cmd_region_dump(dl
);
6737 } else if (dl_argv_match(dl
, "read")) {
6739 return cmd_region_read(dl
);
6740 } else if (dl_argv_match(dl
, "new")) {
6742 return cmd_region_snapshot_new(dl
);
6744 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6748 static int cmd_health_set_params(struct dl
*dl
)
6750 struct nlmsghdr
*nlh
;
6753 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_SET
,
6754 NLM_F_REQUEST
| NLM_F_ACK
);
6755 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
| DL_OPT_HEALTH_REPORTER_NAME
,
6756 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
|
6757 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
|
6758 DL_OPT_HEALTH_REPORTER_AUTO_DUMP
);
6762 dl_opts_put(nlh
, dl
);
6763 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6766 static int cmd_health_dump_clear(struct dl
*dl
)
6768 struct nlmsghdr
*nlh
;
6771 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR
,
6772 NLM_F_REQUEST
| NLM_F_ACK
);
6774 err
= dl_argv_parse_put(nlh
, dl
,
6775 DL_OPT_HANDLE
| DL_OPT_HANDLEP
|
6776 DL_OPT_HEALTH_REPORTER_NAME
, 0);
6780 dl_opts_put(nlh
, dl
);
6781 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6784 static int fmsg_value_show(struct dl
*dl
, int type
, struct nlattr
*nl_data
)
6789 check_indent_newline(dl
);
6792 print_bool(PRINT_ANY
, NULL
, "%s", mnl_attr_get_u8(nl_data
));
6795 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u8(nl_data
));
6798 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u16(nl_data
));
6801 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u32(nl_data
));
6804 print_u64(PRINT_ANY
, NULL
, "%"PRIu64
, mnl_attr_get_u64(nl_data
));
6806 case MNL_TYPE_NUL_STRING
:
6807 print_string(PRINT_ANY
, NULL
, "%s", mnl_attr_get_str(nl_data
));
6809 case MNL_TYPE_BINARY
:
6810 len
= mnl_attr_get_payload_len(nl_data
);
6811 data
= mnl_attr_get_payload(nl_data
);
6812 pr_out_binary_value(dl
, data
, len
);
6820 static void pr_out_fmsg_name(struct dl
*dl
, char **name
)
6825 pr_out_name(dl
, *name
);
6832 struct list_head list
;
6835 struct fmsg_cb_data
{
6839 struct list_head entry_list
;
6842 static int cmd_fmsg_nest_queue(struct fmsg_cb_data
*fmsg_data
,
6843 uint8_t *attr_value
, bool insert
)
6845 struct nest_entry
*entry
;
6848 entry
= malloc(sizeof(struct nest_entry
));
6852 entry
->attr_type
= *attr_value
;
6853 list_add(&entry
->list
, &fmsg_data
->entry_list
);
6855 if (list_empty(&fmsg_data
->entry_list
))
6856 return MNL_CB_ERROR
;
6857 entry
= list_first_entry(&fmsg_data
->entry_list
,
6858 struct nest_entry
, list
);
6859 *attr_value
= entry
->attr_type
;
6860 list_del(&entry
->list
);
6866 static void pr_out_fmsg_group_start(struct dl
*dl
, char **name
)
6869 pr_out_fmsg_name(dl
, name
);
6871 __pr_out_indent_inc();
6874 static void pr_out_fmsg_group_end(struct dl
*dl
)
6877 __pr_out_indent_dec();
6880 static void pr_out_fmsg_start_object(struct dl
*dl
, char **name
)
6882 if (dl
->json_output
) {
6883 pr_out_fmsg_name(dl
, name
);
6884 open_json_object(NULL
);
6886 pr_out_fmsg_group_start(dl
, name
);
6890 static void pr_out_fmsg_end_object(struct dl
*dl
)
6892 if (dl
->json_output
)
6893 close_json_object();
6895 pr_out_fmsg_group_end(dl
);
6898 static void pr_out_fmsg_start_array(struct dl
*dl
, char **name
)
6900 if (dl
->json_output
) {
6901 pr_out_fmsg_name(dl
, name
);
6902 open_json_array(PRINT_JSON
, NULL
);
6904 pr_out_fmsg_group_start(dl
, name
);
6908 static void pr_out_fmsg_end_array(struct dl
*dl
)
6910 if (dl
->json_output
)
6911 close_json_array(PRINT_JSON
, NULL
);
6913 pr_out_fmsg_group_end(dl
);
6916 static int cmd_fmsg_nest(struct fmsg_cb_data
*fmsg_data
, uint8_t nest_value
,
6919 struct dl
*dl
= fmsg_data
->dl
;
6920 uint8_t value
= nest_value
;
6923 err
= cmd_fmsg_nest_queue(fmsg_data
, &value
, start
);
6924 if (err
!= MNL_CB_OK
)
6928 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6930 pr_out_fmsg_start_object(dl
, &fmsg_data
->name
);
6932 pr_out_fmsg_end_object(dl
);
6934 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6936 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6938 pr_out_fmsg_start_array(dl
, &fmsg_data
->name
);
6940 pr_out_fmsg_end_array(dl
);
6948 static int cmd_fmsg_object_cb(const struct nlmsghdr
*nlh
, void *data
)
6950 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6951 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6952 struct fmsg_cb_data
*fmsg_data
= data
;
6953 struct dl
*dl
= fmsg_data
->dl
;
6954 struct nlattr
*nla_object
;
6958 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6959 if (!tb
[DEVLINK_ATTR_FMSG
])
6960 return MNL_CB_ERROR
;
6962 mnl_attr_for_each_nested(nla_object
, tb
[DEVLINK_ATTR_FMSG
]) {
6963 attr_type
= mnl_attr_get_type(nla_object
);
6964 switch (attr_type
) {
6965 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6966 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6967 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6968 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, true);
6969 if (err
!= MNL_CB_OK
)
6972 case DEVLINK_ATTR_FMSG_NEST_END
:
6973 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, false);
6974 if (err
!= MNL_CB_OK
)
6977 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
6978 free(fmsg_data
->name
);
6979 fmsg_data
->name
= strdup(mnl_attr_get_str(nla_object
));
6980 if (!fmsg_data
->name
)
6983 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
:
6984 fmsg_data
->value_type
= mnl_attr_get_u8(nla_object
);
6986 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
6987 pr_out_fmsg_name(dl
, &fmsg_data
->name
);
6988 err
= fmsg_value_show(dl
, fmsg_data
->value_type
,
6990 if (err
!= MNL_CB_OK
)
7000 static void cmd_fmsg_init(struct dl
*dl
, struct fmsg_cb_data
*data
)
7002 /* FMSG is dynamic: opening of an object or array causes a
7003 * newline. JSON starts with an { or [, but plain text should
7004 * not start with a new line. Ensure this by setting
7005 * g_new_line_count to 1: avoiding newline before the first
7008 g_new_line_count
= 1;
7011 INIT_LIST_HEAD(&data
->entry_list
);
7014 static int cmd_health_object_common(struct dl
*dl
, uint8_t cmd
, uint16_t flags
)
7016 struct fmsg_cb_data data
;
7017 struct nlmsghdr
*nlh
;
7020 nlh
= mnlg_msg_prepare(dl
->nlg
, cmd
, flags
| NLM_F_REQUEST
| NLM_F_ACK
);
7022 err
= dl_argv_parse_put(nlh
, dl
,
7023 DL_OPT_HANDLE
| DL_OPT_HANDLEP
|
7024 DL_OPT_HEALTH_REPORTER_NAME
, 0);
7028 cmd_fmsg_init(dl
, &data
);
7029 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_fmsg_object_cb
, &data
);
7034 static int cmd_health_dump_show(struct dl
*dl
)
7036 return cmd_health_object_common(dl
,
7037 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
,
7041 static int cmd_health_diagnose(struct dl
*dl
)
7043 return cmd_health_object_common(dl
,
7044 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
,
7048 static int cmd_health_recover(struct dl
*dl
)
7050 struct nlmsghdr
*nlh
;
7053 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
,
7054 NLM_F_REQUEST
| NLM_F_ACK
);
7056 err
= dl_argv_parse_put(nlh
, dl
,
7057 DL_OPT_HANDLE
| DL_OPT_HANDLEP
|
7058 DL_OPT_HEALTH_REPORTER_NAME
, 0);
7062 dl_opts_put(nlh
, dl
);
7063 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7066 enum devlink_health_reporter_state
{
7067 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
,
7068 DEVLINK_HEALTH_REPORTER_STATE_ERROR
,
7071 static const char *health_state_name(uint8_t state
)
7074 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
:
7075 return HEALTH_REPORTER_STATE_HEALTHY_STR
;
7076 case DEVLINK_HEALTH_REPORTER_STATE_ERROR
:
7077 return HEALTH_REPORTER_STATE_ERROR_STR
;
7079 return "<unknown state>";
7083 static void pr_out_dump_reporter_format_logtime(struct dl
*dl
, const struct nlattr
*attr
)
7085 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7086 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7087 uint64_t time_ms
= mnl_attr_get_u64(attr
);
7088 struct sysinfo s_info
;
7094 info
= localtime(&now
);
7095 err
= sysinfo(&s_info
);
7098 /* Subtract uptime in sec from now yields the time of system
7099 * uptime. To this, add time_ms which is the amount of
7100 * milliseconds elapsed between uptime and the dump taken.
7102 sec
= now
- s_info
.uptime
+ time_ms
/ 1000;
7103 info
= localtime(&sec
);
7105 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", info
);
7106 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", info
);
7107 check_indent_newline(dl
);
7108 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
7109 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
7112 static void pr_out_dump_report_timestamp(struct dl
*dl
, const struct nlattr
*attr
)
7114 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7115 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7120 ts
= mnl_attr_get_u64(attr
);
7121 tv_sec
= ts
/ 1000000000;
7122 tm
= localtime(&tv_sec
);
7124 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", tm
);
7125 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", tm
);
7127 check_indent_newline(dl
);
7128 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
7129 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
7132 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
,
7133 bool print_device
, bool print_port
)
7135 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7136 enum devlink_health_reporter_state state
;
7139 err
= mnl_attr_parse_nested(tb_health
[DEVLINK_ATTR_HEALTH_REPORTER
],
7141 if (err
!= MNL_CB_OK
)
7144 if (!tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
] ||
7145 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] ||
7146 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] ||
7147 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
])
7150 if (!print_device
&& !print_port
)
7153 if (!print_device
&& !tb_health
[DEVLINK_ATTR_PORT_INDEX
])
7155 else if (tb_health
[DEVLINK_ATTR_PORT_INDEX
])
7156 pr_out_port_handle_start_arr(dl
, tb_health
, false);
7159 if (!print_port
&& tb_health
[DEVLINK_ATTR_PORT_INDEX
])
7161 else if (!tb_health
[DEVLINK_ATTR_PORT_INDEX
])
7162 pr_out_handle_start_arr(dl
, tb_health
);
7165 check_indent_newline(dl
);
7166 print_string(PRINT_ANY
, "reporter", "reporter %s",
7167 mnl_attr_get_str(tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]));
7168 if (!dl
->json_output
) {
7170 __pr_out_indent_inc();
7172 state
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
]);
7173 check_indent_newline(dl
);
7174 print_string(PRINT_ANY
, "state", "state %s", health_state_name(state
));
7175 pr_out_u64(dl
, "error",
7176 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
]));
7177 pr_out_u64(dl
, "recover",
7178 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
]));
7179 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
])
7180 pr_out_dump_report_timestamp(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
]);
7181 else if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
])
7182 pr_out_dump_reporter_format_logtime(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
]);
7183 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
7184 pr_out_u64(dl
, "grace_period",
7185 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]));
7186 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
7187 print_bool(PRINT_ANY
, "auto_recover", " auto_recover %s",
7188 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]));
7189 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
])
7190 print_bool(PRINT_ANY
, "auto_dump", " auto_dump %s",
7191 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
]));
7193 __pr_out_indent_dec();
7194 pr_out_handle_end(dl
);
7203 static int cmd_health_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7205 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7206 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7207 struct health_ctx
*ctx
= data
;
7208 struct dl
*dl
= ctx
->dl
;
7210 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7211 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7212 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
7213 return MNL_CB_ERROR
;
7215 pr_out_health(dl
, tb
, ctx
->show_device
, ctx
->show_port
);
7220 static int __cmd_health_show(struct dl
*dl
, bool show_device
, bool show_port
)
7222 struct nlmsghdr
*nlh
;
7223 struct health_ctx ctx
= { dl
, show_device
, show_port
};
7224 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7227 if (dl_argc(dl
) == 0)
7228 flags
|= NLM_F_DUMP
;
7229 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_GET
,
7232 if (dl_argc(dl
) > 0) {
7233 ctx
.show_port
= true;
7234 err
= dl_argv_parse_put(nlh
, dl
,
7235 DL_OPT_HANDLE
| DL_OPT_HANDLEP
|
7236 DL_OPT_HEALTH_REPORTER_NAME
, 0);
7240 pr_out_section_start(dl
, "health");
7242 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_health_show_cb
, &ctx
);
7243 pr_out_section_end(dl
);
7247 static void cmd_health_help(void)
7249 pr_err("Usage: devlink health show [ { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME ]\n");
7250 pr_err(" devlink health recover { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7251 pr_err(" devlink health diagnose { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7252 pr_err(" devlink health dump show { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7253 pr_err(" devlink health dump clear { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7254 pr_err(" devlink health set { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7255 pr_err(" [ grace_period MSEC ]\n");
7256 pr_err(" [ auto_recover { true | false } ]\n");
7257 pr_err(" [ auto_dump { true | false } ]\n");
7260 static int cmd_health(struct dl
*dl
)
7262 if (dl_argv_match(dl
, "help")) {
7265 } else if (dl_argv_match(dl
, "show") ||
7266 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7268 return __cmd_health_show(dl
, true, true);
7269 } else if (dl_argv_match(dl
, "recover")) {
7271 return cmd_health_recover(dl
);
7272 } else if (dl_argv_match(dl
, "diagnose")) {
7274 return cmd_health_diagnose(dl
);
7275 } else if (dl_argv_match(dl
, "dump")) {
7277 if (dl_argv_match(dl
, "show")) {
7279 return cmd_health_dump_show(dl
);
7280 } else if (dl_argv_match(dl
, "clear")) {
7282 return cmd_health_dump_clear(dl
);
7284 } else if (dl_argv_match(dl
, "set")) {
7286 return cmd_health_set_params(dl
);
7288 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7292 static const char *trap_type_name(uint8_t type
)
7295 case DEVLINK_TRAP_TYPE_DROP
:
7297 case DEVLINK_TRAP_TYPE_EXCEPTION
:
7299 case DEVLINK_TRAP_TYPE_CONTROL
:
7302 return "<unknown type>";
7306 static const char *trap_action_name(uint8_t action
)
7309 case DEVLINK_TRAP_ACTION_DROP
:
7311 case DEVLINK_TRAP_ACTION_TRAP
:
7313 case DEVLINK_TRAP_ACTION_MIRROR
:
7316 return "<unknown action>";
7320 static const char *trap_metadata_name(const struct nlattr
*attr
)
7322 switch (attr
->nla_type
) {
7323 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT
:
7324 return "input_port";
7325 case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE
:
7326 return "flow_action_cookie";
7328 return "<unknown metadata type>";
7331 static void pr_out_trap_metadata(struct dl
*dl
, struct nlattr
*attr
)
7333 struct nlattr
*attr_metadata
;
7335 pr_out_array_start(dl
, "metadata");
7336 mnl_attr_for_each_nested(attr_metadata
, attr
) {
7337 check_indent_newline(dl
);
7338 print_string(PRINT_ANY
, NULL
, "%s",
7339 trap_metadata_name(attr_metadata
));
7341 pr_out_array_end(dl
);
7344 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7346 uint8_t action
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_ACTION
]);
7347 uint8_t type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_TYPE
]);
7350 pr_out_handle_start_arr(dl
, tb
);
7352 __pr_out_handle_start(dl
, tb
, true, false);
7354 check_indent_newline(dl
);
7355 print_string(PRINT_ANY
, "name", "name %s",
7356 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_NAME
]));
7357 print_string(PRINT_ANY
, "type", " type %s", trap_type_name(type
));
7358 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7359 print_string(PRINT_ANY
, "action", " action %s", trap_action_name(action
));
7360 print_string(PRINT_ANY
, "group", " group %s",
7361 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7363 pr_out_trap_metadata(dl
, tb
[DEVLINK_ATTR_TRAP_METADATA
]);
7364 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7365 pr_out_handle_end(dl
);
7368 static int cmd_trap_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7370 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7371 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7372 struct dl
*dl
= data
;
7374 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7375 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7376 !tb
[DEVLINK_ATTR_TRAP_NAME
] || !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
7377 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
7378 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
7379 !tb
[DEVLINK_ATTR_TRAP_METADATA
] || !tb
[DEVLINK_ATTR_STATS
])
7380 return MNL_CB_ERROR
;
7382 pr_out_trap(dl
, tb
, true);
7387 static void cmd_trap_help(void)
7389 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop | mirror } ]\n");
7390 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
7391 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop | mirror } ]\n");
7392 pr_err(" [ policer POLICER ] [ nopolicer ]\n");
7393 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
7394 pr_err(" devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
7395 pr_err(" devlink trap policer show DEV policer POLICER\n");
7398 static int cmd_trap_show(struct dl
*dl
)
7400 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7401 struct nlmsghdr
*nlh
;
7404 if (dl_argc(dl
) == 0)
7405 flags
|= NLM_F_DUMP
;
7407 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GET
, flags
);
7409 if (dl_argc(dl
) > 0) {
7410 err
= dl_argv_parse_put(nlh
, dl
,
7411 DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
, 0);
7416 pr_out_section_start(dl
, "trap");
7417 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_show_cb
, dl
);
7418 pr_out_section_end(dl
);
7423 static int cmd_trap_set(struct dl
*dl
)
7425 struct nlmsghdr
*nlh
;
7428 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_SET
,
7429 NLM_F_REQUEST
| NLM_F_ACK
);
7431 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
,
7432 DL_OPT_TRAP_ACTION
);
7436 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7439 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7442 pr_out_handle_start_arr(dl
, tb
);
7444 __pr_out_handle_start(dl
, tb
, true, false);
7446 check_indent_newline(dl
);
7447 print_string(PRINT_ANY
, "name", "name %s",
7448 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7449 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7450 if (tb
[DEVLINK_ATTR_TRAP_POLICER_ID
])
7451 print_uint(PRINT_ANY
, "policer", " policer %u",
7452 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7453 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7454 pr_out_handle_end(dl
);
7457 static int cmd_trap_group_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7459 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7460 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7461 struct dl
*dl
= data
;
7463 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7464 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7465 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] || !tb
[DEVLINK_ATTR_STATS
])
7466 return MNL_CB_ERROR
;
7468 pr_out_trap_group(dl
, tb
, true);
7473 static int cmd_trap_group_show(struct dl
*dl
)
7475 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7476 struct nlmsghdr
*nlh
;
7479 if (dl_argc(dl
) == 0)
7480 flags
|= NLM_F_DUMP
;
7482 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_GET
, flags
);
7484 if (dl_argc(dl
) > 0) {
7485 err
= dl_argv_parse_put(nlh
, dl
,
7486 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7492 pr_out_section_start(dl
, "trap_group");
7493 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_group_show_cb
, dl
);
7494 pr_out_section_end(dl
);
7499 static int cmd_trap_group_set(struct dl
*dl
)
7501 struct nlmsghdr
*nlh
;
7504 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_SET
,
7505 NLM_F_REQUEST
| NLM_F_ACK
);
7507 err
= dl_argv_parse_put(nlh
, dl
,
7508 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7509 DL_OPT_TRAP_ACTION
| DL_OPT_TRAP_POLICER_ID
);
7513 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7516 static int cmd_trap_group(struct dl
*dl
)
7518 if (dl_argv_match(dl
, "help")) {
7521 } else if (dl_argv_match(dl
, "show") ||
7522 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7524 return cmd_trap_group_show(dl
);
7525 } else if (dl_argv_match(dl
, "set")) {
7527 return cmd_trap_group_set(dl
);
7529 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7533 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7536 pr_out_handle_start_arr(dl
, tb
);
7538 __pr_out_handle_start(dl
, tb
, true, false);
7540 check_indent_newline(dl
);
7541 print_uint(PRINT_ANY
, "policer", "policer %u",
7542 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7543 print_u64(PRINT_ANY
, "rate", " rate %llu",
7544 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
]));
7545 print_u64(PRINT_ANY
, "burst", " burst %llu",
7546 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
]));
7547 if (tb
[DEVLINK_ATTR_STATS
])
7548 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7549 pr_out_handle_end(dl
);
7552 static int cmd_trap_policer_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7554 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7555 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7556 struct dl
*dl
= data
;
7558 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7559 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7560 !tb
[DEVLINK_ATTR_TRAP_POLICER_ID
] ||
7561 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
7562 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
7563 return MNL_CB_ERROR
;
7565 pr_out_trap_policer(dl
, tb
, true);
7570 static int cmd_trap_policer_show(struct dl
*dl
)
7572 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7573 struct nlmsghdr
*nlh
;
7576 if (dl_argc(dl
) == 0)
7577 flags
|= NLM_F_DUMP
;
7579 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_GET
, flags
);
7581 if (dl_argc(dl
) > 0) {
7582 err
= dl_argv_parse_put(nlh
, dl
,
7583 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7589 pr_out_section_start(dl
, "trap_policer");
7590 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_policer_show_cb
, dl
);
7591 pr_out_section_end(dl
);
7596 static int cmd_trap_policer_set(struct dl
*dl
)
7598 struct nlmsghdr
*nlh
;
7601 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_SET
,
7602 NLM_F_REQUEST
| NLM_F_ACK
);
7604 err
= dl_argv_parse_put(nlh
, dl
,
7605 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7606 DL_OPT_TRAP_POLICER_RATE
|
7607 DL_OPT_TRAP_POLICER_BURST
);
7611 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7614 static int cmd_trap_policer(struct dl
*dl
)
7616 if (dl_argv_match(dl
, "help")) {
7619 } else if (dl_argv_match(dl
, "show") ||
7620 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7622 return cmd_trap_policer_show(dl
);
7623 } else if (dl_argv_match(dl
, "set")) {
7625 return cmd_trap_policer_set(dl
);
7627 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7631 static int cmd_trap(struct dl
*dl
)
7633 if (dl_argv_match(dl
, "help")) {
7636 } else if (dl_argv_match(dl
, "show") ||
7637 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7639 return cmd_trap_show(dl
);
7640 } else if (dl_argv_match(dl
, "set")) {
7642 return cmd_trap_set(dl
);
7643 } else if (dl_argv_match(dl
, "group")) {
7645 return cmd_trap_group(dl
);
7646 } else if (dl_argv_match(dl
, "policer")) {
7648 return cmd_trap_policer(dl
);
7650 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7654 static void help(void)
7656 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
7657 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
7658 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
7659 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
7662 static int dl_cmd(struct dl
*dl
, int argc
, char **argv
)
7667 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
7670 } else if (dl_argv_match(dl
, "dev")) {
7673 } else if (dl_argv_match(dl
, "port")) {
7675 return cmd_port(dl
);
7676 } else if (dl_argv_match(dl
, "sb")) {
7679 } else if (dl_argv_match(dl
, "monitor")) {
7682 } else if (dl_argv_match(dl
, "dpipe")) {
7684 return cmd_dpipe(dl
);
7685 } else if (dl_argv_match(dl
, "resource")) {
7687 return cmd_resource(dl
);
7688 } else if (dl_argv_match(dl
, "region")) {
7690 return cmd_region(dl
);
7691 } else if (dl_argv_match(dl
, "health")) {
7693 return cmd_health(dl
);
7694 } else if (dl_argv_match(dl
, "trap")) {
7696 return cmd_trap(dl
);
7698 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
7702 static int dl_init(struct dl
*dl
)
7706 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
7708 pr_err("Failed to connect to devlink Netlink\n");
7712 err
= ifname_map_init(dl
);
7714 pr_err("Failed to create index map\n");
7715 goto err_ifname_map_create
;
7717 new_json_obj_plain(dl
->json_output
);
7720 err_ifname_map_create
:
7721 mnlg_socket_close(dl
->nlg
);
7725 static void dl_fini(struct dl
*dl
)
7727 delete_json_obj_plain();
7728 ifname_map_fini(dl
);
7729 mnlg_socket_close(dl
->nlg
);
7732 static struct dl
*dl_alloc(void)
7736 dl
= calloc(1, sizeof(*dl
));
7742 static void dl_free(struct dl
*dl
)
7747 static int dl_batch(struct dl
*dl
, const char *name
, bool force
)
7751 int ret
= EXIT_SUCCESS
;
7753 if (name
&& strcmp(name
, "-") != 0) {
7754 if (freopen(name
, "r", stdin
) == NULL
) {
7756 "Cannot open file \"%s\" for reading: %s\n",
7757 name
, strerror(errno
));
7758 return EXIT_FAILURE
;
7763 while (getcmdline(&line
, &len
, stdin
) != -1) {
7767 largc
= makeargs(line
, largv
, 100);
7769 continue; /* blank line */
7771 if (dl_cmd(dl
, largc
, largv
)) {
7772 fprintf(stderr
, "Command failed %s:%d\n",
7786 int main(int argc
, char **argv
)
7788 static const struct option long_options
[] = {
7789 { "Version", no_argument
, NULL
, 'V' },
7790 { "force", no_argument
, NULL
, 'f' },
7791 { "batch", required_argument
, NULL
, 'b' },
7792 { "no-nice-names", no_argument
, NULL
, 'n' },
7793 { "json", no_argument
, NULL
, 'j' },
7794 { "pretty", no_argument
, NULL
, 'p' },
7795 { "verbose", no_argument
, NULL
, 'v' },
7796 { "statistics", no_argument
, NULL
, 's' },
7797 { "Netns", required_argument
, NULL
, 'N' },
7798 { NULL
, 0, NULL
, 0 }
7800 const char *batch_file
= NULL
;
7809 pr_err("Failed to allocate memory for devlink\n");
7810 return EXIT_FAILURE
;
7813 while ((opt
= getopt_long(argc
, argv
, "Vfb:njpvsN:",
7814 long_options
, NULL
)) >= 0) {
7818 printf("devlink utility, iproute2-%s\n", version
);
7825 batch_file
= optarg
;
7828 dl
->no_nice_names
= true;
7831 dl
->json_output
= true;
7843 if (netns_switch(optarg
)) {
7849 pr_err("Unknown option.\n");
7866 err
= dl_batch(dl
, batch_file
, force
);
7868 err
= dl_cmd(dl
, argc
, argv
);