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>
22 #include <sys/sysinfo.h>
23 #define _LINUX_SYSINFO_H /* avoid collision with musl header */
24 #include <linux/genetlink.h>
25 #include <linux/devlink.h>
26 #include <libmnl/libmnl.h>
27 #include <netinet/ether.h>
28 #include <sys/types.h>
34 #include "json_writer.h"
36 #include "namespace.h"
38 #define ESWITCH_MODE_LEGACY "legacy"
39 #define ESWITCH_MODE_SWITCHDEV "switchdev"
40 #define ESWITCH_INLINE_MODE_NONE "none"
41 #define ESWITCH_INLINE_MODE_LINK "link"
42 #define ESWITCH_INLINE_MODE_NETWORK "network"
43 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
45 #define ESWITCH_ENCAP_MODE_NONE "none"
46 #define ESWITCH_ENCAP_MODE_BASIC "basic"
48 #define PARAM_CMODE_RUNTIME_STR "runtime"
49 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
50 #define PARAM_CMODE_PERMANENT_STR "permanent"
51 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
53 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
54 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
55 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
57 static int g_new_line_count
;
58 static int g_indent_level
;
59 static bool g_indent_newline
;
61 #define INDENT_STR_STEP 2
62 #define INDENT_STR_MAXLEN 32
63 static char g_indent_str
[INDENT_STR_MAXLEN
+ 1] = "";
65 static void __attribute__((format(printf
, 1, 2)))
66 pr_err(const char *fmt
, ...)
71 vfprintf(stderr
, fmt
, ap
);
75 static void __attribute__((format(printf
, 1, 2)))
76 pr_out(const char *fmt
, ...)
80 if (g_indent_newline
) {
81 printf("%s", g_indent_str
);
82 g_indent_newline
= false;
90 static void __attribute__((format(printf
, 2, 3)))
91 pr_out_sp(unsigned int num
, const char *fmt
, ...)
97 ret
= vprintf(fmt
, ap
);
101 printf("%*s", num
- ret
, "");
102 g_new_line_count
= 0; \
105 static void __attribute__((format(printf
, 1, 2)))
106 pr_out_tty(const char *fmt
, ...)
110 if (!isatty(STDOUT_FILENO
))
117 static void __pr_out_indent_inc(void)
119 if (g_indent_level
+ INDENT_STR_STEP
> INDENT_STR_MAXLEN
)
121 g_indent_level
+= INDENT_STR_STEP
;
122 memset(g_indent_str
, ' ', sizeof(g_indent_str
));
123 g_indent_str
[g_indent_level
] = '\0';
126 static void __pr_out_indent_dec(void)
128 if (g_indent_level
- INDENT_STR_STEP
< 0)
130 g_indent_level
-= INDENT_STR_STEP
;
131 g_indent_str
[g_indent_level
] = '\0';
134 static void __pr_out_newline(void)
136 if (g_new_line_count
< 1) {
138 g_indent_newline
= true;
143 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
144 mnl_cb_t data_cb
, void *data
)
148 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
150 pr_err("devlink answers: %s\n", strerror(errno
));
156 static void dummy_signal_handler(int signum
)
160 static int _mnlg_socket_recv_run_intr(struct mnlg_socket
*nlg
,
161 mnl_cb_t data_cb
, void *data
)
163 struct sigaction act
, oact
;
166 act
.sa_handler
= dummy_signal_handler
;
167 sigemptyset(&act
.sa_mask
);
168 act
.sa_flags
= SA_NODEFER
;
170 sigaction(SIGINT
, &act
, &oact
);
171 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
172 sigaction(SIGINT
, &oact
, NULL
);
173 if (err
< 0 && errno
!= EINTR
) {
174 pr_err("devlink answers: %s\n", strerror(errno
));
180 static int _mnlg_socket_send(struct mnlg_socket
*nlg
,
181 const struct nlmsghdr
*nlh
)
185 err
= mnlg_socket_send(nlg
, nlh
);
187 pr_err("Failed to call mnlg_socket_send\n");
193 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
194 const struct nlmsghdr
*nlh
,
195 mnl_cb_t data_cb
, void *data
)
199 err
= _mnlg_socket_send(nlg
, nlh
);
202 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
205 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
206 const char *group_name
)
210 err
= mnlg_socket_group_add(nlg
, group_name
);
212 pr_err("Failed to call mnlg_socket_group_add\n");
219 struct list_head list
;
226 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
227 const char *dev_name
,
231 struct ifname_map
*ifname_map
;
233 ifname_map
= calloc(1, sizeof(*ifname_map
));
236 ifname_map
->bus_name
= strdup(bus_name
);
237 ifname_map
->dev_name
= strdup(dev_name
);
238 ifname_map
->port_index
= port_index
;
239 ifname_map
->ifname
= strdup(ifname
);
240 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
241 !ifname_map
->ifname
) {
242 free(ifname_map
->ifname
);
243 free(ifname_map
->dev_name
);
244 free(ifname_map
->bus_name
);
251 static void ifname_map_free(struct ifname_map
*ifname_map
)
253 free(ifname_map
->ifname
);
254 free(ifname_map
->dev_name
);
255 free(ifname_map
->bus_name
);
259 #define DL_OPT_HANDLE BIT(0)
260 #define DL_OPT_HANDLEP BIT(1)
261 #define DL_OPT_PORT_TYPE BIT(2)
262 #define DL_OPT_PORT_COUNT BIT(3)
263 #define DL_OPT_SB BIT(4)
264 #define DL_OPT_SB_POOL BIT(5)
265 #define DL_OPT_SB_SIZE BIT(6)
266 #define DL_OPT_SB_TYPE BIT(7)
267 #define DL_OPT_SB_THTYPE BIT(8)
268 #define DL_OPT_SB_TH BIT(9)
269 #define DL_OPT_SB_TC BIT(10)
270 #define DL_OPT_ESWITCH_MODE BIT(11)
271 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
272 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
273 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
274 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
275 #define DL_OPT_RESOURCE_PATH BIT(16)
276 #define DL_OPT_RESOURCE_SIZE BIT(17)
277 #define DL_OPT_PARAM_NAME BIT(18)
278 #define DL_OPT_PARAM_VALUE BIT(19)
279 #define DL_OPT_PARAM_CMODE BIT(20)
280 #define DL_OPT_HANDLE_REGION BIT(21)
281 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
282 #define DL_OPT_REGION_ADDRESS BIT(23)
283 #define DL_OPT_REGION_LENGTH BIT(24)
284 #define DL_OPT_FLASH_FILE_NAME BIT(25)
285 #define DL_OPT_FLASH_COMPONENT BIT(26)
286 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
287 #define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(28)
288 #define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(29)
289 #define DL_OPT_TRAP_NAME BIT(30)
290 #define DL_OPT_TRAP_ACTION BIT(31)
291 #define DL_OPT_TRAP_GROUP_NAME BIT(32)
292 #define DL_OPT_NETNS BIT(33)
293 #define DL_OPT_TRAP_POLICER_ID BIT(34)
294 #define DL_OPT_TRAP_POLICER_RATE BIT(35)
295 #define DL_OPT_TRAP_POLICER_BURST BIT(36)
296 #define DL_OPT_HEALTH_REPORTER_AUTO_DUMP BIT(37)
297 #define DL_OPT_PORT_FUNCTION_HW_ADDR BIT(38)
300 uint64_t present
; /* flags of present items */
304 enum devlink_port_type port_type
;
307 uint16_t sb_pool_index
;
308 uint32_t sb_pool_size
;
309 enum devlink_sb_pool_type sb_pool_type
;
310 enum devlink_sb_threshold_type sb_pool_thtype
;
311 uint32_t sb_threshold
;
312 uint16_t sb_tc_index
;
313 enum devlink_eswitch_mode eswitch_mode
;
314 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
315 const char *dpipe_table_name
;
316 bool dpipe_counters_enabled
;
317 enum devlink_eswitch_encap_mode eswitch_encap_mode
;
318 const char *resource_path
;
319 uint64_t resource_size
;
320 uint32_t resource_id
;
321 bool resource_id_valid
;
322 const char *param_name
;
323 const char *param_value
;
324 enum devlink_param_cmode cmode
;
326 uint32_t region_snapshot_id
;
327 uint64_t region_address
;
328 uint64_t region_length
;
329 const char *flash_file_name
;
330 const char *flash_component
;
331 const char *reporter_name
;
332 uint64_t reporter_graceful_period
;
333 bool reporter_auto_recover
;
334 bool reporter_auto_dump
;
335 const char *trap_name
;
336 const char *trap_group_name
;
337 enum devlink_trap_action trap_action
;
340 uint32_t trap_policer_id
;
341 uint64_t trap_policer_rate
;
342 uint64_t trap_policer_burst
;
343 char port_function_hw_addr
[MAX_ADDR_LEN
];
344 uint32_t port_function_hw_addr_len
;
348 struct mnlg_socket
*nlg
;
349 struct list_head ifname_map_list
;
366 static int dl_argc(struct dl
*dl
)
371 static char *dl_argv(struct dl
*dl
)
373 if (dl_argc(dl
) == 0)
378 static void dl_arg_inc(struct dl
*dl
)
380 if (dl_argc(dl
) == 0)
386 static void dl_arg_dec(struct dl
*dl
)
392 static char *dl_argv_next(struct dl
*dl
)
396 if (dl_argc(dl
) == 0)
404 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
406 if (index
>= dl_argc(dl
))
408 return dl
->argv
[index
];
411 static int strcmpx(const char *str1
, const char *str2
)
413 if (strlen(str1
) > strlen(str2
))
415 return strncmp(str1
, str2
, strlen(str1
));
418 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
420 if (dl_argc(dl
) == 0)
422 return strcmpx(dl_argv(dl
), pattern
) == 0;
425 static bool dl_no_arg(struct dl
*dl
)
427 return dl_argc(dl
) == 0;
430 static void __pr_out_indent_newline(struct dl
*dl
)
432 if (!g_indent_newline
&& !dl
->json_output
)
436 static bool is_binary_eol(int i
)
441 static void pr_out_binary_value(struct dl
*dl
, uint8_t *data
, uint32_t len
)
447 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
449 pr_out("%02x ", data
[i
]);
451 if (!dl
->json_output
&& is_binary_eol(i
))
454 if (!dl
->json_output
&& !is_binary_eol(i
))
458 static void pr_out_name(struct dl
*dl
, const char *name
)
460 __pr_out_indent_newline(dl
);
462 print_string(PRINT_JSON
, name
, NULL
, NULL
);
467 static void pr_out_u64(struct dl
*dl
, const char *name
, uint64_t val
)
469 __pr_out_indent_newline(dl
);
470 if (val
== (uint64_t) -1)
471 return print_string_name_value(name
, "unlimited");
474 print_u64(PRINT_JSON
, name
, NULL
, val
);
476 pr_out("%s %"PRIu64
, name
, val
);
479 static void pr_out_section_start(struct dl
*dl
, const char *name
)
481 if (dl
->json_output
) {
482 open_json_object(NULL
);
483 open_json_object(name
);
487 static void pr_out_section_end(struct dl
*dl
)
489 if (dl
->json_output
) {
490 if (dl
->arr_last
.present
)
491 close_json_array(PRINT_JSON
, NULL
);
497 static void pr_out_array_start(struct dl
*dl
, const char *name
)
499 if (dl
->json_output
) {
500 open_json_array(PRINT_JSON
, name
);
502 __pr_out_indent_inc();
505 __pr_out_indent_inc();
510 static void pr_out_array_end(struct dl
*dl
)
512 if (dl
->json_output
) {
513 close_json_array(PRINT_JSON
, NULL
);
515 __pr_out_indent_dec();
516 __pr_out_indent_dec();
520 static void pr_out_object_start(struct dl
*dl
, const char *name
)
522 if (dl
->json_output
) {
523 open_json_object(name
);
525 __pr_out_indent_inc();
528 __pr_out_indent_inc();
533 static void pr_out_object_end(struct dl
*dl
)
535 if (dl
->json_output
) {
538 __pr_out_indent_dec();
539 __pr_out_indent_dec();
543 static void pr_out_entry_start(struct dl
*dl
)
546 open_json_object(NULL
);
549 static void pr_out_entry_end(struct dl
*dl
)
557 static void check_indent_newline(struct dl
*dl
)
559 __pr_out_indent_newline(dl
);
561 if (g_indent_newline
&& !is_json_context()) {
562 printf("%s", g_indent_str
);
563 g_indent_newline
= false;
565 g_new_line_count
= 0;
568 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
569 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
570 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
571 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
572 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
573 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
574 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
575 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
576 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
577 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
578 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
579 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
580 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
581 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
582 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
583 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
584 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
585 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
586 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
587 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
588 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
589 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
590 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
591 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
592 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
593 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
594 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
595 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
596 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
597 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
598 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
599 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
600 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
601 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
602 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
603 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
604 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
605 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
606 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
607 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
608 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
609 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
610 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
611 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
612 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
613 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
614 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
615 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
616 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
617 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
618 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
619 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
620 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
621 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
622 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
623 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
624 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
625 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
626 [DEVLINK_ATTR_PARAM
] = MNL_TYPE_NESTED
,
627 [DEVLINK_ATTR_PARAM_NAME
] = MNL_TYPE_STRING
,
628 [DEVLINK_ATTR_PARAM_TYPE
] = MNL_TYPE_U8
,
629 [DEVLINK_ATTR_PARAM_VALUES_LIST
] = MNL_TYPE_NESTED
,
630 [DEVLINK_ATTR_PARAM_VALUE
] = MNL_TYPE_NESTED
,
631 [DEVLINK_ATTR_PARAM_VALUE_CMODE
] = MNL_TYPE_U8
,
632 [DEVLINK_ATTR_REGION_NAME
] = MNL_TYPE_STRING
,
633 [DEVLINK_ATTR_REGION_SIZE
] = MNL_TYPE_U64
,
634 [DEVLINK_ATTR_REGION_SNAPSHOTS
] = MNL_TYPE_NESTED
,
635 [DEVLINK_ATTR_REGION_SNAPSHOT
] = MNL_TYPE_NESTED
,
636 [DEVLINK_ATTR_REGION_SNAPSHOT_ID
] = MNL_TYPE_U32
,
637 [DEVLINK_ATTR_REGION_CHUNKS
] = MNL_TYPE_NESTED
,
638 [DEVLINK_ATTR_REGION_CHUNK
] = MNL_TYPE_NESTED
,
639 [DEVLINK_ATTR_REGION_CHUNK_DATA
] = MNL_TYPE_BINARY
,
640 [DEVLINK_ATTR_REGION_CHUNK_ADDR
] = MNL_TYPE_U64
,
641 [DEVLINK_ATTR_REGION_CHUNK_LEN
] = MNL_TYPE_U64
,
642 [DEVLINK_ATTR_INFO_DRIVER_NAME
] = MNL_TYPE_STRING
,
643 [DEVLINK_ATTR_INFO_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
644 [DEVLINK_ATTR_INFO_VERSION_FIXED
] = MNL_TYPE_NESTED
,
645 [DEVLINK_ATTR_INFO_VERSION_RUNNING
] = MNL_TYPE_NESTED
,
646 [DEVLINK_ATTR_INFO_VERSION_STORED
] = MNL_TYPE_NESTED
,
647 [DEVLINK_ATTR_INFO_VERSION_NAME
] = MNL_TYPE_STRING
,
648 [DEVLINK_ATTR_INFO_VERSION_VALUE
] = MNL_TYPE_STRING
,
649 [DEVLINK_ATTR_HEALTH_REPORTER
] = MNL_TYPE_NESTED
,
650 [DEVLINK_ATTR_HEALTH_REPORTER_NAME
] = MNL_TYPE_STRING
,
651 [DEVLINK_ATTR_HEALTH_REPORTER_STATE
] = MNL_TYPE_U8
,
652 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] = MNL_TYPE_U64
,
653 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] = MNL_TYPE_U64
,
654 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
] = MNL_TYPE_U64
,
655 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] = MNL_TYPE_U64
,
656 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
] = MNL_TYPE_STRING
,
657 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
] = MNL_TYPE_STRING
,
658 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
] = MNL_TYPE_U64
,
659 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
] = MNL_TYPE_U64
,
660 [DEVLINK_ATTR_STATS
] = MNL_TYPE_NESTED
,
661 [DEVLINK_ATTR_TRAP_NAME
] = MNL_TYPE_STRING
,
662 [DEVLINK_ATTR_TRAP_ACTION
] = MNL_TYPE_U8
,
663 [DEVLINK_ATTR_TRAP_TYPE
] = MNL_TYPE_U8
,
664 [DEVLINK_ATTR_TRAP_GENERIC
] = MNL_TYPE_FLAG
,
665 [DEVLINK_ATTR_TRAP_METADATA
] = MNL_TYPE_NESTED
,
666 [DEVLINK_ATTR_TRAP_GROUP_NAME
] = MNL_TYPE_STRING
,
667 [DEVLINK_ATTR_RELOAD_FAILED
] = MNL_TYPE_U8
,
668 [DEVLINK_ATTR_TRAP_POLICER_ID
] = MNL_TYPE_U32
,
669 [DEVLINK_ATTR_TRAP_POLICER_RATE
] = MNL_TYPE_U64
,
670 [DEVLINK_ATTR_TRAP_POLICER_BURST
] = MNL_TYPE_U64
,
673 static const enum mnl_attr_data_type
674 devlink_stats_policy
[DEVLINK_ATTR_STATS_MAX
+ 1] = {
675 [DEVLINK_ATTR_STATS_RX_PACKETS
] = MNL_TYPE_U64
,
676 [DEVLINK_ATTR_STATS_RX_BYTES
] = MNL_TYPE_U64
,
677 [DEVLINK_ATTR_STATS_RX_DROPPED
] = MNL_TYPE_U64
,
680 static int attr_cb(const struct nlattr
*attr
, void *data
)
682 const struct nlattr
**tb
= data
;
685 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
688 type
= mnl_attr_get_type(attr
);
689 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
696 static int attr_stats_cb(const struct nlattr
*attr
, void *data
)
698 const struct nlattr
**tb
= data
;
701 /* Allow the tool to work on top of newer kernels that might contain
704 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_STATS_MAX
) < 0)
707 type
= mnl_attr_get_type(attr
);
708 if (mnl_attr_validate(attr
, devlink_stats_policy
[type
]) < 0)
715 static const enum mnl_attr_data_type
716 devlink_function_policy
[DEVLINK_PORT_FUNCTION_ATTR_MAX
+ 1] = {
717 [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
] = MNL_TYPE_BINARY
,
720 static int function_attr_cb(const struct nlattr
*attr
, void *data
)
722 const struct nlattr
**tb
= data
;
725 /* Allow the tool to work on top of newer kernels that might contain
728 if (mnl_attr_type_valid(attr
, DEVLINK_PORT_FUNCTION_ATTR_MAX
) < 0)
731 type
= mnl_attr_get_type(attr
);
732 if (mnl_attr_validate(attr
, devlink_function_policy
[type
]) < 0)
739 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
741 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
742 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
743 struct dl
*dl
= data
;
744 struct ifname_map
*ifname_map
;
745 const char *bus_name
;
746 const char *dev_name
;
747 uint32_t port_ifindex
;
748 const char *port_ifname
;
750 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
751 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
752 !tb
[DEVLINK_ATTR_PORT_INDEX
])
755 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
758 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
759 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
760 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
761 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
762 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
763 port_ifindex
, port_ifname
);
766 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
771 static void ifname_map_fini(struct dl
*dl
)
773 struct ifname_map
*ifname_map
, *tmp
;
775 list_for_each_entry_safe(ifname_map
, tmp
,
776 &dl
->ifname_map_list
, list
) {
777 list_del(&ifname_map
->list
);
778 ifname_map_free(ifname_map
);
782 static int ifname_map_init(struct dl
*dl
)
784 struct nlmsghdr
*nlh
;
787 INIT_LIST_HEAD(&dl
->ifname_map_list
);
789 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
790 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
792 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
800 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
801 char **p_bus_name
, char **p_dev_name
,
802 uint32_t *p_port_index
)
804 struct ifname_map
*ifname_map
;
806 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
807 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
808 *p_bus_name
= ifname_map
->bus_name
;
809 *p_dev_name
= ifname_map
->dev_name
;
810 *p_port_index
= ifname_map
->port_index
;
817 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
818 const char *dev_name
, uint32_t port_index
,
821 struct ifname_map
*ifname_map
;
823 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
824 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
825 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
826 port_index
== ifname_map
->port_index
) {
827 *p_ifname
= ifname_map
->ifname
;
834 static unsigned int strslashcount(char *str
)
836 unsigned int count
= 0;
839 while ((pos
= strchr(pos
, '/'))) {
846 static int strslashrsplit(char *str
, char **before
, char **after
)
850 slash
= strrchr(str
, '/');
859 static int strtouint64_t(const char *str
, uint64_t *p_val
)
862 unsigned long long int val
;
864 val
= strtoull(str
, &endptr
, 10);
865 if (endptr
== str
|| *endptr
!= '\0')
873 static int strtouint32_t(const char *str
, uint32_t *p_val
)
876 unsigned long int val
;
878 val
= strtoul(str
, &endptr
, 10);
879 if (endptr
== str
|| *endptr
!= '\0')
887 static int strtouint16_t(const char *str
, uint16_t *p_val
)
890 unsigned long int val
;
892 val
= strtoul(str
, &endptr
, 10);
893 if (endptr
== str
|| *endptr
!= '\0')
901 static int strtouint8_t(const char *str
, uint8_t *p_val
)
904 unsigned long int val
;
906 val
= strtoul(str
, &endptr
, 10);
907 if (endptr
== str
|| *endptr
!= '\0')
915 static int strtobool(const char *str
, bool *p_val
)
919 if (!strcmp(str
, "true") || !strcmp(str
, "1") ||
920 !strcmp(str
, "enable"))
922 else if (!strcmp(str
, "false") || !strcmp(str
, "0") ||
923 !strcmp(str
, "disable"))
931 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
933 strslashrsplit(str
, p_bus_name
, p_dev_name
);
937 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
939 char *str
= dl_argv_next(dl
);
942 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
945 if (strslashcount(str
) != 1) {
946 pr_err("Wrong devlink identification string format.\n");
947 pr_err("Expected \"bus_name/dev_name\".\n");
950 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
953 static int __dl_argv_handle_port(char *str
,
954 char **p_bus_name
, char **p_dev_name
,
955 uint32_t *p_port_index
)
961 err
= strslashrsplit(str
, &handlestr
, &portstr
);
963 pr_err("Port identification \"%s\" is invalid\n", str
);
966 err
= strtouint32_t(portstr
, p_port_index
);
968 pr_err("Port index \"%s\" is not a number or not within range\n",
972 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
974 pr_err("Port identification \"%s\" is invalid\n", str
);
980 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
981 char **p_bus_name
, char **p_dev_name
,
982 uint32_t *p_port_index
)
986 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
989 pr_err("Netdevice \"%s\" not found\n", str
);
995 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
996 char **p_dev_name
, uint32_t *p_port_index
)
998 char *str
= dl_argv_next(dl
);
999 unsigned int slash_count
;
1002 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
1005 slash_count
= strslashcount(str
);
1006 switch (slash_count
) {
1008 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
1009 p_dev_name
, p_port_index
);
1011 return __dl_argv_handle_port(str
, p_bus_name
,
1012 p_dev_name
, p_port_index
);
1014 pr_err("Wrong port identification string format.\n");
1015 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1020 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
1021 char **p_dev_name
, uint32_t *p_port_index
,
1022 uint64_t *p_handle_bit
)
1024 char *str
= dl_argv_next(dl
);
1025 unsigned int slash_count
;
1029 pr_err("One of following identifications expected:\n"
1030 "Devlink identification (\"bus_name/dev_name\")\n"
1031 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
1034 slash_count
= strslashcount(str
);
1035 if (slash_count
== 1) {
1036 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
1039 *p_handle_bit
= DL_OPT_HANDLE
;
1040 } else if (slash_count
== 2) {
1041 err
= __dl_argv_handle_port(str
, p_bus_name
,
1042 p_dev_name
, p_port_index
);
1045 *p_handle_bit
= DL_OPT_HANDLEP
;
1046 } else if (slash_count
== 0) {
1047 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
1048 p_dev_name
, p_port_index
);
1051 *p_handle_bit
= DL_OPT_HANDLEP
;
1053 pr_err("Wrong port identification string format.\n");
1054 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1060 static int __dl_argv_handle_region(char *str
, char **p_bus_name
,
1061 char **p_dev_name
, char **p_region
)
1066 err
= strslashrsplit(str
, &handlestr
, p_region
);
1068 pr_err("Region identification \"%s\" is invalid\n", str
);
1071 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
1073 pr_err("Region identification \"%s\" is invalid\n", str
);
1079 static int dl_argv_handle_region(struct dl
*dl
, char **p_bus_name
,
1080 char **p_dev_name
, char **p_region
)
1082 char *str
= dl_argv_next(dl
);
1083 unsigned int slash_count
;
1086 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
1090 slash_count
= strslashcount(str
);
1091 if (slash_count
!= 2) {
1092 pr_err("Wrong region identification string format.\n");
1093 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
1097 return __dl_argv_handle_region(str
, p_bus_name
, p_dev_name
, p_region
);
1100 static int dl_argv_uint64_t(struct dl
*dl
, uint64_t *p_val
)
1102 char *str
= dl_argv_next(dl
);
1106 pr_err("Unsigned number argument expected\n");
1110 err
= strtouint64_t(str
, p_val
);
1112 pr_err("\"%s\" is not a number or not within range\n", str
);
1118 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
1120 char *str
= dl_argv_next(dl
);
1124 pr_err("Unsigned number argument expected\n");
1128 err
= strtouint32_t(str
, p_val
);
1130 pr_err("\"%s\" is not a number or not within range\n", str
);
1136 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
1138 char *str
= dl_argv_next(dl
);
1142 pr_err("Unsigned number argument expected\n");
1146 err
= strtouint16_t(str
, p_val
);
1148 pr_err("\"%s\" is not a number or not within range\n", str
);
1154 static int dl_argv_bool(struct dl
*dl
, bool *p_val
)
1156 char *str
= dl_argv_next(dl
);
1160 pr_err("Boolean argument expected\n");
1164 err
= strtobool(str
, p_val
);
1166 pr_err("\"%s\" is not a valid boolean value\n", str
);
1172 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
1174 const char *str
= dl_argv_next(dl
);
1177 pr_err("String parameter expected\n");
1184 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
1186 if (strcmp(typestr
, "auto") == 0) {
1187 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
1188 } else if (strcmp(typestr
, "eth") == 0) {
1189 *p_type
= DEVLINK_PORT_TYPE_ETH
;
1190 } else if (strcmp(typestr
, "ib") == 0) {
1191 *p_type
= DEVLINK_PORT_TYPE_IB
;
1193 pr_err("Unknown port type \"%s\"\n", typestr
);
1199 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
1201 if (strcmp(typestr
, "ingress") == 0) {
1202 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
1203 } else if (strcmp(typestr
, "egress") == 0) {
1204 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
1206 pr_err("Unknown pool type \"%s\"\n", typestr
);
1212 static int threshold_type_get(const char *typestr
,
1213 enum devlink_sb_threshold_type
*p_type
)
1215 if (strcmp(typestr
, "static") == 0) {
1216 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
1217 } else if (strcmp(typestr
, "dynamic") == 0) {
1218 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
1220 pr_err("Unknown threshold type \"%s\"\n", typestr
);
1226 static int eswitch_mode_get(const char *typestr
,
1227 enum devlink_eswitch_mode
*p_mode
)
1229 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
1230 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
1231 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
1232 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
1234 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
1240 static int eswitch_inline_mode_get(const char *typestr
,
1241 enum devlink_eswitch_inline_mode
*p_mode
)
1243 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
1244 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
1245 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
1246 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
1247 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
1248 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
1249 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
1250 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
1252 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
1259 eswitch_encap_mode_get(const char *typestr
,
1260 enum devlink_eswitch_encap_mode
*p_encap_mode
)
1262 /* The initial implementation incorrectly accepted "enable"/"disable".
1263 * Carry it to maintain backward compatibility.
1265 if (strcmp(typestr
, "disable") == 0 ||
1266 strcmp(typestr
, ESWITCH_ENCAP_MODE_NONE
) == 0) {
1267 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_NONE
;
1268 } else if (strcmp(typestr
, "enable") == 0 ||
1269 strcmp(typestr
, ESWITCH_ENCAP_MODE_BASIC
) == 0) {
1270 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_BASIC
;
1272 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
1278 static int param_cmode_get(const char *cmodestr
,
1279 enum devlink_param_cmode
*cmode
)
1281 if (strcmp(cmodestr
, PARAM_CMODE_RUNTIME_STR
) == 0) {
1282 *cmode
= DEVLINK_PARAM_CMODE_RUNTIME
;
1283 } else if (strcmp(cmodestr
, PARAM_CMODE_DRIVERINIT_STR
) == 0) {
1284 *cmode
= DEVLINK_PARAM_CMODE_DRIVERINIT
;
1285 } else if (strcmp(cmodestr
, PARAM_CMODE_PERMANENT_STR
) == 0) {
1286 *cmode
= DEVLINK_PARAM_CMODE_PERMANENT
;
1288 pr_err("Unknown configuration mode \"%s\"\n", cmodestr
);
1294 static int trap_action_get(const char *actionstr
,
1295 enum devlink_trap_action
*p_action
)
1297 if (strcmp(actionstr
, "drop") == 0) {
1298 *p_action
= DEVLINK_TRAP_ACTION_DROP
;
1299 } else if (strcmp(actionstr
, "trap") == 0) {
1300 *p_action
= DEVLINK_TRAP_ACTION_TRAP
;
1302 pr_err("Unknown trap action \"%s\"\n", actionstr
);
1308 static int hw_addr_parse(const char *addrstr
, char *hw_addr
, uint32_t *len
)
1312 alen
= ll_addr_a2n(hw_addr
, MAX_ADDR_LEN
, addrstr
);
1319 struct dl_args_metadata
{
1321 char err_msg
[DL_ARGS_REQUIRED_MAX_ERR_LEN
];
1324 static const struct dl_args_metadata dl_args_required
[] = {
1325 {DL_OPT_PORT_TYPE
, "Port type not set."},
1326 {DL_OPT_PORT_COUNT
, "Port split count option expected."},
1327 {DL_OPT_SB_POOL
, "Pool index option expected."},
1328 {DL_OPT_SB_SIZE
, "Pool size option expected."},
1329 {DL_OPT_SB_TYPE
, "Pool type option expected."},
1330 {DL_OPT_SB_THTYPE
, "Pool threshold type option expected."},
1331 {DL_OPT_SB_TH
, "Threshold option expected."},
1332 {DL_OPT_SB_TC
, "TC index option expected."},
1333 {DL_OPT_ESWITCH_MODE
, "E-Switch mode option expected."},
1334 {DL_OPT_ESWITCH_INLINE_MODE
, "E-Switch inline-mode option expected."},
1335 {DL_OPT_DPIPE_TABLE_NAME
, "Dpipe table name expected."},
1336 {DL_OPT_DPIPE_TABLE_COUNTERS
, "Dpipe table counter state expected."},
1337 {DL_OPT_ESWITCH_ENCAP_MODE
, "E-Switch encapsulation option expected."},
1338 {DL_OPT_RESOURCE_PATH
, "Resource path expected."},
1339 {DL_OPT_RESOURCE_SIZE
, "Resource size expected."},
1340 {DL_OPT_PARAM_NAME
, "Parameter name expected."},
1341 {DL_OPT_PARAM_VALUE
, "Value to set expected."},
1342 {DL_OPT_PARAM_CMODE
, "Configuration mode expected."},
1343 {DL_OPT_REGION_SNAPSHOT_ID
, "Region snapshot id expected."},
1344 {DL_OPT_REGION_ADDRESS
, "Region address value expected."},
1345 {DL_OPT_REGION_LENGTH
, "Region length value expected."},
1346 {DL_OPT_HEALTH_REPORTER_NAME
, "Reporter's name is expected."},
1347 {DL_OPT_TRAP_NAME
, "Trap's name is expected."},
1348 {DL_OPT_TRAP_GROUP_NAME
, "Trap group's name is expected."},
1349 {DL_OPT_PORT_FUNCTION_HW_ADDR
, "Port function's hardware address is expected."},
1352 static int dl_args_finding_required_validate(uint64_t o_required
,
1358 for (i
= 0; i
< ARRAY_SIZE(dl_args_required
); i
++) {
1359 o_flag
= dl_args_required
[i
].o_flag
;
1360 if ((o_required
& o_flag
) && !(o_found
& o_flag
)) {
1361 pr_err("%s\n", dl_args_required
[i
].err_msg
);
1365 if (o_required
& ~o_found
) {
1366 pr_err("BUG: unknown argument required but not found\n");
1372 static int dl_argv_parse(struct dl
*dl
, uint64_t o_required
,
1373 uint64_t o_optional
)
1375 struct dl_opts
*opts
= &dl
->opts
;
1376 uint64_t o_all
= o_required
| o_optional
;
1377 uint64_t o_found
= 0;
1380 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
1381 uint64_t handle_bit
;
1383 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
1384 &opts
->port_index
, &handle_bit
);
1387 o_required
&= ~(DL_OPT_HANDLE
| DL_OPT_HANDLEP
) | handle_bit
;
1388 o_found
|= handle_bit
;
1389 } else if (o_required
& DL_OPT_HANDLE
) {
1390 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
1393 o_found
|= DL_OPT_HANDLE
;
1394 } else if (o_required
& DL_OPT_HANDLEP
) {
1395 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
1399 o_found
|= DL_OPT_HANDLEP
;
1400 } else if (o_required
& DL_OPT_HANDLE_REGION
) {
1401 err
= dl_argv_handle_region(dl
, &opts
->bus_name
,
1403 &opts
->region_name
);
1406 o_found
|= DL_OPT_HANDLE_REGION
;
1409 while (dl_argc(dl
)) {
1410 if (dl_argv_match(dl
, "type") &&
1411 (o_all
& DL_OPT_PORT_TYPE
)) {
1412 const char *typestr
;
1415 err
= dl_argv_str(dl
, &typestr
);
1418 err
= port_type_get(typestr
, &opts
->port_type
);
1421 o_found
|= DL_OPT_PORT_TYPE
;
1422 } else if (dl_argv_match(dl
, "count") &&
1423 (o_all
& DL_OPT_PORT_COUNT
)) {
1425 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
1428 o_found
|= DL_OPT_PORT_COUNT
;
1429 } else if (dl_argv_match(dl
, "sb") &&
1430 (o_all
& DL_OPT_SB
)) {
1432 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
1435 o_found
|= DL_OPT_SB
;
1436 } else if (dl_argv_match(dl
, "pool") &&
1437 (o_all
& DL_OPT_SB_POOL
)) {
1439 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
1442 o_found
|= DL_OPT_SB_POOL
;
1443 } else if (dl_argv_match(dl
, "size") &&
1444 (o_all
& DL_OPT_SB_SIZE
)) {
1446 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
1449 o_found
|= DL_OPT_SB_SIZE
;
1450 } else if (dl_argv_match(dl
, "type") &&
1451 (o_all
& DL_OPT_SB_TYPE
)) {
1452 const char *typestr
;
1455 err
= dl_argv_str(dl
, &typestr
);
1458 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
1461 o_found
|= DL_OPT_SB_TYPE
;
1462 } else if (dl_argv_match(dl
, "thtype") &&
1463 (o_all
& DL_OPT_SB_THTYPE
)) {
1464 const char *typestr
;
1467 err
= dl_argv_str(dl
, &typestr
);
1470 err
= threshold_type_get(typestr
,
1471 &opts
->sb_pool_thtype
);
1474 o_found
|= DL_OPT_SB_THTYPE
;
1475 } else if (dl_argv_match(dl
, "th") &&
1476 (o_all
& DL_OPT_SB_TH
)) {
1478 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
1481 o_found
|= DL_OPT_SB_TH
;
1482 } else if (dl_argv_match(dl
, "tc") &&
1483 (o_all
& DL_OPT_SB_TC
)) {
1485 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
1488 o_found
|= DL_OPT_SB_TC
;
1489 } else if (dl_argv_match(dl
, "mode") &&
1490 (o_all
& DL_OPT_ESWITCH_MODE
)) {
1491 const char *typestr
;
1494 err
= dl_argv_str(dl
, &typestr
);
1497 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
1500 o_found
|= DL_OPT_ESWITCH_MODE
;
1501 } else if (dl_argv_match(dl
, "inline-mode") &&
1502 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1503 const char *typestr
;
1506 err
= dl_argv_str(dl
, &typestr
);
1509 err
= eswitch_inline_mode_get(
1510 typestr
, &opts
->eswitch_inline_mode
);
1513 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
1514 } else if (dl_argv_match(dl
, "name") &&
1515 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
1517 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
1520 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
1521 } else if ((dl_argv_match(dl
, "counters") ||
1522 dl_argv_match(dl
, "counters_enabled")) &&
1523 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1525 err
= dl_argv_bool(dl
, &opts
->dpipe_counters_enabled
);
1528 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
1529 } else if ((dl_argv_match(dl
, "encap") || /* Original incorrect implementation */
1530 dl_argv_match(dl
, "encap-mode")) &&
1531 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1532 const char *typestr
;
1535 err
= dl_argv_str(dl
, &typestr
);
1538 err
= eswitch_encap_mode_get(typestr
,
1539 &opts
->eswitch_encap_mode
);
1542 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
1543 } else if (dl_argv_match(dl
, "path") &&
1544 (o_all
& DL_OPT_RESOURCE_PATH
)) {
1546 err
= dl_argv_str(dl
, &opts
->resource_path
);
1549 o_found
|= DL_OPT_RESOURCE_PATH
;
1550 } else if (dl_argv_match(dl
, "size") &&
1551 (o_all
& DL_OPT_RESOURCE_SIZE
)) {
1553 err
= dl_argv_uint64_t(dl
, &opts
->resource_size
);
1556 o_found
|= DL_OPT_RESOURCE_SIZE
;
1557 } else if (dl_argv_match(dl
, "name") &&
1558 (o_all
& DL_OPT_PARAM_NAME
)) {
1560 err
= dl_argv_str(dl
, &opts
->param_name
);
1563 o_found
|= DL_OPT_PARAM_NAME
;
1564 } else if (dl_argv_match(dl
, "value") &&
1565 (o_all
& DL_OPT_PARAM_VALUE
)) {
1567 err
= dl_argv_str(dl
, &opts
->param_value
);
1570 o_found
|= DL_OPT_PARAM_VALUE
;
1571 } else if (dl_argv_match(dl
, "cmode") &&
1572 (o_all
& DL_OPT_PARAM_CMODE
)) {
1573 const char *cmodestr
;
1576 err
= dl_argv_str(dl
, &cmodestr
);
1579 err
= param_cmode_get(cmodestr
, &opts
->cmode
);
1582 o_found
|= DL_OPT_PARAM_CMODE
;
1583 } else if (dl_argv_match(dl
, "snapshot") &&
1584 (o_all
& DL_OPT_REGION_SNAPSHOT_ID
)) {
1586 err
= dl_argv_uint32_t(dl
, &opts
->region_snapshot_id
);
1589 o_found
|= DL_OPT_REGION_SNAPSHOT_ID
;
1590 } else if (dl_argv_match(dl
, "address") &&
1591 (o_all
& DL_OPT_REGION_ADDRESS
)) {
1593 err
= dl_argv_uint64_t(dl
, &opts
->region_address
);
1596 o_found
|= DL_OPT_REGION_ADDRESS
;
1597 } else if (dl_argv_match(dl
, "length") &&
1598 (o_all
& DL_OPT_REGION_LENGTH
)) {
1600 err
= dl_argv_uint64_t(dl
, &opts
->region_length
);
1603 o_found
|= DL_OPT_REGION_LENGTH
;
1604 } else if (dl_argv_match(dl
, "file") &&
1605 (o_all
& DL_OPT_FLASH_FILE_NAME
)) {
1607 err
= dl_argv_str(dl
, &opts
->flash_file_name
);
1610 o_found
|= DL_OPT_FLASH_FILE_NAME
;
1611 } else if (dl_argv_match(dl
, "component") &&
1612 (o_all
& DL_OPT_FLASH_COMPONENT
)) {
1614 err
= dl_argv_str(dl
, &opts
->flash_component
);
1617 o_found
|= DL_OPT_FLASH_COMPONENT
;
1618 } else if (dl_argv_match(dl
, "reporter") &&
1619 (o_all
& DL_OPT_HEALTH_REPORTER_NAME
)) {
1621 err
= dl_argv_str(dl
, &opts
->reporter_name
);
1624 o_found
|= DL_OPT_HEALTH_REPORTER_NAME
;
1625 } else if (dl_argv_match(dl
, "grace_period") &&
1626 (o_all
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)) {
1628 err
= dl_argv_uint64_t(dl
,
1629 &opts
->reporter_graceful_period
);
1632 o_found
|= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
;
1633 } else if (dl_argv_match(dl
, "auto_recover") &&
1634 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)) {
1636 err
= dl_argv_bool(dl
, &opts
->reporter_auto_recover
);
1639 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
;
1640 } else if (dl_argv_match(dl
, "auto_dump") &&
1641 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_DUMP
)) {
1643 err
= dl_argv_bool(dl
, &opts
->reporter_auto_dump
);
1646 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_DUMP
;
1647 } else if (dl_argv_match(dl
, "trap") &&
1648 (o_all
& DL_OPT_TRAP_NAME
)) {
1650 err
= dl_argv_str(dl
, &opts
->trap_name
);
1653 o_found
|= DL_OPT_TRAP_NAME
;
1654 } else if (dl_argv_match(dl
, "group") &&
1655 (o_all
& DL_OPT_TRAP_GROUP_NAME
)) {
1657 err
= dl_argv_str(dl
, &opts
->trap_group_name
);
1660 o_found
|= DL_OPT_TRAP_GROUP_NAME
;
1661 } else if (dl_argv_match(dl
, "action") &&
1662 (o_all
& DL_OPT_TRAP_ACTION
)) {
1663 const char *actionstr
;
1666 err
= dl_argv_str(dl
, &actionstr
);
1669 err
= trap_action_get(actionstr
, &opts
->trap_action
);
1672 o_found
|= DL_OPT_TRAP_ACTION
;
1673 } else if (dl_argv_match(dl
, "netns") &&
1674 (o_all
& DL_OPT_NETNS
)) {
1675 const char *netns_str
;
1678 err
= dl_argv_str(dl
, &netns_str
);
1681 opts
->netns
= netns_get_fd(netns_str
);
1682 if ((int)opts
->netns
< 0) {
1684 err
= dl_argv_uint32_t(dl
, &opts
->netns
);
1687 opts
->netns_is_pid
= true;
1689 o_found
|= DL_OPT_NETNS
;
1690 } else if (dl_argv_match(dl
, "policer") &&
1691 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1693 err
= dl_argv_uint32_t(dl
, &opts
->trap_policer_id
);
1696 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1697 } else if (dl_argv_match(dl
, "nopolicer") &&
1698 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1700 opts
->trap_policer_id
= 0;
1701 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1702 } else if (dl_argv_match(dl
, "rate") &&
1703 (o_all
& DL_OPT_TRAP_POLICER_RATE
)) {
1705 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_rate
);
1708 o_found
|= DL_OPT_TRAP_POLICER_RATE
;
1709 } else if (dl_argv_match(dl
, "burst") &&
1710 (o_all
& DL_OPT_TRAP_POLICER_BURST
)) {
1712 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_burst
);
1715 o_found
|= DL_OPT_TRAP_POLICER_BURST
;
1716 } else if (dl_argv_match(dl
, "hw_addr") &&
1717 (o_all
& DL_OPT_PORT_FUNCTION_HW_ADDR
)) {
1718 const char *addrstr
;
1721 err
= dl_argv_str(dl
, &addrstr
);
1724 err
= hw_addr_parse(addrstr
, opts
->port_function_hw_addr
,
1725 &opts
->port_function_hw_addr_len
);
1728 o_found
|= DL_OPT_PORT_FUNCTION_HW_ADDR
;
1731 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
1736 opts
->present
= o_found
;
1738 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
1740 opts
->present
|= DL_OPT_SB
;
1743 return dl_args_finding_required_validate(o_required
, o_found
);
1747 dl_function_attr_put(struct nlmsghdr
*nlh
, const struct dl_opts
*opts
)
1749 struct nlattr
*nest
;
1751 nest
= mnl_attr_nest_start(nlh
, DEVLINK_ATTR_PORT_FUNCTION
);
1752 mnl_attr_put(nlh
, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
,
1753 opts
->port_function_hw_addr_len
,
1754 opts
->port_function_hw_addr
);
1755 mnl_attr_nest_end(nlh
, nest
);
1758 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1760 struct dl_opts
*opts
= &dl
->opts
;
1762 if (opts
->present
& DL_OPT_HANDLE
) {
1763 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1764 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1765 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1766 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1767 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1768 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1770 } else if (opts
->present
& DL_OPT_HANDLE_REGION
) {
1771 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1772 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1773 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_REGION_NAME
,
1776 if (opts
->present
& DL_OPT_PORT_TYPE
)
1777 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1779 if (opts
->present
& DL_OPT_PORT_COUNT
)
1780 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1782 if (opts
->present
& DL_OPT_SB
)
1783 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1785 if (opts
->present
& DL_OPT_SB_POOL
)
1786 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1787 opts
->sb_pool_index
);
1788 if (opts
->present
& DL_OPT_SB_SIZE
)
1789 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1790 opts
->sb_pool_size
);
1791 if (opts
->present
& DL_OPT_SB_TYPE
)
1792 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1793 opts
->sb_pool_type
);
1794 if (opts
->present
& DL_OPT_SB_THTYPE
)
1795 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1796 opts
->sb_pool_thtype
);
1797 if (opts
->present
& DL_OPT_SB_TH
)
1798 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1799 opts
->sb_threshold
);
1800 if (opts
->present
& DL_OPT_SB_TC
)
1801 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1803 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1804 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1805 opts
->eswitch_mode
);
1806 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1807 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1808 opts
->eswitch_inline_mode
);
1809 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1810 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1811 opts
->dpipe_table_name
);
1812 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1813 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1814 opts
->dpipe_counters_enabled
);
1815 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1816 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1817 opts
->eswitch_encap_mode
);
1818 if ((opts
->present
& DL_OPT_RESOURCE_PATH
) && opts
->resource_id_valid
)
1819 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_ID
,
1821 if (opts
->present
& DL_OPT_RESOURCE_SIZE
)
1822 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_SIZE
,
1823 opts
->resource_size
);
1824 if (opts
->present
& DL_OPT_PARAM_NAME
)
1825 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_NAME
,
1827 if (opts
->present
& DL_OPT_PARAM_CMODE
)
1828 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_CMODE
,
1830 if (opts
->present
& DL_OPT_REGION_SNAPSHOT_ID
)
1831 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_REGION_SNAPSHOT_ID
,
1832 opts
->region_snapshot_id
);
1833 if (opts
->present
& DL_OPT_REGION_ADDRESS
)
1834 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_ADDR
,
1835 opts
->region_address
);
1836 if (opts
->present
& DL_OPT_REGION_LENGTH
)
1837 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_LEN
,
1838 opts
->region_length
);
1839 if (opts
->present
& DL_OPT_FLASH_FILE_NAME
)
1840 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME
,
1841 opts
->flash_file_name
);
1842 if (opts
->present
& DL_OPT_FLASH_COMPONENT
)
1843 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
,
1844 opts
->flash_component
);
1845 if (opts
->present
& DL_OPT_HEALTH_REPORTER_NAME
)
1846 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
1847 opts
->reporter_name
);
1848 if (opts
->present
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)
1849 mnl_attr_put_u64(nlh
,
1850 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
,
1851 opts
->reporter_graceful_period
);
1852 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)
1853 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
,
1854 opts
->reporter_auto_recover
);
1855 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_DUMP
)
1856 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
,
1857 opts
->reporter_auto_dump
);
1858 if (opts
->present
& DL_OPT_TRAP_NAME
)
1859 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_NAME
,
1861 if (opts
->present
& DL_OPT_TRAP_GROUP_NAME
)
1862 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_GROUP_NAME
,
1863 opts
->trap_group_name
);
1864 if (opts
->present
& DL_OPT_TRAP_ACTION
)
1865 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_TRAP_ACTION
,
1867 if (opts
->present
& DL_OPT_NETNS
)
1868 mnl_attr_put_u32(nlh
,
1869 opts
->netns_is_pid
? DEVLINK_ATTR_NETNS_PID
:
1870 DEVLINK_ATTR_NETNS_FD
,
1872 if (opts
->present
& DL_OPT_TRAP_POLICER_ID
)
1873 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_TRAP_POLICER_ID
,
1874 opts
->trap_policer_id
);
1875 if (opts
->present
& DL_OPT_TRAP_POLICER_RATE
)
1876 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_RATE
,
1877 opts
->trap_policer_rate
);
1878 if (opts
->present
& DL_OPT_TRAP_POLICER_BURST
)
1879 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_BURST
,
1880 opts
->trap_policer_burst
);
1881 if (opts
->present
& DL_OPT_PORT_FUNCTION_HW_ADDR
)
1882 dl_function_attr_put(nlh
, opts
);
1885 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1886 uint64_t o_required
, uint64_t o_optional
)
1890 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1893 dl_opts_put(nlh
, dl
);
1897 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1899 struct dl_opts
*opts
= &dl
->opts
;
1900 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1901 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1902 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1903 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1905 if (opts
->present
& DL_OPT_HANDLE
&&
1906 attr_bus_name
&& attr_dev_name
) {
1907 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1908 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1910 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1911 strcmp(dev_name
, opts
->dev_name
) != 0)
1914 if (opts
->present
& DL_OPT_HANDLEP
&&
1915 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1916 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1917 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1918 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1920 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1921 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1922 port_index
!= opts
->port_index
)
1925 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1926 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1928 if (sb_index
!= opts
->sb_index
)
1934 static void cmd_dev_help(void)
1936 pr_err("Usage: devlink dev show [ DEV ]\n");
1937 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1938 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1939 pr_err(" [ encap-mode { none | basic } ]\n");
1940 pr_err(" devlink dev eswitch show DEV\n");
1941 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1942 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1943 pr_err(" devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
1944 pr_err(" devlink dev info [ DEV ]\n");
1945 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1948 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1949 const char *dev_name
)
1951 if (!dl
->arr_last
.present
)
1953 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1954 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1957 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1958 const char *dev_name
)
1960 dl
->arr_last
.present
= true;
1961 free(dl
->arr_last
.dev_name
);
1962 free(dl
->arr_last
.bus_name
);
1963 dl
->arr_last
.bus_name
= strdup(bus_name
);
1964 dl
->arr_last
.dev_name
= strdup(dev_name
);
1967 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1968 const char *dev_name
)
1970 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1973 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1974 const char *dev_name
)
1976 return dl
->arr_last
.present
&&
1977 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1980 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1981 bool content
, bool array
)
1983 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1984 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1987 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
1989 if (dl
->json_output
) {
1991 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1992 close_json_array(PRINT_JSON
, NULL
);
1993 if (should_arr_last_handle_start(dl
, bus_name
,
1995 open_json_array(PRINT_JSON
, buf
);
1996 open_json_object(NULL
);
1997 arr_last_handle_set(dl
, bus_name
, dev_name
);
1999 open_json_object(NULL
);
2002 open_json_object(buf
);
2006 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
2007 __pr_out_indent_dec();
2008 if (should_arr_last_handle_start(dl
, bus_name
,
2010 pr_out("%s%s", buf
, content
? ":" : "");
2012 __pr_out_indent_inc();
2013 arr_last_handle_set(dl
, bus_name
, dev_name
);
2016 pr_out("%s%s", buf
, content
? ":" : "");
2021 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
2023 __pr_out_handle_start(dl
, tb
, true, true);
2026 static void pr_out_handle_end(struct dl
*dl
)
2028 if (dl
->json_output
)
2029 close_json_object();
2034 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
2036 __pr_out_handle_start(dl
, tb
, false, false);
2037 pr_out_handle_end(dl
);
2040 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
2041 const char *dev_name
, uint32_t port_index
)
2043 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
2044 dl
->arr_last
.port_index
== port_index
;
2047 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
2048 const char *dev_name
, uint32_t port_index
)
2050 arr_last_handle_set(dl
, bus_name
, dev_name
);
2051 dl
->arr_last
.port_index
= port_index
;
2054 static bool should_arr_last_port_handle_start(struct dl
*dl
,
2055 const char *bus_name
,
2056 const char *dev_name
,
2057 uint32_t port_index
)
2059 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
2062 static bool should_arr_last_port_handle_end(struct dl
*dl
,
2063 const char *bus_name
,
2064 const char *dev_name
,
2065 uint32_t port_index
)
2067 return dl
->arr_last
.present
&&
2068 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
2071 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
2072 const char *dev_name
,
2073 uint32_t port_index
, bool try_nice
,
2076 static char buf
[64];
2077 char *ifname
= NULL
;
2079 if (dl
->no_nice_names
|| !try_nice
||
2080 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
2081 port_index
, &ifname
) != 0)
2082 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
2084 sprintf(buf
, "%s", ifname
);
2086 if (dl
->json_output
) {
2088 if (should_arr_last_port_handle_end(dl
, bus_name
,
2091 close_json_array(PRINT_JSON
, NULL
);
2092 if (should_arr_last_port_handle_start(dl
, bus_name
,
2095 open_json_array(PRINT_JSON
, buf
);
2096 open_json_object(NULL
);
2097 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
2100 open_json_object(NULL
);
2103 open_json_object(buf
);
2110 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
2112 const char *bus_name
;
2113 const char *dev_name
;
2114 uint32_t port_index
;
2116 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2117 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2118 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
2119 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
2122 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
2124 const char *bus_name
;
2125 const char *dev_name
;
2126 uint32_t port_index
;
2128 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2129 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2130 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
2131 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
2134 static void pr_out_port_handle_end(struct dl
*dl
)
2136 if (dl
->json_output
)
2137 close_json_object();
2142 static void pr_out_region_chunk_start(struct dl
*dl
, uint64_t addr
)
2144 if (dl
->json_output
) {
2145 print_uint(PRINT_JSON
, "address", NULL
, addr
);
2146 open_json_array(PRINT_JSON
, "data");
2150 static void pr_out_region_chunk_end(struct dl
*dl
)
2152 if (dl
->json_output
)
2153 close_json_array(PRINT_JSON
, NULL
);
2156 static void pr_out_region_chunk(struct dl
*dl
, uint8_t *data
, uint32_t len
,
2159 static uint64_t align_val
;
2162 pr_out_region_chunk_start(dl
, addr
);
2164 if (!dl
->json_output
)
2165 if (!(align_val
% 16))
2166 pr_out("%s%016"PRIx64
" ",
2167 align_val
? "\n" : "",
2172 if (dl
->json_output
)
2173 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
2175 pr_out("%02x ", data
[i
]);
2180 pr_out_region_chunk_end(dl
);
2183 static void pr_out_stats(struct dl
*dl
, struct nlattr
*nla_stats
)
2185 struct nlattr
*tb
[DEVLINK_ATTR_STATS_MAX
+ 1] = {};
2191 err
= mnl_attr_parse_nested(nla_stats
, attr_stats_cb
, tb
);
2192 if (err
!= MNL_CB_OK
)
2195 pr_out_object_start(dl
, "stats");
2196 pr_out_object_start(dl
, "rx");
2197 if (tb
[DEVLINK_ATTR_STATS_RX_BYTES
])
2198 pr_out_u64(dl
, "bytes",
2199 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_BYTES
]));
2200 if (tb
[DEVLINK_ATTR_STATS_RX_PACKETS
])
2201 pr_out_u64(dl
, "packets",
2202 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_PACKETS
]));
2203 if (tb
[DEVLINK_ATTR_STATS_RX_DROPPED
])
2204 pr_out_u64(dl
, "dropped",
2205 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_DROPPED
]));
2206 pr_out_object_end(dl
);
2207 pr_out_object_end(dl
);
2210 static const char *param_cmode_name(uint8_t cmode
)
2213 case DEVLINK_PARAM_CMODE_RUNTIME
:
2214 return PARAM_CMODE_RUNTIME_STR
;
2215 case DEVLINK_PARAM_CMODE_DRIVERINIT
:
2216 return PARAM_CMODE_DRIVERINIT_STR
;
2217 case DEVLINK_PARAM_CMODE_PERMANENT
:
2218 return PARAM_CMODE_PERMANENT_STR
;
2219 default: return "<unknown type>";
2223 static const char *eswitch_mode_name(uint32_t mode
)
2226 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
2227 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
2228 default: return "<unknown mode>";
2232 static const char *eswitch_inline_mode_name(uint32_t mode
)
2235 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
2236 return ESWITCH_INLINE_MODE_NONE
;
2237 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
2238 return ESWITCH_INLINE_MODE_LINK
;
2239 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
2240 return ESWITCH_INLINE_MODE_NETWORK
;
2241 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
2242 return ESWITCH_INLINE_MODE_TRANSPORT
;
2244 return "<unknown mode>";
2248 static const char *eswitch_encap_mode_name(uint32_t mode
)
2251 case DEVLINK_ESWITCH_ENCAP_MODE_NONE
:
2252 return ESWITCH_ENCAP_MODE_NONE
;
2253 case DEVLINK_ESWITCH_ENCAP_MODE_BASIC
:
2254 return ESWITCH_ENCAP_MODE_BASIC
;
2256 return "<unknown mode>";
2260 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
2262 __pr_out_handle_start(dl
, tb
, true, false);
2264 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
]) {
2265 check_indent_newline(dl
);
2266 print_string(PRINT_ANY
, "mode", "mode %s",
2267 eswitch_mode_name(mnl_attr_get_u16(
2268 tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
2270 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
]) {
2271 check_indent_newline(dl
);
2272 print_string(PRINT_ANY
, "inline-mode", "inline-mode %s",
2273 eswitch_inline_mode_name(mnl_attr_get_u8(
2274 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
2276 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
2277 check_indent_newline(dl
);
2278 print_string(PRINT_ANY
, "encap-mode", "encap-mode %s",
2279 eswitch_encap_mode_name(mnl_attr_get_u8(
2280 tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
])));
2283 pr_out_handle_end(dl
);
2286 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2288 struct dl
*dl
= data
;
2289 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2290 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2292 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2293 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2294 return MNL_CB_ERROR
;
2295 pr_out_eswitch(dl
, tb
);
2299 static int cmd_dev_eswitch_show(struct dl
*dl
)
2301 struct nlmsghdr
*nlh
;
2304 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
2305 NLM_F_REQUEST
| NLM_F_ACK
);
2307 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2311 pr_out_section_start(dl
, "dev");
2312 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
2313 pr_out_section_end(dl
);
2317 static int cmd_dev_eswitch_set(struct dl
*dl
)
2319 struct nlmsghdr
*nlh
;
2322 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
2323 NLM_F_REQUEST
| NLM_F_ACK
);
2325 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
2326 DL_OPT_ESWITCH_MODE
|
2327 DL_OPT_ESWITCH_INLINE_MODE
|
2328 DL_OPT_ESWITCH_ENCAP_MODE
);
2333 if (dl
->opts
.present
== 1) {
2334 pr_err("Need to set at least one option\n");
2338 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2341 static int cmd_dev_eswitch(struct dl
*dl
)
2343 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2346 } else if (dl_argv_match(dl
, "set")) {
2348 return cmd_dev_eswitch_set(dl
);
2349 } else if (dl_argv_match(dl
, "show")) {
2351 return cmd_dev_eswitch_show(dl
);
2353 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2357 struct param_val_conv
{
2363 static bool param_val_conv_exists(const struct param_val_conv
*param_val_conv
,
2364 uint32_t len
, const char *name
)
2368 for (i
= 0; i
< len
; i
++)
2369 if (!strcmp(param_val_conv
[i
].name
, name
))
2376 param_val_conv_uint_get(const struct param_val_conv
*param_val_conv
,
2377 uint32_t len
, const char *name
, const char *vstr
,
2382 for (i
= 0; i
< len
; i
++)
2383 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2384 !strcmp(param_val_conv
[i
].vstr
, vstr
)) {
2385 *vuint
= param_val_conv
[i
].vuint
;
2393 param_val_conv_str_get(const struct param_val_conv
*param_val_conv
,
2394 uint32_t len
, const char *name
, uint32_t vuint
,
2399 for (i
= 0; i
< len
; i
++)
2400 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2401 param_val_conv
[i
].vuint
== vuint
) {
2402 *vstr
= param_val_conv
[i
].vstr
;
2409 static const struct param_val_conv param_val_conv
[] = {
2411 .name
= "fw_load_policy",
2413 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER
,
2416 .name
= "fw_load_policy",
2418 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH
,
2421 .name
= "reset_dev_on_drv_probe",
2423 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN
,
2426 .name
= "fw_load_policy",
2428 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN
,
2431 .name
= "reset_dev_on_drv_probe",
2433 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS
,
2436 .name
= "reset_dev_on_drv_probe",
2438 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER
,
2441 .name
= "reset_dev_on_drv_probe",
2443 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK
,
2447 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2449 static void pr_out_param_value(struct dl
*dl
, const char *nla_name
,
2450 int nla_type
, struct nlattr
*nl
)
2452 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2453 struct nlattr
*val_attr
;
2458 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_value
);
2459 if (err
!= MNL_CB_OK
)
2462 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2463 (nla_type
!= MNL_TYPE_FLAG
&&
2464 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2467 check_indent_newline(dl
);
2468 print_string(PRINT_ANY
, "cmode", "cmode %s",
2469 param_cmode_name(mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
])));
2471 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2473 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2479 err
= param_val_conv_str_get(param_val_conv
,
2482 mnl_attr_get_u8(val_attr
),
2486 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2488 print_uint(PRINT_ANY
, "value", " value %u",
2489 mnl_attr_get_u8(val_attr
));
2494 err
= param_val_conv_str_get(param_val_conv
,
2497 mnl_attr_get_u16(val_attr
),
2501 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2503 print_uint(PRINT_ANY
, "value", " value %u",
2504 mnl_attr_get_u16(val_attr
));
2509 err
= param_val_conv_str_get(param_val_conv
,
2512 mnl_attr_get_u32(val_attr
),
2516 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2518 print_uint(PRINT_ANY
, "value", " value %u",
2519 mnl_attr_get_u32(val_attr
));
2522 case MNL_TYPE_STRING
:
2523 print_string(PRINT_ANY
, "value", " value %s",
2524 mnl_attr_get_str(val_attr
));
2527 print_bool(PRINT_ANY
, "value", " value %s", val_attr
);
2532 static void pr_out_param(struct dl
*dl
, struct nlattr
**tb
, bool array
)
2534 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2535 struct nlattr
*param_value_attr
;
2536 const char *nla_name
;
2540 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2541 if (err
!= MNL_CB_OK
)
2543 if (!nla_param
[DEVLINK_ATTR_PARAM_NAME
] ||
2544 !nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2545 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2549 pr_out_handle_start_arr(dl
, tb
);
2551 __pr_out_handle_start(dl
, tb
, true, false);
2553 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2555 nla_name
= mnl_attr_get_str(nla_param
[DEVLINK_ATTR_PARAM_NAME
]);
2556 check_indent_newline(dl
);
2557 print_string(PRINT_ANY
, "name", "name %s ", nla_name
);
2558 if (!nla_param
[DEVLINK_ATTR_PARAM_GENERIC
])
2559 print_string(PRINT_ANY
, "type", "type %s", "driver-specific");
2561 print_string(PRINT_ANY
, "type", "type %s", "generic");
2563 pr_out_array_start(dl
, "values");
2564 mnl_attr_for_each_nested(param_value_attr
,
2565 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2566 pr_out_entry_start(dl
);
2567 pr_out_param_value(dl
, nla_name
, nla_type
, param_value_attr
);
2568 pr_out_entry_end(dl
);
2570 pr_out_array_end(dl
);
2571 pr_out_handle_end(dl
);
2574 static int cmd_dev_param_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2576 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2577 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2578 struct dl
*dl
= data
;
2580 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2581 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2582 !tb
[DEVLINK_ATTR_PARAM
])
2583 return MNL_CB_ERROR
;
2584 pr_out_param(dl
, tb
, true);
2600 static int cmd_dev_param_set_cb(const struct nlmsghdr
*nlh
, void *data
)
2602 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2603 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2604 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2605 struct nlattr
*param_value_attr
;
2606 enum devlink_param_cmode cmode
;
2607 struct param_ctx
*ctx
= data
;
2608 struct dl
*dl
= ctx
->dl
;
2612 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2613 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2614 !tb
[DEVLINK_ATTR_PARAM
])
2615 return MNL_CB_ERROR
;
2617 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2618 if (err
!= MNL_CB_OK
)
2619 return MNL_CB_ERROR
;
2621 if (!nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2622 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2623 return MNL_CB_ERROR
;
2625 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2626 mnl_attr_for_each_nested(param_value_attr
,
2627 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2628 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2629 struct nlattr
*val_attr
;
2631 err
= mnl_attr_parse_nested(param_value_attr
,
2632 attr_cb
, nla_value
);
2633 if (err
!= MNL_CB_OK
)
2634 return MNL_CB_ERROR
;
2636 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2637 (nla_type
!= MNL_TYPE_FLAG
&&
2638 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2639 return MNL_CB_ERROR
;
2641 cmode
= mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
]);
2642 if (cmode
== dl
->opts
.cmode
) {
2643 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2646 ctx
->value
.vu8
= mnl_attr_get_u8(val_attr
);
2649 ctx
->value
.vu16
= mnl_attr_get_u16(val_attr
);
2652 ctx
->value
.vu32
= mnl_attr_get_u32(val_attr
);
2654 case MNL_TYPE_STRING
:
2655 ctx
->value
.vstr
= mnl_attr_get_str(val_attr
);
2658 ctx
->value
.vbool
= val_attr
? true : false;
2664 ctx
->nla_type
= nla_type
;
2668 static int cmd_dev_param_set(struct dl
*dl
)
2670 struct param_ctx ctx
= {};
2671 struct nlmsghdr
*nlh
;
2679 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
|
2681 DL_OPT_PARAM_VALUE
|
2682 DL_OPT_PARAM_CMODE
, 0);
2686 /* Get value type */
2687 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
,
2688 NLM_F_REQUEST
| NLM_F_ACK
);
2689 dl_opts_put(nlh
, dl
);
2692 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_set_cb
, &ctx
);
2696 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_SET
,
2697 NLM_F_REQUEST
| NLM_F_ACK
);
2698 dl_opts_put(nlh
, dl
);
2700 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2701 dl
->opts
.param_name
);
2703 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_TYPE
, ctx
.nla_type
);
2704 switch (ctx
.nla_type
) {
2707 err
= param_val_conv_uint_get(param_val_conv
,
2709 dl
->opts
.param_name
,
2710 dl
->opts
.param_value
,
2714 err
= strtouint8_t(dl
->opts
.param_value
, &val_u8
);
2717 goto err_param_value_parse
;
2718 if (val_u8
== ctx
.value
.vu8
)
2720 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u8
);
2724 err
= param_val_conv_uint_get(param_val_conv
,
2726 dl
->opts
.param_name
,
2727 dl
->opts
.param_value
,
2731 err
= strtouint16_t(dl
->opts
.param_value
, &val_u16
);
2734 goto err_param_value_parse
;
2735 if (val_u16
== ctx
.value
.vu16
)
2737 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u16
);
2741 err
= param_val_conv_uint_get(param_val_conv
,
2743 dl
->opts
.param_name
,
2744 dl
->opts
.param_value
,
2747 err
= strtouint32_t(dl
->opts
.param_value
, &val_u32
);
2749 goto err_param_value_parse
;
2750 if (val_u32
== ctx
.value
.vu32
)
2752 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u32
);
2755 err
= strtobool(dl
->opts
.param_value
, &val_bool
);
2757 goto err_param_value_parse
;
2758 if (val_bool
== ctx
.value
.vbool
)
2761 mnl_attr_put(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2764 case MNL_TYPE_STRING
:
2765 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2766 dl
->opts
.param_value
);
2767 if (!strcmp(dl
->opts
.param_value
, ctx
.value
.vstr
))
2771 printf("Value type not supported\n");
2774 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2776 err_param_value_parse
:
2777 pr_err("Value \"%s\" is not a number or not within range\n",
2778 dl
->opts
.param_value
);
2782 static int cmd_dev_param_show(struct dl
*dl
)
2784 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2785 struct nlmsghdr
*nlh
;
2788 if (dl_argc(dl
) == 0)
2789 flags
|= NLM_F_DUMP
;
2791 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
, flags
);
2793 if (dl_argc(dl
) > 0) {
2794 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
|
2795 DL_OPT_PARAM_NAME
, 0);
2800 pr_out_section_start(dl
, "param");
2801 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_show_cb
, dl
);
2802 pr_out_section_end(dl
);
2806 static int cmd_dev_param(struct dl
*dl
)
2808 if (dl_argv_match(dl
, "help")) {
2811 } else if (dl_argv_match(dl
, "show") ||
2812 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2814 return cmd_dev_param_show(dl
);
2815 } else if (dl_argv_match(dl
, "set")) {
2817 return cmd_dev_param_set(dl
);
2819 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2822 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2824 struct dl
*dl
= data
;
2825 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2826 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2827 uint8_t reload_failed
= 0;
2829 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2830 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2831 return MNL_CB_ERROR
;
2833 if (tb
[DEVLINK_ATTR_RELOAD_FAILED
])
2834 reload_failed
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_RELOAD_FAILED
]);
2836 if (reload_failed
) {
2837 __pr_out_handle_start(dl
, tb
, true, false);
2838 check_indent_newline(dl
);
2839 print_bool(PRINT_ANY
, "reload_failed", "reload_failed %s", true);
2840 pr_out_handle_end(dl
);
2842 pr_out_handle(dl
, tb
);
2848 static int cmd_dev_show(struct dl
*dl
)
2850 struct nlmsghdr
*nlh
;
2851 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2854 if (dl_argc(dl
) == 0)
2855 flags
|= NLM_F_DUMP
;
2857 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
2859 if (dl_argc(dl
) > 0) {
2860 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2865 pr_out_section_start(dl
, "dev");
2866 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
2867 pr_out_section_end(dl
);
2871 static int cmd_dev_reload(struct dl
*dl
)
2873 struct nlmsghdr
*nlh
;
2876 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2881 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RELOAD
,
2882 NLM_F_REQUEST
| NLM_F_ACK
);
2884 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_NETNS
);
2888 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2891 static void pr_out_versions_single(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2892 const char *name
, int type
)
2894 struct nlattr
*version
;
2896 mnl_attr_for_each(version
, nlh
, sizeof(struct genlmsghdr
)) {
2897 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2898 const char *ver_value
;
2899 const char *ver_name
;
2902 if (mnl_attr_get_type(version
) != type
)
2905 err
= mnl_attr_parse_nested(version
, attr_cb
, tb
);
2906 if (err
!= MNL_CB_OK
)
2909 if (!tb
[DEVLINK_ATTR_INFO_VERSION_NAME
] ||
2910 !tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
])
2914 pr_out_object_start(dl
, name
);
2918 ver_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_NAME
]);
2919 ver_value
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
]);
2921 check_indent_newline(dl
);
2922 print_string_name_value(ver_name
, ver_value
);
2923 if (!dl
->json_output
)
2928 pr_out_object_end(dl
);
2931 static void pr_out_info(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2932 struct nlattr
**tb
, bool has_versions
)
2934 __pr_out_handle_start(dl
, tb
, true, false);
2936 __pr_out_indent_inc();
2937 if (tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
]) {
2938 struct nlattr
*nla_drv
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
];
2940 if (!dl
->json_output
)
2942 check_indent_newline(dl
);
2943 print_string(PRINT_ANY
, "driver", "driver %s",
2944 mnl_attr_get_str(nla_drv
));
2947 if (tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
]) {
2948 struct nlattr
*nla_sn
= tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
];
2950 if (!dl
->json_output
)
2952 check_indent_newline(dl
);
2953 print_string(PRINT_ANY
, "serial_number", "serial_number %s",
2954 mnl_attr_get_str(nla_sn
));
2956 __pr_out_indent_dec();
2959 pr_out_object_start(dl
, "versions");
2961 pr_out_versions_single(dl
, nlh
, "fixed",
2962 DEVLINK_ATTR_INFO_VERSION_FIXED
);
2963 pr_out_versions_single(dl
, nlh
, "running",
2964 DEVLINK_ATTR_INFO_VERSION_RUNNING
);
2965 pr_out_versions_single(dl
, nlh
, "stored",
2966 DEVLINK_ATTR_INFO_VERSION_STORED
);
2968 pr_out_object_end(dl
);
2971 pr_out_handle_end(dl
);
2974 static int cmd_versions_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2976 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2977 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2978 bool has_versions
, has_info
;
2979 struct dl
*dl
= data
;
2981 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2983 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2984 return MNL_CB_ERROR
;
2986 has_versions
= tb
[DEVLINK_ATTR_INFO_VERSION_FIXED
] ||
2987 tb
[DEVLINK_ATTR_INFO_VERSION_RUNNING
] ||
2988 tb
[DEVLINK_ATTR_INFO_VERSION_STORED
];
2989 has_info
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
] ||
2990 tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
] ||
2994 pr_out_info(dl
, nlh
, tb
, has_versions
);
2999 static int cmd_dev_info(struct dl
*dl
)
3001 struct nlmsghdr
*nlh
;
3002 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3005 if (dl_argv_match(dl
, "help")) {
3010 if (dl_argc(dl
) == 0)
3011 flags
|= NLM_F_DUMP
;
3013 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_INFO_GET
, flags
);
3015 if (dl_argc(dl
) > 0) {
3016 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
3021 pr_out_section_start(dl
, "info");
3022 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_versions_show_cb
, dl
);
3023 pr_out_section_end(dl
);
3027 struct cmd_dev_flash_status_ctx
{
3030 char *last_component
;
3031 uint8_t not_first
:1,
3037 static int nullstrcmp(const char *str1
, const char *str2
)
3040 return strcmp(str1
, str2
);
3043 return str1
? 1 : -1;
3046 static int cmd_dev_flash_status_cb(const struct nlmsghdr
*nlh
, void *data
)
3048 struct cmd_dev_flash_status_ctx
*ctx
= data
;
3049 struct dl_opts
*opts
= &ctx
->dl
->opts
;
3050 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3051 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3052 const char *component
= NULL
;
3053 uint64_t done
= 0, total
= 0;
3054 const char *msg
= NULL
;
3055 const char *bus_name
;
3056 const char *dev_name
;
3058 if (genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_STATUS
&&
3059 genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_END
)
3062 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3063 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
3064 return MNL_CB_ERROR
;
3065 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
3066 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
3067 if (strcmp(bus_name
, opts
->bus_name
) ||
3068 strcmp(dev_name
, opts
->dev_name
))
3069 return MNL_CB_ERROR
;
3071 if (genl
->cmd
== DEVLINK_CMD_FLASH_UPDATE_END
&& ctx
->not_first
) {
3073 free(ctx
->last_msg
);
3074 free(ctx
->last_component
);
3075 ctx
->received_end
= 1;
3079 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
])
3080 msg
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]);
3081 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
])
3082 component
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]);
3083 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
3084 done
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]);
3085 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
3086 total
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]);
3088 if (!nullstrcmp(msg
, ctx
->last_msg
) &&
3089 !nullstrcmp(component
, ctx
->last_component
) &&
3090 ctx
->last_pc
&& ctx
->not_first
) {
3091 pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3096 pr_out("[%s] ", component
);
3097 free(ctx
->last_component
);
3098 ctx
->last_component
= strdup(component
);
3102 free(ctx
->last_msg
);
3103 ctx
->last_msg
= strdup(msg
);
3107 pr_out_tty(" %3lu%%", (done
* 100) / total
);
3118 static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx
*ctx
,
3119 struct mnlg_socket
*nlg_ntf
,
3122 int nlfd
= mnlg_socket_get_fd(nlg_ntf
);
3129 for (i
= 0; i
< 3; i
++)
3131 FD_SET(pipe_r
, &fds
[0]);
3133 FD_SET(nlfd
, &fds
[0]);
3137 while (select(fdmax
, &fds
[0], &fds
[1], &fds
[2], NULL
) < 0) {
3140 pr_err("select() failed\n");
3143 if (FD_ISSET(nlfd
, &fds
[0])) {
3144 err
= _mnlg_socket_recv_run(nlg_ntf
,
3145 cmd_dev_flash_status_cb
, ctx
);
3149 if (FD_ISSET(pipe_r
, &fds
[0])) {
3150 err
= read(pipe_r
, &err2
, sizeof(err2
));
3152 pr_err("Failed to read pipe\n");
3157 ctx
->flash_done
= 1;
3163 static int cmd_dev_flash(struct dl
*dl
)
3165 struct cmd_dev_flash_status_ctx ctx
= {.dl
= dl
,};
3166 struct mnlg_socket
*nlg_ntf
;
3167 struct nlmsghdr
*nlh
;
3173 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3178 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_FLASH_UPDATE
,
3179 NLM_F_REQUEST
| NLM_F_ACK
);
3181 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_FLASH_FILE_NAME
,
3182 DL_OPT_FLASH_COMPONENT
);
3186 nlg_ntf
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
3190 err
= _mnlg_socket_group_add(nlg_ntf
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
3194 err
= pipe(pipe_fds
);
3197 pipe_r
= pipe_fds
[0];
3198 pipe_w
= pipe_fds
[1];
3206 /* In child, just execute the flash and pass returned
3207 * value through pipe once it is done.
3212 err
= _mnlg_socket_send(dl
->nlg
, nlh
);
3213 cc
= write(pipe_w
, &err
, sizeof(err
));
3215 exit(cc
!= sizeof(err
));
3220 err
= cmd_dev_flash_fds_process(&ctx
, nlg_ntf
, pipe_r
);
3223 } while (!ctx
.flash_done
|| (ctx
.not_first
&& !ctx
.received_end
));
3225 err
= _mnlg_socket_recv_run(dl
->nlg
, NULL
, NULL
);
3228 mnlg_socket_close(nlg_ntf
);
3232 static int cmd_dev(struct dl
*dl
)
3234 if (dl_argv_match(dl
, "help")) {
3237 } else if (dl_argv_match(dl
, "show") ||
3238 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3240 return cmd_dev_show(dl
);
3241 } else if (dl_argv_match(dl
, "eswitch")) {
3243 return cmd_dev_eswitch(dl
);
3244 } else if (dl_argv_match(dl
, "reload")) {
3246 return cmd_dev_reload(dl
);
3247 } else if (dl_argv_match(dl
, "param")) {
3249 return cmd_dev_param(dl
);
3250 } else if (dl_argv_match(dl
, "info")) {
3252 return cmd_dev_info(dl
);
3253 } else if (dl_argv_match(dl
, "flash")) {
3255 return cmd_dev_flash(dl
);
3257 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3261 static void cmd_port_help(void)
3263 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3264 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3265 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3266 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3267 pr_err(" devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3270 static const char *port_type_name(uint32_t type
)
3273 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
3274 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
3275 case DEVLINK_PORT_TYPE_ETH
: return "eth";
3276 case DEVLINK_PORT_TYPE_IB
: return "ib";
3277 default: return "<unknown type>";
3281 static const char *port_flavour_name(uint16_t flavour
)
3284 case DEVLINK_PORT_FLAVOUR_PHYSICAL
:
3286 case DEVLINK_PORT_FLAVOUR_CPU
:
3288 case DEVLINK_PORT_FLAVOUR_DSA
:
3290 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3292 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3294 case DEVLINK_PORT_FLAVOUR_VIRTUAL
:
3297 return "<unknown flavour>";
3301 static void pr_out_port_pfvf_num(struct dl
*dl
, struct nlattr
**tb
)
3305 if (tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]) {
3306 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]);
3307 print_uint(PRINT_ANY
, "pfnum", " pfnum %u", fn_num
);
3309 if (tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]) {
3310 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]);
3311 print_uint(PRINT_ANY
, "vfnum", " vfnum %u", fn_num
);
3315 static void pr_out_port_function(struct dl
*dl
, struct nlattr
**tb_port
)
3317 struct nlattr
*tb
[DEVLINK_PORT_FUNCTION_ATTR_MAX
+ 1] = {};
3318 unsigned char *data
;
3319 SPRINT_BUF(hw_addr
);
3323 if (!tb_port
[DEVLINK_ATTR_PORT_FUNCTION
])
3326 err
= mnl_attr_parse_nested(tb_port
[DEVLINK_ATTR_PORT_FUNCTION
],
3327 function_attr_cb
, tb
);
3328 if (err
!= MNL_CB_OK
)
3331 if (!tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
])
3334 len
= mnl_attr_get_payload_len(tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
]);
3335 data
= mnl_attr_get_payload(tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
]);
3337 pr_out_object_start(dl
, "function");
3338 check_indent_newline(dl
);
3339 print_string(PRINT_ANY
, "hw_addr", "hw_addr %s",
3340 ll_addr_n2a(data
, len
, 0, hw_addr
, sizeof(hw_addr
)));
3341 if (!dl
->json_output
)
3342 __pr_out_indent_dec();
3343 pr_out_object_end(dl
);
3346 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
3348 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
3349 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
3351 pr_out_port_handle_start(dl
, tb
, false);
3352 check_indent_newline(dl
);
3354 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
3356 print_string(PRINT_ANY
, "type", "type %s",
3357 port_type_name(port_type
));
3359 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
3361 if (port_type
!= des_port_type
)
3362 print_string(PRINT_ANY
, "des_type", " des_type %s",
3363 port_type_name(des_port_type
));
3366 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]) {
3367 print_string(PRINT_ANY
, "netdev", " netdev %s",
3368 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
3370 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]) {
3371 print_string(PRINT_ANY
, "ibdev", " ibdev %s",
3372 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
3374 if (tb
[DEVLINK_ATTR_PORT_FLAVOUR
]) {
3375 uint16_t port_flavour
=
3376 mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_FLAVOUR
]);
3378 print_string(PRINT_ANY
, "flavour", " flavour %s",
3379 port_flavour_name(port_flavour
));
3381 switch (port_flavour
) {
3382 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3383 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3384 pr_out_port_pfvf_num(dl
, tb
);
3390 if (tb
[DEVLINK_ATTR_PORT_NUMBER
]) {
3391 uint32_t port_number
;
3393 port_number
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_NUMBER
]);
3394 print_uint(PRINT_ANY
, "port", " port %u", port_number
);
3396 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
3397 print_uint(PRINT_ANY
, "split_group", " split_group %u",
3398 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
3399 pr_out_port_function(dl
, tb
);
3400 pr_out_port_handle_end(dl
);
3403 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3405 struct dl
*dl
= data
;
3406 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3407 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3409 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3410 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3411 !tb
[DEVLINK_ATTR_PORT_INDEX
])
3412 return MNL_CB_ERROR
;
3413 pr_out_port(dl
, tb
);
3417 static int cmd_port_show(struct dl
*dl
)
3419 struct nlmsghdr
*nlh
;
3420 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3423 if (dl_argc(dl
) == 0)
3424 flags
|= NLM_F_DUMP
;
3426 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
3428 if (dl_argc(dl
) > 0) {
3429 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3434 pr_out_section_start(dl
, "port");
3435 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
3436 pr_out_section_end(dl
);
3440 static int cmd_port_set(struct dl
*dl
)
3442 struct nlmsghdr
*nlh
;
3445 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
3446 NLM_F_REQUEST
| NLM_F_ACK
);
3448 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
3452 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3455 static int cmd_port_split(struct dl
*dl
)
3457 struct nlmsghdr
*nlh
;
3460 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
3461 NLM_F_REQUEST
| NLM_F_ACK
);
3463 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
3467 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3470 static int cmd_port_unsplit(struct dl
*dl
)
3472 struct nlmsghdr
*nlh
;
3475 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
3476 NLM_F_REQUEST
| NLM_F_ACK
);
3478 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3482 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3485 static void cmd_port_function_help(void)
3487 pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3490 static int cmd_port_function_set(struct dl
*dl
)
3492 struct nlmsghdr
*nlh
;
3495 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
, NLM_F_REQUEST
| NLM_F_ACK
);
3497 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_FUNCTION_HW_ADDR
, 0);
3501 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3504 static int cmd_port_function(struct dl
*dl
)
3506 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3507 cmd_port_function_help();
3509 } else if (dl_argv_match(dl
, "set")) {
3511 return cmd_port_function_set(dl
);
3513 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3517 static int cmd_port(struct dl
*dl
)
3519 if (dl_argv_match(dl
, "help")) {
3522 } else if (dl_argv_match(dl
, "show") ||
3523 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3525 return cmd_port_show(dl
);
3526 } else if (dl_argv_match(dl
, "set")) {
3528 return cmd_port_set(dl
);
3529 } else if (dl_argv_match(dl
, "split")) {
3531 return cmd_port_split(dl
);
3532 } else if (dl_argv_match(dl
, "unsplit")) {
3534 return cmd_port_unsplit(dl
);
3535 } else if (dl_argv_match(dl
, "function")) {
3537 return cmd_port_function(dl
);
3539 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3543 static void cmd_sb_help(void)
3545 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
3546 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
3547 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
3548 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
3549 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3550 pr_err(" pool POOL_INDEX ]\n");
3551 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3552 pr_err(" pool POOL_INDEX th THRESHOLD\n");
3553 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3554 pr_err(" type { ingress | egress } ]\n");
3555 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3556 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
3557 pr_err(" th THRESHOLD\n");
3558 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
3559 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
3560 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
3563 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
3565 pr_out_handle_start_arr(dl
, tb
);
3566 check_indent_newline(dl
);
3567 print_uint(PRINT_ANY
, "sb", "sb %u",
3568 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3569 print_uint(PRINT_ANY
, "size", " size %u",
3570 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
3571 print_uint(PRINT_ANY
, "ing_pools", " ing_pools %u",
3572 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
3573 print_uint(PRINT_ANY
, "eg_pools", " eg_pools %u",
3574 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
3575 print_uint(PRINT_ANY
, "ing_tcs", " ing_tcs %u",
3576 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
3577 print_uint(PRINT_ANY
, "eg_tcs", " eg_tcs %u",
3578 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
3579 pr_out_handle_end(dl
);
3582 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3584 struct dl
*dl
= data
;
3585 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3586 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3588 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3589 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3590 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
3591 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
3592 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
3593 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
3594 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
3595 return MNL_CB_ERROR
;
3600 static int cmd_sb_show(struct dl
*dl
)
3602 struct nlmsghdr
*nlh
;
3603 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3606 if (dl_argc(dl
) == 0)
3607 flags
|= NLM_F_DUMP
;
3609 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
3611 if (dl_argc(dl
) > 0) {
3612 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3617 pr_out_section_start(dl
, "sb");
3618 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
3619 pr_out_section_end(dl
);
3623 static const char *pool_type_name(uint8_t type
)
3626 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
3627 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
3628 default: return "<unknown type>";
3632 static const char *threshold_type_name(uint8_t type
)
3635 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
3636 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
3637 default: return "<unknown type>";
3641 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
3643 pr_out_handle_start_arr(dl
, tb
);
3644 check_indent_newline(dl
);
3645 print_uint(PRINT_ANY
, "sb", "sb %u",
3646 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3647 print_uint(PRINT_ANY
, "pool", " pool %u",
3648 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3649 print_string(PRINT_ANY
, "type", " type %s",
3650 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3651 print_uint(PRINT_ANY
, "size", " size %u",
3652 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
3653 print_string(PRINT_ANY
, "thtype", " thtype %s",
3654 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
3655 if (tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
])
3656 print_uint(PRINT_ANY
, "cell_size", " cell size %u",
3657 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
]));
3658 pr_out_handle_end(dl
);
3661 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3663 struct dl
*dl
= data
;
3664 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3665 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3667 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3668 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3669 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3670 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
3671 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
3672 return MNL_CB_ERROR
;
3673 pr_out_sb_pool(dl
, tb
);
3677 static int cmd_sb_pool_show(struct dl
*dl
)
3679 struct nlmsghdr
*nlh
;
3680 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3683 if (dl_argc(dl
) == 0)
3684 flags
|= NLM_F_DUMP
;
3686 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
3688 if (dl_argc(dl
) > 0) {
3689 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
3695 pr_out_section_start(dl
, "pool");
3696 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
3697 pr_out_section_end(dl
);
3701 static int cmd_sb_pool_set(struct dl
*dl
)
3703 struct nlmsghdr
*nlh
;
3706 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
3707 NLM_F_REQUEST
| NLM_F_ACK
);
3709 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
3710 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
3714 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3717 static int cmd_sb_pool(struct dl
*dl
)
3719 if (dl_argv_match(dl
, "help")) {
3722 } else if (dl_argv_match(dl
, "show") ||
3723 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3725 return cmd_sb_pool_show(dl
);
3726 } else if (dl_argv_match(dl
, "set")) {
3728 return cmd_sb_pool_set(dl
);
3730 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3734 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
3736 pr_out_port_handle_start_arr(dl
, tb
, true);
3737 check_indent_newline(dl
);
3738 print_uint(PRINT_ANY
, "sb", "sb %u",
3739 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3740 print_uint(PRINT_ANY
, "pool", " pool %u",
3741 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3742 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3743 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3744 pr_out_port_handle_end(dl
);
3747 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3749 struct dl
*dl
= data
;
3750 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3751 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3753 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3754 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3755 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3756 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3757 return MNL_CB_ERROR
;
3758 pr_out_sb_port_pool(dl
, tb
);
3762 static int cmd_sb_port_pool_show(struct dl
*dl
)
3764 struct nlmsghdr
*nlh
;
3765 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3768 if (dl_argc(dl
) == 0)
3769 flags
|= NLM_F_DUMP
;
3771 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3773 if (dl_argc(dl
) > 0) {
3774 err
= dl_argv_parse_put(nlh
, dl
,
3775 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
3781 pr_out_section_start(dl
, "port_pool");
3782 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
3783 pr_out_section_end(dl
);
3787 static int cmd_sb_port_pool_set(struct dl
*dl
)
3789 struct nlmsghdr
*nlh
;
3792 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
3793 NLM_F_REQUEST
| NLM_F_ACK
);
3795 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
3796 DL_OPT_SB_TH
, DL_OPT_SB
);
3800 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3803 static int cmd_sb_port_pool(struct dl
*dl
)
3805 if (dl_argv_match(dl
, "help")) {
3808 } else if (dl_argv_match(dl
, "show") ||
3809 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3811 return cmd_sb_port_pool_show(dl
);
3812 } else if (dl_argv_match(dl
, "set")) {
3814 return cmd_sb_port_pool_set(dl
);
3816 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3820 static int cmd_sb_port(struct dl
*dl
)
3822 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3825 } else if (dl_argv_match(dl
, "pool")) {
3827 return cmd_sb_port_pool(dl
);
3829 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3833 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
3835 pr_out_port_handle_start_arr(dl
, tb
, true);
3836 check_indent_newline(dl
);
3837 print_uint(PRINT_ANY
, "sb", "sb %u",
3838 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3839 print_uint(PRINT_ANY
, "tc", " tc %u",
3840 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
3841 print_string(PRINT_ANY
, "type", " type %s",
3842 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3843 print_uint(PRINT_ANY
, "pool", " pool %u",
3844 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3845 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3846 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3847 pr_out_port_handle_end(dl
);
3850 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3852 struct dl
*dl
= data
;
3853 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3854 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3856 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3857 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3858 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3859 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3860 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3861 return MNL_CB_ERROR
;
3862 pr_out_sb_tc_bind(dl
, tb
);
3866 static int cmd_sb_tc_bind_show(struct dl
*dl
)
3868 struct nlmsghdr
*nlh
;
3869 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3872 if (dl_argc(dl
) == 0)
3873 flags
|= NLM_F_DUMP
;
3875 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3877 if (dl_argc(dl
) > 0) {
3878 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3879 DL_OPT_SB_TYPE
, DL_OPT_SB
);
3884 pr_out_section_start(dl
, "tc_bind");
3885 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
3886 pr_out_section_end(dl
);
3890 static int cmd_sb_tc_bind_set(struct dl
*dl
)
3892 struct nlmsghdr
*nlh
;
3895 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
3896 NLM_F_REQUEST
| NLM_F_ACK
);
3898 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3899 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
3904 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3907 static int cmd_sb_tc_bind(struct dl
*dl
)
3909 if (dl_argv_match(dl
, "help")) {
3912 } else if (dl_argv_match(dl
, "show") ||
3913 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3915 return cmd_sb_tc_bind_show(dl
);
3916 } else if (dl_argv_match(dl
, "set")) {
3918 return cmd_sb_tc_bind_set(dl
);
3920 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3924 static int cmd_sb_tc(struct dl
*dl
)
3926 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3929 } else if (dl_argv_match(dl
, "bind")) {
3931 return cmd_sb_tc_bind(dl
);
3933 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3938 struct list_head list
;
3942 uint32_t bound_pool_index
;
3946 struct list_head list
;
3949 uint32_t port_index
;
3951 struct list_head pool_list
;
3952 struct list_head ing_tc_list
;
3953 struct list_head eg_tc_list
;
3959 struct list_head port_list
;
3962 static struct occ_item
*occ_item_alloc(void)
3964 return calloc(1, sizeof(struct occ_item
));
3967 static void occ_item_free(struct occ_item
*occ_item
)
3972 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
3974 struct occ_port
*occ_port
;
3976 occ_port
= calloc(1, sizeof(*occ_port
));
3979 occ_port
->port_index
= port_index
;
3980 INIT_LIST_HEAD(&occ_port
->pool_list
);
3981 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
3982 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
3986 static void occ_port_free(struct occ_port
*occ_port
)
3988 struct occ_item
*occ_item
, *tmp
;
3990 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
3991 occ_item_free(occ_item
);
3992 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
3993 occ_item_free(occ_item
);
3994 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
3995 occ_item_free(occ_item
);
3998 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
4000 struct occ_show
*occ_show
;
4002 occ_show
= calloc(1, sizeof(*occ_show
));
4006 INIT_LIST_HEAD(&occ_show
->port_list
);
4010 static void occ_show_free(struct occ_show
*occ_show
)
4012 struct occ_port
*occ_port
, *tmp
;
4014 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
4015 occ_port_free(occ_port
);
4018 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
4021 struct occ_port
*occ_port
;
4022 uint32_t port_index
;
4024 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
4026 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
4027 if (occ_port
->port_index
== port_index
)
4030 occ_port
= occ_port_alloc(port_index
);
4033 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
4037 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
4040 struct occ_item
*occ_item
;
4043 pr_out_sp(7, " %s:", label
);
4044 list_for_each_entry(occ_item
, list
, list
) {
4045 if ((i
- 1) % 4 == 0 && i
!= 1)
4048 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
4049 occ_item
->bound_pool_index
);
4051 pr_out_sp(7, "%2u:", occ_item
->index
);
4052 pr_out_sp(21, "%10u/%u", occ_item
->cur
, occ_item
->max
);
4056 if ((i
- 1) % 4 != 0)
4060 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
4061 struct list_head
*list
,
4064 struct occ_item
*occ_item
;
4067 open_json_object(label
);
4068 list_for_each_entry(occ_item
, list
, list
) {
4069 sprintf(buf
, "%u", occ_item
->index
);
4070 open_json_object(buf
);
4072 print_uint(PRINT_JSON
, "bound_pool", NULL
,
4073 occ_item
->bound_pool_index
);
4074 print_uint(PRINT_JSON
, "current", NULL
, occ_item
->cur
);
4075 print_uint(PRINT_JSON
, "max", NULL
, occ_item
->max
);
4076 close_json_object();
4078 close_json_object();
4081 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
4083 if (dl
->json_output
) {
4084 pr_out_json_occ_show_item_list(dl
, "pool",
4085 &occ_port
->pool_list
, false);
4086 pr_out_json_occ_show_item_list(dl
, "itc",
4087 &occ_port
->ing_tc_list
, true);
4088 pr_out_json_occ_show_item_list(dl
, "etc",
4089 &occ_port
->eg_tc_list
, true);
4092 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
4093 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
4094 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
4098 static void pr_out_occ_show(struct occ_show
*occ_show
)
4100 struct dl
*dl
= occ_show
->dl
;
4101 struct dl_opts
*opts
= &dl
->opts
;
4102 struct occ_port
*occ_port
;
4104 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
4105 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
4106 occ_port
->port_index
, true, false);
4107 pr_out_occ_show_port(dl
, occ_port
);
4108 pr_out_port_handle_end(dl
);
4112 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
4115 struct occ_port
*occ_port
;
4116 struct occ_item
*occ_item
;
4118 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
4121 occ_port
= occ_port_get(occ_show
, tb
);
4123 occ_show
->err
= -ENOMEM
;
4127 occ_item
= occ_item_alloc();
4129 occ_show
->err
= -ENOMEM
;
4132 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4133 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4134 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4135 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
4138 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4140 struct occ_show
*occ_show
= data
;
4141 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4142 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4144 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4145 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4146 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4147 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4148 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4149 return MNL_CB_ERROR
;
4150 cmd_sb_occ_port_pool_process(occ_show
, tb
);
4154 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
4157 struct occ_port
*occ_port
;
4158 struct occ_item
*occ_item
;
4161 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
4164 occ_port
= occ_port_get(occ_show
, tb
);
4166 occ_show
->err
= -ENOMEM
;
4170 occ_item
= occ_item_alloc();
4172 occ_show
->err
= -ENOMEM
;
4175 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
4176 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4177 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4178 occ_item
->bound_pool_index
=
4179 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4180 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
4181 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
4182 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
4183 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
4184 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
4186 occ_item_free(occ_item
);
4189 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4191 struct occ_show
*occ_show
= data
;
4192 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4193 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4195 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4196 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4197 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4198 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
4199 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4200 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4201 return MNL_CB_ERROR
;
4202 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
4206 static int cmd_sb_occ_show(struct dl
*dl
)
4208 struct nlmsghdr
*nlh
;
4209 struct occ_show
*occ_show
;
4210 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
4213 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
4217 occ_show
= occ_show_alloc(dl
);
4221 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
4223 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4224 cmd_sb_occ_port_pool_process_cb
, occ_show
);
4228 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
4230 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4231 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
4235 pr_out_section_start(dl
, "occupancy");
4236 pr_out_occ_show(occ_show
);
4237 pr_out_section_end(dl
);
4240 occ_show_free(occ_show
);
4244 static int cmd_sb_occ_snapshot(struct dl
*dl
)
4246 struct nlmsghdr
*nlh
;
4249 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
4250 NLM_F_REQUEST
| NLM_F_ACK
);
4252 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4256 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4259 static int cmd_sb_occ_clearmax(struct dl
*dl
)
4261 struct nlmsghdr
*nlh
;
4264 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
4265 NLM_F_REQUEST
| NLM_F_ACK
);
4267 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4271 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4274 static int cmd_sb_occ(struct dl
*dl
)
4276 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4279 } else if (dl_argv_match(dl
, "show") ||
4280 dl_argv_match(dl
, "list")) {
4282 return cmd_sb_occ_show(dl
);
4283 } else if (dl_argv_match(dl
, "snapshot")) {
4285 return cmd_sb_occ_snapshot(dl
);
4286 } else if (dl_argv_match(dl
, "clearmax")) {
4288 return cmd_sb_occ_clearmax(dl
);
4290 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4294 static int cmd_sb(struct dl
*dl
)
4296 if (dl_argv_match(dl
, "help")) {
4299 } else if (dl_argv_match(dl
, "show") ||
4300 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
4302 return cmd_sb_show(dl
);
4303 } else if (dl_argv_match(dl
, "pool")) {
4305 return cmd_sb_pool(dl
);
4306 } else if (dl_argv_match(dl
, "port")) {
4308 return cmd_sb_port(dl
);
4309 } else if (dl_argv_match(dl
, "tc")) {
4311 return cmd_sb_tc(dl
);
4312 } else if (dl_argv_match(dl
, "occupancy")) {
4314 return cmd_sb_occ(dl
);
4316 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4320 static const char *cmd_name(uint8_t cmd
)
4323 case DEVLINK_CMD_UNSPEC
: return "unspec";
4324 case DEVLINK_CMD_GET
: return "get";
4325 case DEVLINK_CMD_SET
: return "set";
4326 case DEVLINK_CMD_NEW
: return "new";
4327 case DEVLINK_CMD_DEL
: return "del";
4328 case DEVLINK_CMD_PORT_GET
: return "get";
4329 case DEVLINK_CMD_PORT_SET
: return "set";
4330 case DEVLINK_CMD_PORT_NEW
: return "new";
4331 case DEVLINK_CMD_PORT_DEL
: return "del";
4332 case DEVLINK_CMD_PARAM_GET
: return "get";
4333 case DEVLINK_CMD_PARAM_SET
: return "set";
4334 case DEVLINK_CMD_PARAM_NEW
: return "new";
4335 case DEVLINK_CMD_PARAM_DEL
: return "del";
4336 case DEVLINK_CMD_REGION_GET
: return "get";
4337 case DEVLINK_CMD_REGION_SET
: return "set";
4338 case DEVLINK_CMD_REGION_NEW
: return "new";
4339 case DEVLINK_CMD_REGION_DEL
: return "del";
4340 case DEVLINK_CMD_FLASH_UPDATE
: return "begin";
4341 case DEVLINK_CMD_FLASH_UPDATE_END
: return "end";
4342 case DEVLINK_CMD_FLASH_UPDATE_STATUS
: return "status";
4343 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
: return "status";
4344 case DEVLINK_CMD_TRAP_GET
: return "get";
4345 case DEVLINK_CMD_TRAP_SET
: return "set";
4346 case DEVLINK_CMD_TRAP_NEW
: return "new";
4347 case DEVLINK_CMD_TRAP_DEL
: return "del";
4348 case DEVLINK_CMD_TRAP_GROUP_GET
: return "get";
4349 case DEVLINK_CMD_TRAP_GROUP_SET
: return "set";
4350 case DEVLINK_CMD_TRAP_GROUP_NEW
: return "new";
4351 case DEVLINK_CMD_TRAP_GROUP_DEL
: return "del";
4352 case DEVLINK_CMD_TRAP_POLICER_GET
: return "get";
4353 case DEVLINK_CMD_TRAP_POLICER_SET
: return "set";
4354 case DEVLINK_CMD_TRAP_POLICER_NEW
: return "new";
4355 case DEVLINK_CMD_TRAP_POLICER_DEL
: return "del";
4356 default: return "<unknown cmd>";
4360 static const char *cmd_obj(uint8_t cmd
)
4363 case DEVLINK_CMD_UNSPEC
: return "unspec";
4364 case DEVLINK_CMD_GET
:
4365 case DEVLINK_CMD_SET
:
4366 case DEVLINK_CMD_NEW
:
4367 case DEVLINK_CMD_DEL
:
4369 case DEVLINK_CMD_PORT_GET
:
4370 case DEVLINK_CMD_PORT_SET
:
4371 case DEVLINK_CMD_PORT_NEW
:
4372 case DEVLINK_CMD_PORT_DEL
:
4374 case DEVLINK_CMD_PARAM_GET
:
4375 case DEVLINK_CMD_PARAM_SET
:
4376 case DEVLINK_CMD_PARAM_NEW
:
4377 case DEVLINK_CMD_PARAM_DEL
:
4379 case DEVLINK_CMD_REGION_GET
:
4380 case DEVLINK_CMD_REGION_SET
:
4381 case DEVLINK_CMD_REGION_NEW
:
4382 case DEVLINK_CMD_REGION_DEL
:
4384 case DEVLINK_CMD_FLASH_UPDATE
:
4385 case DEVLINK_CMD_FLASH_UPDATE_END
:
4386 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4388 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4390 case DEVLINK_CMD_TRAP_GET
:
4391 case DEVLINK_CMD_TRAP_SET
:
4392 case DEVLINK_CMD_TRAP_NEW
:
4393 case DEVLINK_CMD_TRAP_DEL
:
4395 case DEVLINK_CMD_TRAP_GROUP_GET
:
4396 case DEVLINK_CMD_TRAP_GROUP_SET
:
4397 case DEVLINK_CMD_TRAP_GROUP_NEW
:
4398 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4399 return "trap-group";
4400 case DEVLINK_CMD_TRAP_POLICER_GET
:
4401 case DEVLINK_CMD_TRAP_POLICER_SET
:
4402 case DEVLINK_CMD_TRAP_POLICER_NEW
:
4403 case DEVLINK_CMD_TRAP_POLICER_DEL
:
4404 return "trap-policer";
4405 default: return "<unknown obj>";
4409 static void pr_out_mon_header(uint8_t cmd
)
4411 if (!is_json_context()) {
4412 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
4414 open_json_object(NULL
);
4415 print_string(PRINT_JSON
, "command", NULL
, cmd_name(cmd
));
4416 open_json_object(cmd_obj(cmd
));
4420 static void pr_out_mon_footer(void)
4422 if (is_json_context()) {
4423 close_json_object();
4424 close_json_object();
4428 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
4430 const char *obj
= cmd_obj(cmd
);
4431 unsigned int index
= 0;
4432 const char *cur_obj
;
4436 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4437 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
4443 static void pr_out_flash_update(struct dl
*dl
, struct nlattr
**tb
)
4445 __pr_out_handle_start(dl
, tb
, true, false);
4447 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]) {
4448 check_indent_newline(dl
);
4449 print_string(PRINT_ANY
, "msg", "msg %s",
4450 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]));
4452 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]) {
4453 check_indent_newline(dl
);
4454 print_string(PRINT_ANY
, "component", "component %s",
4455 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]));
4458 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
4459 pr_out_u64(dl
, "done",
4460 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]));
4462 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
4463 pr_out_u64(dl
, "total",
4464 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]));
4466 pr_out_handle_end(dl
);
4469 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
);
4470 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
);
4471 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4472 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4473 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4475 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
4477 struct dl
*dl
= data
;
4478 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4479 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4480 uint8_t cmd
= genl
->cmd
;
4482 if (!cmd_filter_check(dl
, cmd
))
4486 case DEVLINK_CMD_GET
: /* fall through */
4487 case DEVLINK_CMD_SET
: /* fall through */
4488 case DEVLINK_CMD_NEW
: /* fall through */
4489 case DEVLINK_CMD_DEL
:
4490 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4491 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4492 return MNL_CB_ERROR
;
4493 pr_out_mon_header(genl
->cmd
);
4494 pr_out_handle(dl
, tb
);
4495 pr_out_mon_footer();
4497 case DEVLINK_CMD_PORT_GET
: /* fall through */
4498 case DEVLINK_CMD_PORT_SET
: /* fall through */
4499 case DEVLINK_CMD_PORT_NEW
: /* fall through */
4500 case DEVLINK_CMD_PORT_DEL
:
4501 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4502 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4503 !tb
[DEVLINK_ATTR_PORT_INDEX
])
4504 return MNL_CB_ERROR
;
4505 pr_out_mon_header(genl
->cmd
);
4506 pr_out_port(dl
, tb
);
4507 pr_out_mon_footer();
4509 case DEVLINK_CMD_PARAM_GET
: /* fall through */
4510 case DEVLINK_CMD_PARAM_SET
: /* fall through */
4511 case DEVLINK_CMD_PARAM_NEW
: /* fall through */
4512 case DEVLINK_CMD_PARAM_DEL
:
4513 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4514 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4515 !tb
[DEVLINK_ATTR_PARAM
])
4516 return MNL_CB_ERROR
;
4517 pr_out_mon_header(genl
->cmd
);
4518 pr_out_param(dl
, tb
, false);
4519 pr_out_mon_footer();
4521 case DEVLINK_CMD_REGION_GET
: /* fall through */
4522 case DEVLINK_CMD_REGION_SET
: /* fall through */
4523 case DEVLINK_CMD_REGION_NEW
: /* fall through */
4524 case DEVLINK_CMD_REGION_DEL
:
4525 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4526 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4527 !tb
[DEVLINK_ATTR_REGION_NAME
])
4528 return MNL_CB_ERROR
;
4529 pr_out_mon_header(genl
->cmd
);
4530 pr_out_region(dl
, tb
);
4531 pr_out_mon_footer();
4533 case DEVLINK_CMD_FLASH_UPDATE
: /* fall through */
4534 case DEVLINK_CMD_FLASH_UPDATE_END
: /* fall through */
4535 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4536 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4537 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4538 return MNL_CB_ERROR
;
4539 pr_out_mon_header(genl
->cmd
);
4540 pr_out_flash_update(dl
, tb
);
4541 pr_out_mon_footer();
4543 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4544 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4545 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4546 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
4547 return MNL_CB_ERROR
;
4548 pr_out_mon_header(genl
->cmd
);
4549 pr_out_health(dl
, tb
);
4550 pr_out_mon_footer();
4552 case DEVLINK_CMD_TRAP_GET
: /* fall through */
4553 case DEVLINK_CMD_TRAP_SET
: /* fall through */
4554 case DEVLINK_CMD_TRAP_NEW
: /* fall through */
4555 case DEVLINK_CMD_TRAP_DEL
:
4556 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4557 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4558 !tb
[DEVLINK_ATTR_TRAP_NAME
] ||
4559 !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
4560 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
4561 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4562 !tb
[DEVLINK_ATTR_TRAP_METADATA
] ||
4563 !tb
[DEVLINK_ATTR_STATS
])
4564 return MNL_CB_ERROR
;
4565 pr_out_mon_header(genl
->cmd
);
4566 pr_out_trap(dl
, tb
, false);
4567 pr_out_mon_footer();
4569 case DEVLINK_CMD_TRAP_GROUP_GET
: /* fall through */
4570 case DEVLINK_CMD_TRAP_GROUP_SET
: /* fall through */
4571 case DEVLINK_CMD_TRAP_GROUP_NEW
: /* fall through */
4572 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4573 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4574 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4575 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4576 !tb
[DEVLINK_ATTR_STATS
])
4577 return MNL_CB_ERROR
;
4578 pr_out_mon_header(genl
->cmd
);
4579 pr_out_trap_group(dl
, tb
, false);
4580 pr_out_mon_footer();
4582 case DEVLINK_CMD_TRAP_POLICER_GET
: /* fall through */
4583 case DEVLINK_CMD_TRAP_POLICER_SET
: /* fall through */
4584 case DEVLINK_CMD_TRAP_POLICER_NEW
: /* fall through */
4585 case DEVLINK_CMD_TRAP_POLICER_DEL
: /* fall through */
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_TRAP_POLICER_ID
] ||
4589 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
4590 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
4591 return MNL_CB_ERROR
;
4592 pr_out_mon_header(genl
->cmd
);
4593 pr_out_trap_policer(dl
, tb
, false);
4599 static int cmd_mon_show(struct dl
*dl
)
4602 unsigned int index
= 0;
4603 const char *cur_obj
;
4605 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4606 if (strcmp(cur_obj
, "all") != 0 &&
4607 strcmp(cur_obj
, "dev") != 0 &&
4608 strcmp(cur_obj
, "port") != 0 &&
4609 strcmp(cur_obj
, "health") != 0 &&
4610 strcmp(cur_obj
, "trap") != 0 &&
4611 strcmp(cur_obj
, "trap-group") != 0 &&
4612 strcmp(cur_obj
, "trap-policer") != 0) {
4613 pr_err("Unknown object \"%s\"\n", cur_obj
);
4617 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
4620 open_json_object(NULL
);
4621 open_json_array(PRINT_JSON
, "mon");
4622 err
= _mnlg_socket_recv_run_intr(dl
->nlg
, cmd_mon_show_cb
, dl
);
4623 close_json_array(PRINT_JSON
, NULL
);
4624 close_json_object();
4630 static void cmd_mon_help(void)
4632 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
4633 "where OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
4636 static int cmd_mon(struct dl
*dl
)
4638 if (dl_argv_match(dl
, "help")) {
4642 return cmd_mon_show(dl
);
4645 struct dpipe_field
{
4648 unsigned int bitwidth
;
4649 enum devlink_dpipe_field_mapping_type mapping_type
;
4652 struct dpipe_header
{
4653 struct list_head list
;
4656 struct dpipe_field
*fields
;
4657 unsigned int fields_count
;
4660 struct dpipe_table
{
4661 struct list_head list
;
4663 unsigned int resource_id
;
4664 bool resource_valid
;
4667 struct dpipe_tables
{
4668 struct list_head table_list
;
4678 enum devlink_resource_unit unit
;
4683 struct list_head list
;
4684 struct list_head resource_list
;
4685 struct resource
*parent
;
4689 struct list_head resource_list
;
4692 struct resource_ctx
{
4695 struct resources
*resources
;
4696 struct dpipe_tables
*tables
;
4697 bool print_resources
;
4698 bool pending_change
;
4701 static struct resource
*resource_alloc(void)
4703 struct resource
*resource
;
4705 resource
= calloc(1, sizeof(struct resource
));
4708 INIT_LIST_HEAD(&resource
->resource_list
);
4712 static void resource_free(struct resource
*resource
)
4714 struct resource
*child_resource
, *tmp
;
4716 list_for_each_entry_safe(child_resource
, tmp
, &resource
->resource_list
,
4718 free(child_resource
->name
);
4719 resource_free(child_resource
);
4724 static struct resources
*resources_alloc(void)
4726 struct resources
*resources
;
4728 resources
= calloc(1, sizeof(struct resources
));
4731 INIT_LIST_HEAD(&resources
->resource_list
);
4735 static void resources_free(struct resources
*resources
)
4737 struct resource
*resource
, *tmp
;
4739 list_for_each_entry_safe(resource
, tmp
, &resources
->resource_list
, list
)
4740 resource_free(resource
);
4743 static int resource_ctx_init(struct resource_ctx
*ctx
, struct dl
*dl
)
4745 ctx
->resources
= resources_alloc();
4746 if (!ctx
->resources
)
4752 static void resource_ctx_fini(struct resource_ctx
*ctx
)
4754 resources_free(ctx
->resources
);
4760 struct list_head global_headers
;
4761 struct list_head local_headers
;
4762 struct dpipe_tables
*tables
;
4763 struct resources
*resources
;
4768 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
4770 struct dpipe_header
*header
;
4772 header
= calloc(1, sizeof(struct dpipe_header
));
4775 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
4776 if (!header
->fields
)
4777 goto err_fields_alloc
;
4778 header
->fields_count
= fields_count
;
4786 static void dpipe_header_free(struct dpipe_header
*header
)
4788 free(header
->fields
);
4792 static void dpipe_header_clear(struct dpipe_header
*header
)
4794 struct dpipe_field
*field
;
4797 for (i
= 0; i
< header
->fields_count
; i
++) {
4798 field
= &header
->fields
[i
];
4804 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
4805 struct dpipe_header
*header
, bool global
)
4808 list_add(&header
->list
, &ctx
->global_headers
);
4810 list_add(&header
->list
, &ctx
->local_headers
);
4813 static void dpipe_header_del(struct dpipe_header
*header
)
4815 list_del(&header
->list
);
4818 static struct dpipe_table
*dpipe_table_alloc(void)
4820 return calloc(1, sizeof(struct dpipe_table
));
4823 static void dpipe_table_free(struct dpipe_table
*table
)
4828 static struct dpipe_tables
*dpipe_tables_alloc(void)
4830 struct dpipe_tables
*tables
;
4832 tables
= calloc(1, sizeof(struct dpipe_tables
));
4835 INIT_LIST_HEAD(&tables
->table_list
);
4839 static void dpipe_tables_free(struct dpipe_tables
*tables
)
4841 struct dpipe_table
*table
, *tmp
;
4843 list_for_each_entry_safe(table
, tmp
, &tables
->table_list
, list
)
4844 dpipe_table_free(table
);
4848 static int dpipe_ctx_init(struct dpipe_ctx
*ctx
, struct dl
*dl
)
4850 ctx
->tables
= dpipe_tables_alloc();
4855 INIT_LIST_HEAD(&ctx
->global_headers
);
4856 INIT_LIST_HEAD(&ctx
->local_headers
);
4860 static void dpipe_ctx_fini(struct dpipe_ctx
*ctx
)
4862 struct dpipe_header
*header
, *tmp
;
4864 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
4866 dpipe_header_del(header
);
4867 dpipe_header_clear(header
);
4868 dpipe_header_free(header
);
4870 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
4872 dpipe_header_del(header
);
4873 dpipe_header_clear(header
);
4874 dpipe_header_free(header
);
4876 dpipe_tables_free(ctx
->tables
);
4879 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
4880 uint32_t header_id
, bool global
)
4882 struct list_head
*header_list
;
4883 struct dpipe_header
*header
;
4886 header_list
= &ctx
->global_headers
;
4888 header_list
= &ctx
->local_headers
;
4889 list_for_each_entry(header
, header_list
, list
) {
4890 if (header
->id
!= header_id
)
4892 return header
->name
;
4897 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
4899 uint32_t field_id
, bool global
)
4901 struct list_head
*header_list
;
4902 struct dpipe_header
*header
;
4905 header_list
= &ctx
->global_headers
;
4907 header_list
= &ctx
->local_headers
;
4908 list_for_each_entry(header
, header_list
, list
) {
4909 if (header
->id
!= header_id
)
4911 return header
->fields
[field_id
].name
;
4917 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
4919 switch (mapping_type
) {
4920 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
4922 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
4930 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
4931 uint32_t field_id
, bool global
)
4933 enum devlink_dpipe_field_mapping_type mapping_type
;
4934 struct list_head
*header_list
;
4935 struct dpipe_header
*header
;
4938 header_list
= &ctx
->global_headers
;
4940 header_list
= &ctx
->local_headers
;
4941 list_for_each_entry(header
, header_list
, list
) {
4942 if (header
->id
!= header_id
)
4944 mapping_type
= header
->fields
[field_id
].mapping_type
;
4945 return dpipe_field_mapping_e2s(mapping_type
);
4950 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
4951 struct dpipe_field
*fields
,
4952 unsigned int field_count
)
4954 struct dpipe_field
*field
;
4957 for (i
= 0; i
< field_count
; i
++) {
4959 pr_out_entry_start(ctx
->dl
);
4960 check_indent_newline(ctx
->dl
);
4961 print_string(PRINT_ANY
, "name", "name %s", field
->name
);
4962 if (ctx
->dl
->verbose
)
4963 print_uint(PRINT_ANY
, "id", " id %u", field
->id
);
4964 print_uint(PRINT_ANY
, "bitwidth", " bitwidth %u", field
->bitwidth
);
4965 if (field
->mapping_type
) {
4966 print_string(PRINT_ANY
, "mapping_type", " mapping_type %s",
4967 dpipe_field_mapping_e2s(field
->mapping_type
));
4969 pr_out_entry_end(ctx
->dl
);
4974 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
4975 struct dpipe_header
*header
, bool global
)
4977 pr_out_handle_start_arr(ctx
->dl
, tb
);
4978 check_indent_newline(ctx
->dl
);
4979 print_string(PRINT_ANY
, "name", "name %s", header
->name
);
4980 if (ctx
->dl
->verbose
) {
4981 print_uint(PRINT_ANY
, "id", " id %u", header
->id
);
4982 print_bool(PRINT_ANY
, "global", " global %s", global
);
4984 pr_out_array_start(ctx
->dl
, "field");
4985 pr_out_dpipe_fields(ctx
, header
->fields
,
4986 header
->fields_count
);
4987 pr_out_array_end(ctx
->dl
);
4988 pr_out_handle_end(ctx
->dl
);
4991 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
4994 struct dpipe_header
*header
;
4996 list_for_each_entry(header
, &ctx
->local_headers
, list
)
4997 pr_out_dpipe_header(ctx
, tb
, header
, false);
4999 list_for_each_entry(header
, &ctx
->global_headers
, list
)
5000 pr_out_dpipe_header(ctx
, tb
, header
, true);
5003 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
5005 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
5009 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
5010 if (err
!= MNL_CB_OK
)
5012 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
5013 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
5014 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
5015 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
5018 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
5019 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5020 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
5021 field
->name
= strdup(name
);
5024 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
5028 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
5029 struct dpipe_field
*fields
)
5031 struct nlattr
*nla_field
;
5035 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
5036 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
5044 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
5046 struct nlattr
*nla_field
;
5047 unsigned int count
= 0;
5049 mnl_attr_for_each_nested(nla_field
, nla_fields
)
5054 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5056 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
5057 struct dpipe_header
*header
;
5058 unsigned int fields_count
;
5059 const char *header_name
;
5063 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
5064 if (err
!= MNL_CB_OK
)
5067 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
5068 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5069 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
5072 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
5073 header
= dpipe_header_alloc(fields_count
);
5077 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
5078 header
->name
= strdup(header_name
);
5079 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5080 header
->fields_count
= fields_count
;
5081 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5083 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
5087 dpipe_header_add(ctx
, header
, global
);
5091 dpipe_header_free(header
);
5095 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5097 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
5098 struct nlattr
*nla_header
;
5101 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
5102 err
= dpipe_header_get(ctx
, nla_header
);
5109 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
5111 struct dpipe_ctx
*ctx
= data
;
5112 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5113 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5116 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5117 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5118 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
5119 return MNL_CB_ERROR
;
5120 err
= dpipe_headers_get(ctx
, tb
);
5123 return MNL_CB_ERROR
;
5126 if (ctx
->print_headers
)
5127 pr_out_dpipe_headers(ctx
, tb
);
5131 static int cmd_dpipe_headers_show(struct dl
*dl
)
5133 struct nlmsghdr
*nlh
;
5134 struct dpipe_ctx ctx
= {};
5135 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5138 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5140 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
5144 err
= dpipe_ctx_init(&ctx
, dl
);
5148 ctx
.print_headers
= true;
5150 pr_out_section_start(dl
, "header");
5151 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5153 pr_err("error get headers %s\n", strerror(ctx
.err
));
5154 pr_out_section_end(dl
);
5156 dpipe_ctx_fini(&ctx
);
5160 static void cmd_dpipe_help(void)
5162 pr_err("Usage: devlink dpipe table show DEV [ name TABLE_NAME ]\n");
5163 pr_err(" devlink dpipe table set DEV name TABLE_NAME\n");
5164 pr_err(" [ counters_enabled { true | false } ]\n");
5165 pr_err(" devlink dpipe table dump DEV name TABLE_NAME\n");
5166 pr_err(" devlink dpipe header show DEV\n");
5169 static int cmd_dpipe_header(struct dl
*dl
)
5171 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5174 } else if (dl_argv_match(dl
, "show")) {
5176 return cmd_dpipe_headers_show(dl
);
5178 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5183 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
5185 switch (action_type
) {
5186 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
5187 return "field_modify";
5193 struct dpipe_op_info
{
5199 struct dpipe_action
{
5200 struct dpipe_op_info info
;
5204 static void pr_out_dpipe_action(struct dpipe_action
*action
,
5205 struct dpipe_ctx
*ctx
)
5207 struct dpipe_op_info
*op_info
= &action
->info
;
5208 const char *mapping
;
5210 check_indent_newline(ctx
->dl
);
5211 print_string(PRINT_ANY
, "type", "type %s",
5212 dpipe_action_type_e2s(action
->type
));
5213 print_string(PRINT_ANY
, "header", " header %s",
5214 dpipe_header_id2s(ctx
, op_info
->header_id
,
5215 op_info
->header_global
));
5216 print_string(PRINT_ANY
, "field", " field %s",
5217 dpipe_field_id2s(ctx
, op_info
->header_id
,
5219 op_info
->header_global
));
5220 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5222 op_info
->header_global
);
5224 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5227 static int dpipe_action_parse(struct dpipe_action
*action
, struct nlattr
*nl
)
5229 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
5232 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
5233 if (err
!= MNL_CB_OK
)
5236 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
5237 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5238 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5239 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5243 action
->type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
5244 action
->info
.header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5245 action
->info
.field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5246 action
->info
.header_global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5251 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
5252 struct nlattr
*nla_actions
)
5254 struct nlattr
*nla_action
;
5255 struct dpipe_action action
;
5257 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
5258 pr_out_entry_start(ctx
->dl
);
5259 if (dpipe_action_parse(&action
, nla_action
))
5260 goto err_action_parse
;
5261 pr_out_dpipe_action(&action
, ctx
);
5262 pr_out_entry_end(ctx
->dl
);
5267 pr_out_entry_end(ctx
->dl
);
5272 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
5274 switch (match_type
) {
5275 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
5276 return "field_exact";
5282 struct dpipe_match
{
5283 struct dpipe_op_info info
;
5287 static void pr_out_dpipe_match(struct dpipe_match
*match
,
5288 struct dpipe_ctx
*ctx
)
5290 struct dpipe_op_info
*op_info
= &match
->info
;
5291 const char *mapping
;
5293 check_indent_newline(ctx
->dl
);
5294 print_string(PRINT_ANY
, "type", "type %s",
5295 dpipe_match_type_e2s(match
->type
));
5296 print_string(PRINT_ANY
, "header", " header %s",
5297 dpipe_header_id2s(ctx
, op_info
->header_id
,
5298 op_info
->header_global
));
5299 print_string(PRINT_ANY
, "field", " field %s",
5300 dpipe_field_id2s(ctx
, op_info
->header_id
,
5302 op_info
->header_global
));
5303 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5305 op_info
->header_global
);
5307 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5310 static int dpipe_match_parse(struct dpipe_match
*match
,
5314 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
5317 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
5318 if (err
!= MNL_CB_OK
)
5321 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
5322 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5323 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5324 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5328 match
->type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
5329 match
->info
.header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5330 match
->info
.field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5331 match
->info
.header_global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5336 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
5337 struct nlattr
*nla_matches
)
5339 struct nlattr
*nla_match
;
5340 struct dpipe_match match
;
5342 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
5343 pr_out_entry_start(ctx
->dl
);
5344 if (dpipe_match_parse(&match
, nla_match
))
5345 goto err_match_parse
;
5346 pr_out_dpipe_match(&match
, ctx
);
5347 pr_out_entry_end(ctx
->dl
);
5352 pr_out_entry_end(ctx
->dl
);
5356 static struct resource
*
5357 resource_find(struct resources
*resources
, struct resource
*resource
,
5358 uint64_t resource_id
)
5360 struct list_head
*list_head
;
5363 list_head
= &resources
->resource_list
;
5365 list_head
= &resource
->resource_list
;
5367 list_for_each_entry(resource
, list_head
, list
) {
5368 struct resource
*child_resource
;
5370 if (resource
->id
== resource_id
)
5373 child_resource
= resource_find(resources
, resource
,
5376 return child_resource
;
5382 resource_path_print(struct dl
*dl
, struct resources
*resources
,
5383 uint64_t resource_id
)
5385 struct resource
*resource
, *parent_resource
;
5386 const char del
[] = "/";
5390 resource
= resource_find(resources
, NULL
, resource_id
);
5394 for (parent_resource
= resource
; parent_resource
;
5395 parent_resource
= parent_resource
->parent
)
5396 path_len
+= strlen(parent_resource
->name
) + 1;
5399 path
= calloc(1, path_len
);
5403 path
+= path_len
- 1;
5404 for (parent_resource
= resource
; parent_resource
;
5405 parent_resource
= parent_resource
->parent
) {
5406 path
-= strlen(parent_resource
->name
);
5407 memcpy(path
, parent_resource
->name
,
5408 strlen(parent_resource
->name
));
5409 path
-= strlen(del
);
5410 memcpy(path
, del
, strlen(del
));
5412 check_indent_newline(dl
);
5413 print_string(PRINT_ANY
, "resource_path", "resource_path %s", path
);
5417 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5419 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
5420 struct dpipe_table
*table
;
5421 uint32_t resource_units
;
5422 bool counters_enabled
;
5423 bool resource_valid
;
5427 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
5428 if (err
!= MNL_CB_OK
)
5431 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
5432 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
5433 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
5434 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
5435 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
5439 table
= dpipe_table_alloc();
5443 table
->name
= strdup(mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]));
5444 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
5445 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
5447 resource_valid
= nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
] &&
5449 if (resource_valid
) {
5450 table
->resource_id
= mnl_attr_get_u64(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
]);
5451 table
->resource_valid
= true;
5454 list_add_tail(&table
->list
, &ctx
->tables
->table_list
);
5455 if (!ctx
->print_tables
)
5458 check_indent_newline(ctx
->dl
);
5459 print_string(PRINT_ANY
, "name", "name %s", table
->name
);
5460 print_uint(PRINT_ANY
, "size", " size %u", size
);
5461 print_bool(PRINT_ANY
, "counters_enabled", " counters_enabled %s", counters_enabled
);
5463 if (resource_valid
) {
5464 resource_units
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS
]);
5465 resource_path_print(ctx
->dl
, ctx
->resources
,
5466 table
->resource_id
);
5467 print_uint(PRINT_ANY
, "resource_units", " resource_units %u",
5471 pr_out_array_start(ctx
->dl
, "match");
5472 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
5473 goto err_matches_show
;
5474 pr_out_array_end(ctx
->dl
);
5476 pr_out_array_start(ctx
->dl
, "action");
5477 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
5478 goto err_actions_show
;
5479 pr_out_array_end(ctx
->dl
);
5485 pr_out_array_end(ctx
->dl
);
5489 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5491 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
5492 struct nlattr
*nla_table
;
5494 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
5495 if (ctx
->print_tables
)
5496 pr_out_handle_start_arr(ctx
->dl
, tb
);
5497 if (dpipe_table_show(ctx
, nla_table
))
5498 goto err_table_show
;
5499 if (ctx
->print_tables
)
5500 pr_out_handle_end(ctx
->dl
);
5505 if (ctx
->print_tables
)
5506 pr_out_handle_end(ctx
->dl
);
5510 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5512 struct dpipe_ctx
*ctx
= data
;
5513 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5514 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5516 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5517 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5518 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
5519 return MNL_CB_ERROR
;
5521 if (dpipe_tables_show(ctx
, tb
))
5522 return MNL_CB_ERROR
;
5526 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
);
5528 static int cmd_dpipe_table_show(struct dl
*dl
)
5530 struct nlmsghdr
*nlh
;
5531 struct dpipe_ctx dpipe_ctx
= {};
5532 struct resource_ctx resource_ctx
= {};
5533 uint16_t flags
= NLM_F_REQUEST
;
5536 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
5540 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5542 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5546 dpipe_ctx
.print_tables
= true;
5548 dl_opts_put(nlh
, dl
);
5549 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
,
5552 pr_err("error get headers %s\n", strerror(dpipe_ctx
.err
));
5553 goto err_headers_get
;
5556 err
= resource_ctx_init(&resource_ctx
, dl
);
5558 goto err_resource_ctx_init
;
5560 resource_ctx
.print_resources
= false;
5561 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
, flags
);
5562 dl_opts_put(nlh
, dl
);
5563 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
5566 dpipe_ctx
.resources
= resource_ctx
.resources
;
5568 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5569 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
5570 dl_opts_put(nlh
, dl
);
5572 pr_out_section_start(dl
, "table");
5573 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, &dpipe_ctx
);
5574 pr_out_section_end(dl
);
5576 resource_ctx_fini(&resource_ctx
);
5577 dpipe_ctx_fini(&dpipe_ctx
);
5580 err_resource_ctx_init
:
5582 dpipe_ctx_fini(&dpipe_ctx
);
5586 static int cmd_dpipe_table_set(struct dl
*dl
)
5588 struct nlmsghdr
*nlh
;
5591 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
5592 NLM_F_REQUEST
| NLM_F_ACK
);
5594 err
= dl_argv_parse_put(nlh
, dl
,
5595 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
5596 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
5600 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5603 enum dpipe_value_type
{
5604 DPIPE_VALUE_TYPE_VALUE
,
5605 DPIPE_VALUE_TYPE_MASK
,
5609 dpipe_value_type_e2s(enum dpipe_value_type type
)
5612 case DPIPE_VALUE_TYPE_VALUE
:
5614 case DPIPE_VALUE_TYPE_MASK
:
5615 return "value_mask";
5621 struct dpipe_field_printer
{
5622 unsigned int field_id
;
5623 void (*printer
)(struct dpipe_ctx
*, enum dpipe_value_type
, void *);
5626 struct dpipe_header_printer
{
5627 struct dpipe_field_printer
*printers
;
5628 unsigned int printers_count
;
5629 unsigned int header_id
;
5632 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx
*ctx
,
5633 enum dpipe_value_type type
,
5636 struct in_addr ip_addr
;
5638 ip_addr
.s_addr
= htonl(*(uint32_t *)value
);
5639 check_indent_newline(ctx
->dl
);
5640 print_string_name_value(dpipe_value_type_e2s(type
), inet_ntoa(ip_addr
));
5644 dpipe_field_printer_ethernet_addr(struct dpipe_ctx
*ctx
,
5645 enum dpipe_value_type type
,
5648 check_indent_newline(ctx
->dl
);
5649 print_string_name_value(dpipe_value_type_e2s(type
),
5650 ether_ntoa((struct ether_addr
*)value
));
5653 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx
*ctx
,
5654 enum dpipe_value_type type
,
5657 char str
[INET6_ADDRSTRLEN
];
5659 inet_ntop(AF_INET6
, value
, str
, INET6_ADDRSTRLEN
);
5660 check_indent_newline(ctx
->dl
);
5661 print_string_name_value(dpipe_value_type_e2s(type
), str
);
5664 static struct dpipe_field_printer dpipe_field_printers_ipv4
[] = {
5666 .printer
= dpipe_field_printer_ipv4_addr
,
5667 .field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
,
5671 static struct dpipe_header_printer dpipe_header_printer_ipv4
= {
5672 .printers
= dpipe_field_printers_ipv4
,
5673 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv4
),
5674 .header_id
= DEVLINK_DPIPE_HEADER_IPV4
,
5677 static struct dpipe_field_printer dpipe_field_printers_ethernet
[] = {
5679 .printer
= dpipe_field_printer_ethernet_addr
,
5680 .field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
,
5684 static struct dpipe_header_printer dpipe_header_printer_ethernet
= {
5685 .printers
= dpipe_field_printers_ethernet
,
5686 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ethernet
),
5687 .header_id
= DEVLINK_DPIPE_HEADER_ETHERNET
,
5690 static struct dpipe_field_printer dpipe_field_printers_ipv6
[] = {
5692 .printer
= dpipe_field_printer_ipv6_addr
,
5693 .field_id
= DEVLINK_DPIPE_FIELD_IPV6_DST_IP
,
5697 static struct dpipe_header_printer dpipe_header_printer_ipv6
= {
5698 .printers
= dpipe_field_printers_ipv6
,
5699 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv6
),
5700 .header_id
= DEVLINK_DPIPE_HEADER_IPV6
,
5703 static struct dpipe_header_printer
*dpipe_header_printers
[] = {
5704 &dpipe_header_printer_ipv4
,
5705 &dpipe_header_printer_ethernet
,
5706 &dpipe_header_printer_ipv6
,
5709 static int dpipe_print_prot_header(struct dpipe_ctx
*ctx
,
5710 struct dpipe_op_info
*info
,
5711 enum dpipe_value_type type
,
5714 unsigned int header_printers_count
= ARRAY_SIZE(dpipe_header_printers
);
5715 struct dpipe_header_printer
*header_printer
;
5716 struct dpipe_field_printer
*field_printer
;
5717 unsigned int field_printers_count
;
5721 for (i
= 0; i
< header_printers_count
; i
++) {
5722 header_printer
= dpipe_header_printers
[i
];
5723 if (header_printer
->header_id
!= info
->header_id
)
5725 field_printers_count
= header_printer
->printers_count
;
5726 for (j
= 0; j
< field_printers_count
; j
++) {
5727 field_printer
= &header_printer
->printers
[j
];
5728 if (field_printer
->field_id
!= info
->field_id
)
5730 field_printer
->printer(ctx
, type
, value
);
5738 static void __pr_out_entry_value(struct dpipe_ctx
*ctx
,
5740 unsigned int value_len
,
5741 struct dpipe_op_info
*info
,
5742 enum dpipe_value_type type
)
5744 if (info
->header_global
&&
5745 !dpipe_print_prot_header(ctx
, info
, type
, value
))
5748 if (value_len
== sizeof(uint32_t)) {
5749 uint32_t *value_32
= value
;
5751 check_indent_newline(ctx
->dl
);
5752 print_uint_name_value(dpipe_value_type_e2s(type
), *value_32
);
5756 static void pr_out_dpipe_entry_value(struct dpipe_ctx
*ctx
,
5757 struct nlattr
**nla_match_value
,
5758 struct dpipe_op_info
*info
)
5760 void *value
, *value_mask
;
5761 uint32_t value_mapping
;
5765 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
5766 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
5768 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5769 value
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5772 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
5773 check_indent_newline(ctx
->dl
);
5774 print_uint(PRINT_ANY
, "mapping_value", "mapping_value %u", value_mapping
);
5778 value_mask
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5779 __pr_out_entry_value(ctx
, value_mask
, value_len
, info
,
5780 DPIPE_VALUE_TYPE_MASK
);
5783 __pr_out_entry_value(ctx
, value
, value_len
, info
, DPIPE_VALUE_TYPE_VALUE
);
5786 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
5789 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5790 struct dpipe_match match
;
5793 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
5794 if (err
!= MNL_CB_OK
)
5797 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
5798 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5802 pr_out_entry_start(ctx
->dl
);
5803 if (dpipe_match_parse(&match
,
5804 nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
5805 goto err_match_parse
;
5806 pr_out_dpipe_match(&match
, ctx
);
5807 pr_out_dpipe_entry_value(ctx
, nla_match_value
, &match
.info
);
5808 pr_out_entry_end(ctx
->dl
);
5813 pr_out_entry_end(ctx
->dl
);
5817 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
5820 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5821 struct dpipe_action action
;
5824 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
5825 if (err
!= MNL_CB_OK
)
5828 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
5829 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5833 pr_out_entry_start(ctx
->dl
);
5834 if (dpipe_action_parse(&action
,
5835 nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
5836 goto err_action_parse
;
5837 pr_out_dpipe_action(&action
, ctx
);
5838 pr_out_dpipe_entry_value(ctx
, nla_action_value
, &action
.info
);
5839 pr_out_entry_end(ctx
->dl
);
5844 pr_out_entry_end(ctx
->dl
);
5849 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
5850 struct nlattr
*nla_action_values
)
5852 struct nlattr
*nla_action_value
;
5854 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
5855 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
5862 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
5863 struct nlattr
*nla_match_values
)
5865 struct nlattr
*nla_match_value
;
5867 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
5868 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
5874 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5876 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
5877 uint32_t entry_index
;
5881 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
5882 if (err
!= MNL_CB_OK
)
5885 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
5886 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
5887 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
5891 check_indent_newline(ctx
->dl
);
5892 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
5893 print_uint(PRINT_ANY
, "index", "index %u", entry_index
);
5895 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
5896 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
5897 print_uint(PRINT_ANY
, "counter", " counter %u", counter
);
5900 pr_out_array_start(ctx
->dl
, "match_value");
5901 if (dpipe_tables_match_values_show(ctx
,
5902 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
5903 goto err_match_values_show
;
5904 pr_out_array_end(ctx
->dl
);
5906 pr_out_array_start(ctx
->dl
, "action_value");
5907 if (dpipe_tables_action_values_show(ctx
,
5908 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
5909 goto err_action_values_show
;
5910 pr_out_array_end(ctx
->dl
);
5913 err_action_values_show
:
5914 err_match_values_show
:
5915 pr_out_array_end(ctx
->dl
);
5919 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5921 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
5922 struct nlattr
*nla_entry
;
5924 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
5925 pr_out_handle_start_arr(ctx
->dl
, tb
);
5926 if (dpipe_entry_show(ctx
, nla_entry
))
5927 goto err_entry_show
;
5928 pr_out_handle_end(ctx
->dl
);
5933 pr_out_handle_end(ctx
->dl
);
5937 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5939 struct dpipe_ctx
*ctx
= data
;
5940 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5941 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5943 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5944 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5945 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
5946 return MNL_CB_ERROR
;
5948 if (dpipe_table_entries_show(ctx
, tb
))
5949 return MNL_CB_ERROR
;
5953 static int cmd_dpipe_table_dump(struct dl
*dl
)
5955 struct nlmsghdr
*nlh
;
5956 struct dpipe_ctx ctx
= {};
5957 uint16_t flags
= NLM_F_REQUEST
;
5960 err
= dpipe_ctx_init(&ctx
, dl
);
5964 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
5968 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5969 dl_opts_put(nlh
, dl
);
5970 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5972 pr_err("error get headers %s\n", strerror(ctx
.err
));
5976 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5977 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
5978 dl_opts_put(nlh
, dl
);
5980 pr_out_section_start(dl
, "table_entry");
5981 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, &ctx
);
5982 pr_out_section_end(dl
);
5984 dpipe_ctx_fini(&ctx
);
5988 static int cmd_dpipe_table(struct dl
*dl
)
5990 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5993 } else if (dl_argv_match(dl
, "show")) {
5995 return cmd_dpipe_table_show(dl
);
5996 } else if (dl_argv_match(dl
, "set")) {
5998 return cmd_dpipe_table_set(dl
);
5999 } else if (dl_argv_match(dl
, "dump")) {
6001 return cmd_dpipe_table_dump(dl
);
6003 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6007 static int cmd_dpipe(struct dl
*dl
)
6009 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6012 } else if (dl_argv_match(dl
, "header")) {
6014 return cmd_dpipe_header(dl
);
6015 } else if (dl_argv_match(dl
, "table")) {
6017 return cmd_dpipe_table(dl
);
6019 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6024 resource_parse(struct resource_ctx
*ctx
, struct resource
*resource
,
6025 struct nlattr
**nla_resource
)
6027 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
] ||
6028 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
] ||
6029 !nla_resource
[DEVLINK_ATTR_RESOURCE_ID
] ||
6030 !nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
] ||
6031 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
] ||
6032 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
] ||
6033 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]) {
6037 resource
->name
= strdup(mnl_attr_get_str(nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
]));
6038 resource
->size
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
]);
6039 resource
->id
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_ID
]);
6040 resource
->unit
= mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
]);
6041 resource
->size_min
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
]);
6042 resource
->size_max
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
]);
6043 resource
->size_gran
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]);
6045 if (nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
])
6046 resource
->size_new
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
]);
6048 resource
->size_new
= resource
->size
;
6050 if (nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]) {
6051 resource
->size_occ
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]);
6052 resource
->occ_valid
= true;
6055 if (resource
->size_new
!= resource
->size
)
6056 ctx
->pending_change
= true;
6062 resource_get(struct resource_ctx
*ctx
, struct resource
*resource
,
6063 struct resource
*parent_resource
, struct nlattr
*nl
)
6065 struct nlattr
*nla_resource
[DEVLINK_ATTR_MAX
+ 1] = {};
6066 struct nlattr
*nla_child_resource
;
6067 struct nlattr
*nla_resources
;
6077 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_resource
);
6078 if (err
!= MNL_CB_OK
)
6081 err
= resource_parse(ctx
, resource
, nla_resource
);
6085 resource
->parent
= parent_resource
;
6086 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
])
6089 resource
->size_valid
= !!mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_VALID
]);
6090 nla_resources
= nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
];
6092 mnl_attr_for_each_nested(nla_child_resource
, nla_resources
) {
6093 struct resource
*child_resource
;
6094 struct list_head
*list
;
6096 child_resource
= resource_alloc();
6097 if (!child_resource
)
6101 list
= &ctx
->resources
->resource_list
;
6103 list
= &resource
->resource_list
;
6105 list_add_tail(&child_resource
->list
, list
);
6106 err
= resource_get(ctx
, child_resource
, resource
,
6107 nla_child_resource
);
6115 static const char *resource_unit_str_get(enum devlink_resource_unit unit
)
6118 case DEVLINK_RESOURCE_UNIT_ENTRY
: return "entry";
6119 default: return "<unknown unit>";
6123 static void resource_show(struct resource
*resource
,
6124 struct resource_ctx
*ctx
)
6126 struct resource
*child_resource
;
6127 struct dpipe_table
*table
;
6128 struct dl
*dl
= ctx
->dl
;
6131 check_indent_newline(dl
);
6132 print_string(PRINT_ANY
, "name", "name %s", resource
->name
);
6134 resource_path_print(dl
, ctx
->resources
, resource
->id
);
6135 pr_out_u64(dl
, "size", resource
->size
);
6136 if (resource
->size
!= resource
->size_new
)
6137 pr_out_u64(dl
, "size_new", resource
->size_new
);
6138 if (resource
->occ_valid
)
6139 print_uint(PRINT_ANY
, "occ", " occ %u", resource
->size_occ
);
6140 print_string(PRINT_ANY
, "unit", " unit %s",
6141 resource_unit_str_get(resource
->unit
));
6143 if (resource
->size_min
!= resource
->size_max
) {
6144 print_uint(PRINT_ANY
, "size_min", " size_min %u",
6145 resource
->size_min
);
6146 pr_out_u64(dl
, "size_max", resource
->size_max
);
6147 print_uint(PRINT_ANY
, "size_gran", " size_gran %u",
6148 resource
->size_gran
);
6151 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
)
6152 if (table
->resource_id
== resource
->id
&&
6153 table
->resource_valid
)
6157 pr_out_array_start(dl
, "dpipe_tables");
6159 print_string(PRINT_ANY
, "dpipe_tables", " dpipe_tables none",
6162 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
) {
6163 if (table
->resource_id
!= resource
->id
||
6164 !table
->resource_valid
)
6166 pr_out_entry_start(dl
);
6167 check_indent_newline(dl
);
6168 print_string(PRINT_ANY
, "table_name", "table_name %s",
6170 pr_out_entry_end(dl
);
6173 pr_out_array_end(dl
);
6175 if (list_empty(&resource
->resource_list
))
6178 if (ctx
->pending_change
) {
6179 check_indent_newline(dl
);
6180 print_string(PRINT_ANY
, "size_valid", "size_valid %s",
6181 resource
->size_valid
? "true" : "false");
6183 pr_out_array_start(dl
, "resources");
6184 list_for_each_entry(child_resource
, &resource
->resource_list
, list
) {
6185 pr_out_entry_start(dl
);
6186 resource_show(child_resource
, ctx
);
6187 pr_out_entry_end(dl
);
6189 pr_out_array_end(dl
);
6193 resources_show(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6195 struct resources
*resources
= ctx
->resources
;
6196 struct resource
*resource
;
6198 list_for_each_entry(resource
, &resources
->resource_list
, list
) {
6199 pr_out_handle_start_arr(ctx
->dl
, tb
);
6200 resource_show(resource
, ctx
);
6201 pr_out_handle_end(ctx
->dl
);
6205 static int resources_get(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6207 return resource_get(ctx
, NULL
, NULL
, tb
[DEVLINK_ATTR_RESOURCE_LIST
]);
6210 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
6212 struct resource_ctx
*ctx
= data
;
6213 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6214 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6217 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6218 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6219 !tb
[DEVLINK_ATTR_RESOURCE_LIST
])
6220 return MNL_CB_ERROR
;
6222 err
= resources_get(ctx
, tb
);
6225 return MNL_CB_ERROR
;
6228 if (ctx
->print_resources
)
6229 resources_show(ctx
, tb
);
6234 static int cmd_resource_show(struct dl
*dl
)
6236 struct nlmsghdr
*nlh
;
6237 struct dpipe_ctx dpipe_ctx
= {};
6238 struct resource_ctx resource_ctx
= {};
6241 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, 0);
6245 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
,
6247 dl_opts_put(nlh
, dl
);
6249 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
6253 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
,
6256 pr_err("error get tables %s\n", strerror(dpipe_ctx
.err
));
6260 err
= resource_ctx_init(&resource_ctx
, dl
);
6264 resource_ctx
.print_resources
= true;
6265 resource_ctx
.tables
= dpipe_ctx
.tables
;
6266 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6267 NLM_F_REQUEST
| NLM_F_ACK
);
6268 dl_opts_put(nlh
, dl
);
6269 pr_out_section_start(dl
, "resources");
6270 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
6272 pr_out_section_end(dl
);
6273 resource_ctx_fini(&resource_ctx
);
6275 dpipe_ctx_fini(&dpipe_ctx
);
6279 static void cmd_resource_help(void)
6281 pr_err("Usage: devlink resource show DEV\n"
6282 " devlink resource set DEV path PATH size SIZE\n");
6285 static struct resource
*
6286 resource_find_by_name(struct list_head
*list
, char *name
)
6288 struct resource
*resource
;
6290 list_for_each_entry(resource
, list
, list
) {
6291 if (!strcmp(resource
->name
, name
))
6298 resource_path_parse(struct resource_ctx
*ctx
, const char *resource_path
,
6299 uint32_t *p_resource_id
, bool *p_resource_valid
)
6301 struct resource
*resource
;
6302 uint32_t resource_id
= 0;
6303 char *resource_path_dup
;
6304 struct list_head
*list
;
6305 const char del
[] = "/";
6306 char *resource_name
;
6308 resource_path_dup
= strdup(resource_path
);
6309 list
= &ctx
->resources
->resource_list
;
6310 resource_name
= strtok(resource_path_dup
, del
);
6311 while (resource_name
!= NULL
) {
6312 resource
= resource_find_by_name(list
, resource_name
);
6314 goto err_resource_lookup
;
6316 list
= &resource
->resource_list
;
6317 resource_name
= strtok(NULL
, del
);
6318 resource_id
= resource
->id
;
6320 free(resource_path_dup
);
6321 *p_resource_valid
= true;
6322 *p_resource_id
= resource_id
;
6325 err_resource_lookup
:
6326 free(resource_path_dup
);
6330 static int cmd_resource_set(struct dl
*dl
)
6332 struct nlmsghdr
*nlh
;
6333 struct resource_ctx ctx
= {};
6336 err
= resource_ctx_init(&ctx
, dl
);
6340 ctx
.print_resources
= false;
6341 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_RESOURCE_PATH
|
6342 DL_OPT_RESOURCE_SIZE
, 0);
6346 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6348 dl_opts_put(nlh
, dl
);
6349 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
, &ctx
);
6351 pr_err("error getting resources %s\n", strerror(ctx
.err
));
6355 err
= resource_path_parse(&ctx
, dl
->opts
.resource_path
,
6356 &dl
->opts
.resource_id
,
6357 &dl
->opts
.resource_id_valid
);
6359 pr_err("error parsing resource path %s\n", strerror(-err
));
6363 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_SET
,
6364 NLM_F_REQUEST
| NLM_F_ACK
);
6366 dl_opts_put(nlh
, dl
);
6367 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6369 resource_ctx_fini(&ctx
);
6373 static int cmd_resource(struct dl
*dl
)
6375 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6376 cmd_resource_help();
6378 } else if (dl_argv_match(dl
, "show")) {
6380 return cmd_resource_show(dl
);
6381 } else if (dl_argv_match(dl
, "set")) {
6383 return cmd_resource_set(dl
);
6385 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6389 static void pr_out_region_handle_start(struct dl
*dl
, struct nlattr
**tb
)
6391 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
6392 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
6393 const char *region_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_REGION_NAME
]);
6396 sprintf(buf
, "%s/%s/%s", bus_name
, dev_name
, region_name
);
6397 if (dl
->json_output
)
6398 open_json_object(buf
);
6403 static void pr_out_region_handle_end(struct dl
*dl
)
6405 if (dl
->json_output
)
6406 close_json_object();
6411 static void pr_out_region_snapshots_start(struct dl
*dl
, bool array
)
6413 __pr_out_indent_newline(dl
);
6414 if (dl
->json_output
)
6415 open_json_array(PRINT_JSON
, "snapshot");
6417 pr_out("snapshot %s", array
? "[" : "");
6420 static void pr_out_region_snapshots_end(struct dl
*dl
, bool array
)
6422 if (dl
->json_output
)
6423 close_json_array(PRINT_JSON
, NULL
);
6428 static void pr_out_region_snapshots_id(struct dl
*dl
, struct nlattr
**tb
, int index
)
6430 uint32_t snapshot_id
;
6432 if (!tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6435 snapshot_id
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
]);
6437 if (dl
->json_output
)
6438 print_uint(PRINT_JSON
, NULL
, NULL
, snapshot_id
);
6440 pr_out("%s%u", index
? " " : "", snapshot_id
);
6443 static void pr_out_snapshots(struct dl
*dl
, struct nlattr
**tb
)
6445 struct nlattr
*tb_snapshot
[DEVLINK_ATTR_MAX
+ 1] = {};
6446 struct nlattr
*nla_sanpshot
;
6449 pr_out_region_snapshots_start(dl
, true);
6450 mnl_attr_for_each_nested(nla_sanpshot
, tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
]) {
6451 err
= mnl_attr_parse_nested(nla_sanpshot
, attr_cb
, tb_snapshot
);
6452 if (err
!= MNL_CB_OK
)
6454 pr_out_region_snapshots_id(dl
, tb_snapshot
, index
++);
6456 pr_out_region_snapshots_end(dl
, true);
6459 static void pr_out_snapshot(struct dl
*dl
, struct nlattr
**tb
)
6461 pr_out_region_snapshots_start(dl
, false);
6462 pr_out_region_snapshots_id(dl
, tb
, 0);
6463 pr_out_region_snapshots_end(dl
, false);
6466 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
)
6468 pr_out_region_handle_start(dl
, tb
);
6470 if (tb
[DEVLINK_ATTR_REGION_SIZE
])
6471 pr_out_u64(dl
, "size",
6472 mnl_attr_get_u64(tb
[DEVLINK_ATTR_REGION_SIZE
]));
6474 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
])
6475 pr_out_snapshots(dl
, tb
);
6477 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6478 pr_out_snapshot(dl
, tb
);
6480 pr_out_region_handle_end(dl
);
6483 static int cmd_region_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6485 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6486 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6487 struct dl
*dl
= data
;
6489 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6490 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6491 !tb
[DEVLINK_ATTR_REGION_NAME
] || !tb
[DEVLINK_ATTR_REGION_SIZE
])
6492 return MNL_CB_ERROR
;
6494 pr_out_region(dl
, tb
);
6499 static int cmd_region_show(struct dl
*dl
)
6501 struct nlmsghdr
*nlh
;
6502 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6505 if (dl_argc(dl
) == 0)
6506 flags
|= NLM_F_DUMP
;
6508 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_GET
, flags
);
6510 if (dl_argc(dl
) > 0) {
6511 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
, 0);
6516 pr_out_section_start(dl
, "regions");
6517 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_show_cb
, dl
);
6518 pr_out_section_end(dl
);
6522 static int cmd_region_snapshot_del(struct dl
*dl
)
6524 struct nlmsghdr
*nlh
;
6527 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_DEL
,
6528 NLM_F_REQUEST
| NLM_F_ACK
);
6530 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6531 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6535 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6538 static int cmd_region_read_cb(const struct nlmsghdr
*nlh
, void *data
)
6540 struct nlattr
*nla_entry
, *nla_chunk_data
, *nla_chunk_addr
;
6541 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6542 struct nlattr
*tb_field
[DEVLINK_ATTR_MAX
+ 1] = {};
6543 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6544 struct dl
*dl
= data
;
6547 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6548 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6549 !tb
[DEVLINK_ATTR_REGION_CHUNKS
])
6550 return MNL_CB_ERROR
;
6552 mnl_attr_for_each_nested(nla_entry
, tb
[DEVLINK_ATTR_REGION_CHUNKS
]) {
6553 err
= mnl_attr_parse_nested(nla_entry
, attr_cb
, tb_field
);
6554 if (err
!= MNL_CB_OK
)
6555 return MNL_CB_ERROR
;
6557 nla_chunk_data
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_DATA
];
6558 if (!nla_chunk_data
)
6561 nla_chunk_addr
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_ADDR
];
6562 if (!nla_chunk_addr
)
6565 pr_out_region_chunk(dl
, mnl_attr_get_payload(nla_chunk_data
),
6566 mnl_attr_get_payload_len(nla_chunk_data
),
6567 mnl_attr_get_u64(nla_chunk_addr
));
6572 static int cmd_region_dump(struct dl
*dl
)
6574 struct nlmsghdr
*nlh
;
6577 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6578 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6580 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6581 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6585 pr_out_section_start(dl
, "dump");
6586 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6587 pr_out_section_end(dl
);
6588 if (!dl
->json_output
)
6593 static int cmd_region_read(struct dl
*dl
)
6595 struct nlmsghdr
*nlh
;
6598 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6599 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6601 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6602 DL_OPT_REGION_ADDRESS
| DL_OPT_REGION_LENGTH
|
6603 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6607 pr_out_section_start(dl
, "read");
6608 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6609 pr_out_section_end(dl
);
6610 if (!dl
->json_output
)
6615 static int cmd_region_snapshot_new_cb(const struct nlmsghdr
*nlh
, void *data
)
6617 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6618 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6619 struct dl
*dl
= data
;
6621 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6622 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6623 !tb
[DEVLINK_ATTR_REGION_NAME
] ||
6624 !tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6625 return MNL_CB_ERROR
;
6627 pr_out_region(dl
, tb
);
6632 static int cmd_region_snapshot_new(struct dl
*dl
)
6634 struct nlmsghdr
*nlh
;
6637 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_NEW
,
6638 NLM_F_REQUEST
| NLM_F_ACK
);
6640 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
,
6641 DL_OPT_REGION_SNAPSHOT_ID
);
6645 pr_out_section_start(dl
, "regions");
6646 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_snapshot_new_cb
, dl
);
6647 pr_out_section_end(dl
);
6651 static void cmd_region_help(void)
6653 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
6654 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
6655 pr_err(" devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
6656 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
6657 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
6660 static int cmd_region(struct dl
*dl
)
6662 if (dl_no_arg(dl
)) {
6663 return cmd_region_show(dl
);
6664 } else if (dl_argv_match(dl
, "help")) {
6667 } else if (dl_argv_match(dl
, "show")) {
6669 return cmd_region_show(dl
);
6670 } else if (dl_argv_match(dl
, "del")) {
6672 return cmd_region_snapshot_del(dl
);
6673 } else if (dl_argv_match(dl
, "dump")) {
6675 return cmd_region_dump(dl
);
6676 } else if (dl_argv_match(dl
, "read")) {
6678 return cmd_region_read(dl
);
6679 } else if (dl_argv_match(dl
, "new")) {
6681 return cmd_region_snapshot_new(dl
);
6683 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6687 static int cmd_health_set_params(struct dl
*dl
)
6689 struct nlmsghdr
*nlh
;
6692 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_SET
,
6693 NLM_F_REQUEST
| NLM_F_ACK
);
6694 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
,
6695 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
|
6696 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
|
6697 DL_OPT_HEALTH_REPORTER_AUTO_DUMP
);
6701 dl_opts_put(nlh
, dl
);
6702 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6705 static int cmd_health_dump_clear(struct dl
*dl
)
6707 struct nlmsghdr
*nlh
;
6710 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR
,
6711 NLM_F_REQUEST
| NLM_F_ACK
);
6713 err
= dl_argv_parse_put(nlh
, dl
,
6714 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6718 dl_opts_put(nlh
, dl
);
6719 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6722 static int fmsg_value_show(struct dl
*dl
, int type
, struct nlattr
*nl_data
)
6727 check_indent_newline(dl
);
6730 print_bool(PRINT_ANY
, NULL
, "%s", mnl_attr_get_u8(nl_data
));
6733 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u8(nl_data
));
6736 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u16(nl_data
));
6739 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u32(nl_data
));
6742 print_u64(PRINT_ANY
, NULL
, "%"PRIu64
, mnl_attr_get_u64(nl_data
));
6744 case MNL_TYPE_NUL_STRING
:
6745 print_string(PRINT_ANY
, NULL
, "%s", mnl_attr_get_str(nl_data
));
6747 case MNL_TYPE_BINARY
:
6748 len
= mnl_attr_get_payload_len(nl_data
);
6749 data
= mnl_attr_get_payload(nl_data
);
6750 pr_out_binary_value(dl
, data
, len
);
6758 static void pr_out_fmsg_name(struct dl
*dl
, char **name
)
6763 pr_out_name(dl
, *name
);
6770 struct list_head list
;
6773 struct fmsg_cb_data
{
6777 struct list_head entry_list
;
6780 static int cmd_fmsg_nest_queue(struct fmsg_cb_data
*fmsg_data
,
6781 uint8_t *attr_value
, bool insert
)
6783 struct nest_entry
*entry
;
6786 entry
= malloc(sizeof(struct nest_entry
));
6790 entry
->attr_type
= *attr_value
;
6791 list_add(&entry
->list
, &fmsg_data
->entry_list
);
6793 if (list_empty(&fmsg_data
->entry_list
))
6794 return MNL_CB_ERROR
;
6795 entry
= list_first_entry(&fmsg_data
->entry_list
,
6796 struct nest_entry
, list
);
6797 *attr_value
= entry
->attr_type
;
6798 list_del(&entry
->list
);
6804 static void pr_out_fmsg_group_start(struct dl
*dl
, char **name
)
6807 pr_out_fmsg_name(dl
, name
);
6809 __pr_out_indent_inc();
6812 static void pr_out_fmsg_group_end(struct dl
*dl
)
6815 __pr_out_indent_dec();
6818 static void pr_out_fmsg_start_object(struct dl
*dl
, char **name
)
6820 if (dl
->json_output
) {
6821 pr_out_fmsg_name(dl
, name
);
6822 open_json_object(NULL
);
6824 pr_out_fmsg_group_start(dl
, name
);
6828 static void pr_out_fmsg_end_object(struct dl
*dl
)
6830 if (dl
->json_output
)
6831 close_json_object();
6833 pr_out_fmsg_group_end(dl
);
6836 static void pr_out_fmsg_start_array(struct dl
*dl
, char **name
)
6838 if (dl
->json_output
) {
6839 pr_out_fmsg_name(dl
, name
);
6840 open_json_array(PRINT_JSON
, NULL
);
6842 pr_out_fmsg_group_start(dl
, name
);
6846 static void pr_out_fmsg_end_array(struct dl
*dl
)
6848 if (dl
->json_output
)
6849 close_json_array(PRINT_JSON
, NULL
);
6851 pr_out_fmsg_group_end(dl
);
6854 static int cmd_fmsg_nest(struct fmsg_cb_data
*fmsg_data
, uint8_t nest_value
,
6857 struct dl
*dl
= fmsg_data
->dl
;
6858 uint8_t value
= nest_value
;
6861 err
= cmd_fmsg_nest_queue(fmsg_data
, &value
, start
);
6862 if (err
!= MNL_CB_OK
)
6866 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6868 pr_out_fmsg_start_object(dl
, &fmsg_data
->name
);
6870 pr_out_fmsg_end_object(dl
);
6872 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6874 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6876 pr_out_fmsg_start_array(dl
, &fmsg_data
->name
);
6878 pr_out_fmsg_end_array(dl
);
6886 static int cmd_fmsg_object_cb(const struct nlmsghdr
*nlh
, void *data
)
6888 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6889 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6890 struct fmsg_cb_data
*fmsg_data
= data
;
6891 struct dl
*dl
= fmsg_data
->dl
;
6892 struct nlattr
*nla_object
;
6896 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6897 if (!tb
[DEVLINK_ATTR_FMSG
])
6898 return MNL_CB_ERROR
;
6900 mnl_attr_for_each_nested(nla_object
, tb
[DEVLINK_ATTR_FMSG
]) {
6901 attr_type
= mnl_attr_get_type(nla_object
);
6902 switch (attr_type
) {
6903 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6904 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6905 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6906 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, true);
6907 if (err
!= MNL_CB_OK
)
6910 case DEVLINK_ATTR_FMSG_NEST_END
:
6911 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, false);
6912 if (err
!= MNL_CB_OK
)
6915 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
6916 free(fmsg_data
->name
);
6917 fmsg_data
->name
= strdup(mnl_attr_get_str(nla_object
));
6918 if (!fmsg_data
->name
)
6921 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
:
6922 fmsg_data
->value_type
= mnl_attr_get_u8(nla_object
);
6924 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
6925 pr_out_fmsg_name(dl
, &fmsg_data
->name
);
6926 err
= fmsg_value_show(dl
, fmsg_data
->value_type
,
6928 if (err
!= MNL_CB_OK
)
6938 static void cmd_fmsg_init(struct dl
*dl
, struct fmsg_cb_data
*data
)
6940 /* FMSG is dynamic: opening of an object or array causes a
6941 * newline. JSON starts with an { or [, but plain text should
6942 * not start with a new line. Ensure this by setting
6943 * g_new_line_count to 1: avoiding newline before the first
6946 g_new_line_count
= 1;
6949 INIT_LIST_HEAD(&data
->entry_list
);
6952 static int cmd_health_object_common(struct dl
*dl
, uint8_t cmd
, uint16_t flags
)
6954 struct fmsg_cb_data data
;
6955 struct nlmsghdr
*nlh
;
6958 nlh
= mnlg_msg_prepare(dl
->nlg
, cmd
, flags
| NLM_F_REQUEST
| NLM_F_ACK
);
6960 err
= dl_argv_parse_put(nlh
, dl
,
6961 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6965 cmd_fmsg_init(dl
, &data
);
6966 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_fmsg_object_cb
, &data
);
6971 static int cmd_health_dump_show(struct dl
*dl
)
6973 return cmd_health_object_common(dl
,
6974 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
,
6978 static int cmd_health_diagnose(struct dl
*dl
)
6980 return cmd_health_object_common(dl
,
6981 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
,
6985 static int cmd_health_recover(struct dl
*dl
)
6987 struct nlmsghdr
*nlh
;
6990 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
,
6991 NLM_F_REQUEST
| NLM_F_ACK
);
6993 err
= dl_argv_parse_put(nlh
, dl
,
6994 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6998 dl_opts_put(nlh
, dl
);
6999 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7002 enum devlink_health_reporter_state
{
7003 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
,
7004 DEVLINK_HEALTH_REPORTER_STATE_ERROR
,
7007 static const char *health_state_name(uint8_t state
)
7010 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
:
7011 return HEALTH_REPORTER_STATE_HEALTHY_STR
;
7012 case DEVLINK_HEALTH_REPORTER_STATE_ERROR
:
7013 return HEALTH_REPORTER_STATE_ERROR_STR
;
7015 return "<unknown state>";
7019 static void pr_out_dump_reporter_format_logtime(struct dl
*dl
, const struct nlattr
*attr
)
7021 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7022 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7023 uint64_t time_ms
= mnl_attr_get_u64(attr
);
7024 struct sysinfo s_info
;
7030 info
= localtime(&now
);
7031 err
= sysinfo(&s_info
);
7034 /* Subtract uptime in sec from now yields the time of system
7035 * uptime. To this, add time_ms which is the amount of
7036 * milliseconds elapsed between uptime and the dump taken.
7038 sec
= now
- s_info
.uptime
+ time_ms
/ 1000;
7039 info
= localtime(&sec
);
7041 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", info
);
7042 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", info
);
7043 check_indent_newline(dl
);
7044 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
7045 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
7048 static void pr_out_dump_report_timestamp(struct dl
*dl
, const struct nlattr
*attr
)
7050 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7051 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
7056 ts
= mnl_attr_get_u64(attr
);
7057 tv_sec
= ts
/ 1000000000;
7058 tm
= localtime(&tv_sec
);
7060 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", tm
);
7061 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", tm
);
7063 check_indent_newline(dl
);
7064 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
7065 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
7068 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
)
7070 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7071 enum devlink_health_reporter_state state
;
7074 err
= mnl_attr_parse_nested(tb_health
[DEVLINK_ATTR_HEALTH_REPORTER
],
7076 if (err
!= MNL_CB_OK
)
7079 if (!tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
] ||
7080 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] ||
7081 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] ||
7082 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
])
7085 pr_out_handle_start_arr(dl
, tb_health
);
7087 check_indent_newline(dl
);
7088 print_string(PRINT_ANY
, "reporter", "reporter %s",
7089 mnl_attr_get_str(tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]));
7090 if (!dl
->json_output
) {
7092 __pr_out_indent_inc();
7094 state
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
]);
7095 check_indent_newline(dl
);
7096 print_string(PRINT_ANY
, "state", "state %s", health_state_name(state
));
7097 pr_out_u64(dl
, "error",
7098 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
]));
7099 pr_out_u64(dl
, "recover",
7100 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
]));
7101 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
])
7102 pr_out_dump_report_timestamp(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
]);
7103 else if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
])
7104 pr_out_dump_reporter_format_logtime(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
]);
7105 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
7106 pr_out_u64(dl
, "grace_period",
7107 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]));
7108 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
7109 print_bool(PRINT_ANY
, "auto_recover", " auto_recover %s",
7110 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]));
7111 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
])
7112 print_bool(PRINT_ANY
, "auto_dump", " auto_dump %s",
7113 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
]));
7115 __pr_out_indent_dec();
7116 pr_out_handle_end(dl
);
7119 static int cmd_health_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7121 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7122 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7123 struct dl
*dl
= data
;
7125 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7126 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7127 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
7128 return MNL_CB_ERROR
;
7130 pr_out_health(dl
, tb
);
7135 static int cmd_health_show(struct dl
*dl
)
7137 struct nlmsghdr
*nlh
;
7138 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7141 if (dl_argc(dl
) == 0)
7142 flags
|= NLM_F_DUMP
;
7143 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_GET
,
7146 if (dl_argc(dl
) > 0) {
7147 err
= dl_argv_parse_put(nlh
, dl
,
7149 DL_OPT_HEALTH_REPORTER_NAME
, 0);
7153 pr_out_section_start(dl
, "health");
7155 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_health_show_cb
, dl
);
7156 pr_out_section_end(dl
);
7160 static void cmd_health_help(void)
7162 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
7163 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
7164 pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n");
7165 pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n");
7166 pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n");
7167 pr_err(" devlink health set DEV reporter REPORTER_NAME\n");
7168 pr_err(" [ grace_period MSEC ]\n");
7169 pr_err(" [ auto_recover { true | false } ]\n");
7170 pr_err(" [ auto_dump { true | false } ]\n");
7173 static int cmd_health(struct dl
*dl
)
7175 if (dl_argv_match(dl
, "help")) {
7178 } else if (dl_argv_match(dl
, "show") ||
7179 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7181 return cmd_health_show(dl
);
7182 } else if (dl_argv_match(dl
, "recover")) {
7184 return cmd_health_recover(dl
);
7185 } else if (dl_argv_match(dl
, "diagnose")) {
7187 return cmd_health_diagnose(dl
);
7188 } else if (dl_argv_match(dl
, "dump")) {
7190 if (dl_argv_match(dl
, "show")) {
7192 return cmd_health_dump_show(dl
);
7193 } else if (dl_argv_match(dl
, "clear")) {
7195 return cmd_health_dump_clear(dl
);
7197 } else if (dl_argv_match(dl
, "set")) {
7199 return cmd_health_set_params(dl
);
7201 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7205 static const char *trap_type_name(uint8_t type
)
7208 case DEVLINK_TRAP_TYPE_DROP
:
7210 case DEVLINK_TRAP_TYPE_EXCEPTION
:
7213 return "<unknown type>";
7217 static const char *trap_action_name(uint8_t action
)
7220 case DEVLINK_TRAP_ACTION_DROP
:
7222 case DEVLINK_TRAP_ACTION_TRAP
:
7225 return "<unknown action>";
7229 static const char *trap_metadata_name(const struct nlattr
*attr
)
7231 switch (attr
->nla_type
) {
7232 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT
:
7233 return "input_port";
7234 case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE
:
7235 return "flow_action_cookie";
7237 return "<unknown metadata type>";
7240 static void pr_out_trap_metadata(struct dl
*dl
, struct nlattr
*attr
)
7242 struct nlattr
*attr_metadata
;
7244 pr_out_array_start(dl
, "metadata");
7245 mnl_attr_for_each_nested(attr_metadata
, attr
) {
7246 check_indent_newline(dl
);
7247 print_string(PRINT_ANY
, NULL
, "%s",
7248 trap_metadata_name(attr_metadata
));
7250 pr_out_array_end(dl
);
7253 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7255 uint8_t action
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_ACTION
]);
7256 uint8_t type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_TYPE
]);
7259 pr_out_handle_start_arr(dl
, tb
);
7261 __pr_out_handle_start(dl
, tb
, true, false);
7263 check_indent_newline(dl
);
7264 print_string(PRINT_ANY
, "name", "name %s",
7265 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_NAME
]));
7266 print_string(PRINT_ANY
, "type", " type %s", trap_type_name(type
));
7267 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7268 print_string(PRINT_ANY
, "action", " action %s", trap_action_name(action
));
7269 print_string(PRINT_ANY
, "group", " group %s",
7270 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7272 pr_out_trap_metadata(dl
, tb
[DEVLINK_ATTR_TRAP_METADATA
]);
7273 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7274 pr_out_handle_end(dl
);
7277 static int cmd_trap_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7279 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7280 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7281 struct dl
*dl
= data
;
7283 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7284 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7285 !tb
[DEVLINK_ATTR_TRAP_NAME
] || !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
7286 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
7287 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
7288 !tb
[DEVLINK_ATTR_TRAP_METADATA
] || !tb
[DEVLINK_ATTR_STATS
])
7289 return MNL_CB_ERROR
;
7291 pr_out_trap(dl
, tb
, true);
7296 static void cmd_trap_help(void)
7298 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop } ]\n");
7299 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
7300 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop } ]\n");
7301 pr_err(" [ policer POLICER ] [ nopolicer ]\n");
7302 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
7303 pr_err(" devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
7304 pr_err(" devlink trap policer show DEV policer POLICER\n");
7307 static int cmd_trap_show(struct dl
*dl
)
7309 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7310 struct nlmsghdr
*nlh
;
7313 if (dl_argc(dl
) == 0)
7314 flags
|= NLM_F_DUMP
;
7316 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GET
, flags
);
7318 if (dl_argc(dl
) > 0) {
7319 err
= dl_argv_parse_put(nlh
, dl
,
7320 DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
, 0);
7325 pr_out_section_start(dl
, "trap");
7326 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_show_cb
, dl
);
7327 pr_out_section_end(dl
);
7332 static int cmd_trap_set(struct dl
*dl
)
7334 struct nlmsghdr
*nlh
;
7337 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_SET
,
7338 NLM_F_REQUEST
| NLM_F_ACK
);
7340 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
,
7341 DL_OPT_TRAP_ACTION
);
7345 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7348 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7351 pr_out_handle_start_arr(dl
, tb
);
7353 __pr_out_handle_start(dl
, tb
, true, false);
7355 check_indent_newline(dl
);
7356 print_string(PRINT_ANY
, "name", "name %s",
7357 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7358 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7359 if (tb
[DEVLINK_ATTR_TRAP_POLICER_ID
])
7360 print_uint(PRINT_ANY
, "policer", " policer %u",
7361 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7362 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7363 pr_out_handle_end(dl
);
7366 static int cmd_trap_group_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7368 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7369 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7370 struct dl
*dl
= data
;
7372 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7373 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7374 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] || !tb
[DEVLINK_ATTR_STATS
])
7375 return MNL_CB_ERROR
;
7377 pr_out_trap_group(dl
, tb
, true);
7382 static int cmd_trap_group_show(struct dl
*dl
)
7384 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7385 struct nlmsghdr
*nlh
;
7388 if (dl_argc(dl
) == 0)
7389 flags
|= NLM_F_DUMP
;
7391 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_GET
, flags
);
7393 if (dl_argc(dl
) > 0) {
7394 err
= dl_argv_parse_put(nlh
, dl
,
7395 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7401 pr_out_section_start(dl
, "trap_group");
7402 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_group_show_cb
, dl
);
7403 pr_out_section_end(dl
);
7408 static int cmd_trap_group_set(struct dl
*dl
)
7410 struct nlmsghdr
*nlh
;
7413 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_SET
,
7414 NLM_F_REQUEST
| NLM_F_ACK
);
7416 err
= dl_argv_parse_put(nlh
, dl
,
7417 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7418 DL_OPT_TRAP_ACTION
| DL_OPT_TRAP_POLICER_ID
);
7422 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7425 static int cmd_trap_group(struct dl
*dl
)
7427 if (dl_argv_match(dl
, "help")) {
7430 } else if (dl_argv_match(dl
, "show") ||
7431 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7433 return cmd_trap_group_show(dl
);
7434 } else if (dl_argv_match(dl
, "set")) {
7436 return cmd_trap_group_set(dl
);
7438 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7442 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7445 pr_out_handle_start_arr(dl
, tb
);
7447 __pr_out_handle_start(dl
, tb
, true, false);
7449 check_indent_newline(dl
);
7450 print_uint(PRINT_ANY
, "policer", "policer %u",
7451 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7452 print_u64(PRINT_ANY
, "rate", " rate %llu",
7453 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
]));
7454 print_u64(PRINT_ANY
, "burst", " burst %llu",
7455 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
]));
7456 if (tb
[DEVLINK_ATTR_STATS
])
7457 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7458 pr_out_handle_end(dl
);
7461 static int cmd_trap_policer_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7463 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7464 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7465 struct dl
*dl
= data
;
7467 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7468 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7469 !tb
[DEVLINK_ATTR_TRAP_POLICER_ID
] ||
7470 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
7471 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
7472 return MNL_CB_ERROR
;
7474 pr_out_trap_policer(dl
, tb
, true);
7479 static int cmd_trap_policer_show(struct dl
*dl
)
7481 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7482 struct nlmsghdr
*nlh
;
7485 if (dl_argc(dl
) == 0)
7486 flags
|= NLM_F_DUMP
;
7488 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_GET
, flags
);
7490 if (dl_argc(dl
) > 0) {
7491 err
= dl_argv_parse_put(nlh
, dl
,
7492 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7498 pr_out_section_start(dl
, "trap_policer");
7499 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_policer_show_cb
, dl
);
7500 pr_out_section_end(dl
);
7505 static int cmd_trap_policer_set(struct dl
*dl
)
7507 struct nlmsghdr
*nlh
;
7510 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_SET
,
7511 NLM_F_REQUEST
| NLM_F_ACK
);
7513 err
= dl_argv_parse_put(nlh
, dl
,
7514 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7515 DL_OPT_TRAP_POLICER_RATE
|
7516 DL_OPT_TRAP_POLICER_BURST
);
7520 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7523 static int cmd_trap_policer(struct dl
*dl
)
7525 if (dl_argv_match(dl
, "help")) {
7528 } else if (dl_argv_match(dl
, "show") ||
7529 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7531 return cmd_trap_policer_show(dl
);
7532 } else if (dl_argv_match(dl
, "set")) {
7534 return cmd_trap_policer_set(dl
);
7536 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7540 static int cmd_trap(struct dl
*dl
)
7542 if (dl_argv_match(dl
, "help")) {
7545 } else if (dl_argv_match(dl
, "show") ||
7546 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7548 return cmd_trap_show(dl
);
7549 } else if (dl_argv_match(dl
, "set")) {
7551 return cmd_trap_set(dl
);
7552 } else if (dl_argv_match(dl
, "group")) {
7554 return cmd_trap_group(dl
);
7555 } else if (dl_argv_match(dl
, "policer")) {
7557 return cmd_trap_policer(dl
);
7559 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7563 static void help(void)
7565 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
7566 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
7567 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
7568 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
7571 static int dl_cmd(struct dl
*dl
, int argc
, char **argv
)
7576 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
7579 } else if (dl_argv_match(dl
, "dev")) {
7582 } else if (dl_argv_match(dl
, "port")) {
7584 return cmd_port(dl
);
7585 } else if (dl_argv_match(dl
, "sb")) {
7588 } else if (dl_argv_match(dl
, "monitor")) {
7591 } else if (dl_argv_match(dl
, "dpipe")) {
7593 return cmd_dpipe(dl
);
7594 } else if (dl_argv_match(dl
, "resource")) {
7596 return cmd_resource(dl
);
7597 } else if (dl_argv_match(dl
, "region")) {
7599 return cmd_region(dl
);
7600 } else if (dl_argv_match(dl
, "health")) {
7602 return cmd_health(dl
);
7603 } else if (dl_argv_match(dl
, "trap")) {
7605 return cmd_trap(dl
);
7607 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
7611 static int dl_init(struct dl
*dl
)
7615 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
7617 pr_err("Failed to connect to devlink Netlink\n");
7621 err
= ifname_map_init(dl
);
7623 pr_err("Failed to create index map\n");
7624 goto err_ifname_map_create
;
7626 new_json_obj_plain(dl
->json_output
);
7629 err_ifname_map_create
:
7630 mnlg_socket_close(dl
->nlg
);
7634 static void dl_fini(struct dl
*dl
)
7636 delete_json_obj_plain();
7637 ifname_map_fini(dl
);
7638 mnlg_socket_close(dl
->nlg
);
7641 static struct dl
*dl_alloc(void)
7645 dl
= calloc(1, sizeof(*dl
));
7651 static void dl_free(struct dl
*dl
)
7656 static int dl_batch(struct dl
*dl
, const char *name
, bool force
)
7660 int ret
= EXIT_SUCCESS
;
7662 if (name
&& strcmp(name
, "-") != 0) {
7663 if (freopen(name
, "r", stdin
) == NULL
) {
7665 "Cannot open file \"%s\" for reading: %s\n",
7666 name
, strerror(errno
));
7667 return EXIT_FAILURE
;
7672 while (getcmdline(&line
, &len
, stdin
) != -1) {
7676 largc
= makeargs(line
, largv
, 100);
7678 continue; /* blank line */
7680 if (dl_cmd(dl
, largc
, largv
)) {
7681 fprintf(stderr
, "Command failed %s:%d\n",
7695 int main(int argc
, char **argv
)
7697 static const struct option long_options
[] = {
7698 { "Version", no_argument
, NULL
, 'V' },
7699 { "force", no_argument
, NULL
, 'f' },
7700 { "batch", required_argument
, NULL
, 'b' },
7701 { "no-nice-names", no_argument
, NULL
, 'n' },
7702 { "json", no_argument
, NULL
, 'j' },
7703 { "pretty", no_argument
, NULL
, 'p' },
7704 { "verbose", no_argument
, NULL
, 'v' },
7705 { "statistics", no_argument
, NULL
, 's' },
7706 { "Netns", required_argument
, NULL
, 'N' },
7707 { NULL
, 0, NULL
, 0 }
7709 const char *batch_file
= NULL
;
7718 pr_err("Failed to allocate memory for devlink\n");
7719 return EXIT_FAILURE
;
7722 while ((opt
= getopt_long(argc
, argv
, "Vfb:njpvsN:",
7723 long_options
, NULL
)) >= 0) {
7727 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
7734 batch_file
= optarg
;
7737 dl
->no_nice_names
= true;
7740 dl
->json_output
= true;
7752 if (netns_switch(optarg
)) {
7758 pr_err("Unknown option.\n");
7775 err
= dl_batch(dl
, batch_file
, force
);
7777 err
= dl_cmd(dl
, argc
, argv
);