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)
299 uint64_t present
; /* flags of present items */
303 enum devlink_port_type port_type
;
306 uint16_t sb_pool_index
;
307 uint32_t sb_pool_size
;
308 enum devlink_sb_pool_type sb_pool_type
;
309 enum devlink_sb_threshold_type sb_pool_thtype
;
310 uint32_t sb_threshold
;
311 uint16_t sb_tc_index
;
312 enum devlink_eswitch_mode eswitch_mode
;
313 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
314 const char *dpipe_table_name
;
315 bool dpipe_counters_enabled
;
316 enum devlink_eswitch_encap_mode eswitch_encap_mode
;
317 const char *resource_path
;
318 uint64_t resource_size
;
319 uint32_t resource_id
;
320 bool resource_id_valid
;
321 const char *param_name
;
322 const char *param_value
;
323 enum devlink_param_cmode cmode
;
325 uint32_t region_snapshot_id
;
326 uint64_t region_address
;
327 uint64_t region_length
;
328 const char *flash_file_name
;
329 const char *flash_component
;
330 const char *reporter_name
;
331 uint64_t reporter_graceful_period
;
332 bool reporter_auto_recover
;
333 bool reporter_auto_dump
;
334 const char *trap_name
;
335 const char *trap_group_name
;
336 enum devlink_trap_action trap_action
;
339 uint32_t trap_policer_id
;
340 uint64_t trap_policer_rate
;
341 uint64_t trap_policer_burst
;
345 struct mnlg_socket
*nlg
;
346 struct list_head ifname_map_list
;
363 static int dl_argc(struct dl
*dl
)
368 static char *dl_argv(struct dl
*dl
)
370 if (dl_argc(dl
) == 0)
375 static void dl_arg_inc(struct dl
*dl
)
377 if (dl_argc(dl
) == 0)
383 static void dl_arg_dec(struct dl
*dl
)
389 static char *dl_argv_next(struct dl
*dl
)
393 if (dl_argc(dl
) == 0)
401 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
403 if (index
>= dl_argc(dl
))
405 return dl
->argv
[index
];
408 static int strcmpx(const char *str1
, const char *str2
)
410 if (strlen(str1
) > strlen(str2
))
412 return strncmp(str1
, str2
, strlen(str1
));
415 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
417 if (dl_argc(dl
) == 0)
419 return strcmpx(dl_argv(dl
), pattern
) == 0;
422 static bool dl_no_arg(struct dl
*dl
)
424 return dl_argc(dl
) == 0;
427 static void __pr_out_indent_newline(struct dl
*dl
)
429 if (!g_indent_newline
&& !dl
->json_output
)
433 static bool is_binary_eol(int i
)
438 static void pr_out_binary_value(struct dl
*dl
, uint8_t *data
, uint32_t len
)
444 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
446 pr_out("%02x ", data
[i
]);
448 if (!dl
->json_output
&& is_binary_eol(i
))
451 if (!dl
->json_output
&& !is_binary_eol(i
))
455 static void pr_out_name(struct dl
*dl
, const char *name
)
457 __pr_out_indent_newline(dl
);
459 print_string(PRINT_JSON
, name
, NULL
, NULL
);
464 static void pr_out_u64(struct dl
*dl
, const char *name
, uint64_t val
)
466 __pr_out_indent_newline(dl
);
467 if (val
== (uint64_t) -1)
468 return print_string_name_value(name
, "unlimited");
471 print_u64(PRINT_JSON
, name
, NULL
, val
);
473 pr_out("%s %"PRIu64
, name
, val
);
476 static void pr_out_section_start(struct dl
*dl
, const char *name
)
478 if (dl
->json_output
) {
479 open_json_object(NULL
);
480 open_json_object(name
);
484 static void pr_out_section_end(struct dl
*dl
)
486 if (dl
->json_output
) {
487 if (dl
->arr_last
.present
)
488 close_json_array(PRINT_JSON
, NULL
);
494 static void pr_out_array_start(struct dl
*dl
, const char *name
)
496 if (dl
->json_output
) {
497 open_json_array(PRINT_JSON
, name
);
499 __pr_out_indent_inc();
502 __pr_out_indent_inc();
507 static void pr_out_array_end(struct dl
*dl
)
509 if (dl
->json_output
) {
510 close_json_array(PRINT_JSON
, NULL
);
512 __pr_out_indent_dec();
513 __pr_out_indent_dec();
517 static void pr_out_object_start(struct dl
*dl
, const char *name
)
519 if (dl
->json_output
) {
520 open_json_object(name
);
522 __pr_out_indent_inc();
525 __pr_out_indent_inc();
530 static void pr_out_object_end(struct dl
*dl
)
532 if (dl
->json_output
) {
535 __pr_out_indent_dec();
536 __pr_out_indent_dec();
540 static void pr_out_entry_start(struct dl
*dl
)
543 open_json_object(NULL
);
546 static void pr_out_entry_end(struct dl
*dl
)
554 static void check_indent_newline(struct dl
*dl
)
556 __pr_out_indent_newline(dl
);
558 if (g_indent_newline
&& !is_json_context()) {
559 printf("%s", g_indent_str
);
560 g_indent_newline
= false;
562 g_new_line_count
= 0;
565 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
566 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
567 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
568 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
569 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
570 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
571 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
572 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
573 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
574 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
575 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
576 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
577 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
578 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
579 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
580 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
581 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
582 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
583 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
584 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
585 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
586 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
587 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
588 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
589 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
590 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
591 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
592 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
593 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
594 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
595 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
596 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
597 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
598 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
599 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
600 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
601 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
602 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
603 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
604 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
605 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
606 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
607 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
608 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
609 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
610 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
611 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
612 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
613 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
614 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
615 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
616 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
617 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
618 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
619 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
620 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
621 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
622 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
623 [DEVLINK_ATTR_PARAM
] = MNL_TYPE_NESTED
,
624 [DEVLINK_ATTR_PARAM_NAME
] = MNL_TYPE_STRING
,
625 [DEVLINK_ATTR_PARAM_TYPE
] = MNL_TYPE_U8
,
626 [DEVLINK_ATTR_PARAM_VALUES_LIST
] = MNL_TYPE_NESTED
,
627 [DEVLINK_ATTR_PARAM_VALUE
] = MNL_TYPE_NESTED
,
628 [DEVLINK_ATTR_PARAM_VALUE_CMODE
] = MNL_TYPE_U8
,
629 [DEVLINK_ATTR_REGION_NAME
] = MNL_TYPE_STRING
,
630 [DEVLINK_ATTR_REGION_SIZE
] = MNL_TYPE_U64
,
631 [DEVLINK_ATTR_REGION_SNAPSHOTS
] = MNL_TYPE_NESTED
,
632 [DEVLINK_ATTR_REGION_SNAPSHOT
] = MNL_TYPE_NESTED
,
633 [DEVLINK_ATTR_REGION_SNAPSHOT_ID
] = MNL_TYPE_U32
,
634 [DEVLINK_ATTR_REGION_CHUNKS
] = MNL_TYPE_NESTED
,
635 [DEVLINK_ATTR_REGION_CHUNK
] = MNL_TYPE_NESTED
,
636 [DEVLINK_ATTR_REGION_CHUNK_DATA
] = MNL_TYPE_BINARY
,
637 [DEVLINK_ATTR_REGION_CHUNK_ADDR
] = MNL_TYPE_U64
,
638 [DEVLINK_ATTR_REGION_CHUNK_LEN
] = MNL_TYPE_U64
,
639 [DEVLINK_ATTR_INFO_DRIVER_NAME
] = MNL_TYPE_STRING
,
640 [DEVLINK_ATTR_INFO_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
641 [DEVLINK_ATTR_INFO_VERSION_FIXED
] = MNL_TYPE_NESTED
,
642 [DEVLINK_ATTR_INFO_VERSION_RUNNING
] = MNL_TYPE_NESTED
,
643 [DEVLINK_ATTR_INFO_VERSION_STORED
] = MNL_TYPE_NESTED
,
644 [DEVLINK_ATTR_INFO_VERSION_NAME
] = MNL_TYPE_STRING
,
645 [DEVLINK_ATTR_INFO_VERSION_VALUE
] = MNL_TYPE_STRING
,
646 [DEVLINK_ATTR_HEALTH_REPORTER
] = MNL_TYPE_NESTED
,
647 [DEVLINK_ATTR_HEALTH_REPORTER_NAME
] = MNL_TYPE_STRING
,
648 [DEVLINK_ATTR_HEALTH_REPORTER_STATE
] = MNL_TYPE_U8
,
649 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] = MNL_TYPE_U64
,
650 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] = MNL_TYPE_U64
,
651 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
] = MNL_TYPE_U64
,
652 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] = MNL_TYPE_U64
,
653 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
] = MNL_TYPE_STRING
,
654 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
] = MNL_TYPE_STRING
,
655 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
] = MNL_TYPE_U64
,
656 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
] = MNL_TYPE_U64
,
657 [DEVLINK_ATTR_STATS
] = MNL_TYPE_NESTED
,
658 [DEVLINK_ATTR_TRAP_NAME
] = MNL_TYPE_STRING
,
659 [DEVLINK_ATTR_TRAP_ACTION
] = MNL_TYPE_U8
,
660 [DEVLINK_ATTR_TRAP_TYPE
] = MNL_TYPE_U8
,
661 [DEVLINK_ATTR_TRAP_GENERIC
] = MNL_TYPE_FLAG
,
662 [DEVLINK_ATTR_TRAP_METADATA
] = MNL_TYPE_NESTED
,
663 [DEVLINK_ATTR_TRAP_GROUP_NAME
] = MNL_TYPE_STRING
,
664 [DEVLINK_ATTR_RELOAD_FAILED
] = MNL_TYPE_U8
,
665 [DEVLINK_ATTR_TRAP_POLICER_ID
] = MNL_TYPE_U32
,
666 [DEVLINK_ATTR_TRAP_POLICER_RATE
] = MNL_TYPE_U64
,
667 [DEVLINK_ATTR_TRAP_POLICER_BURST
] = MNL_TYPE_U64
,
670 static const enum mnl_attr_data_type
671 devlink_stats_policy
[DEVLINK_ATTR_STATS_MAX
+ 1] = {
672 [DEVLINK_ATTR_STATS_RX_PACKETS
] = MNL_TYPE_U64
,
673 [DEVLINK_ATTR_STATS_RX_BYTES
] = MNL_TYPE_U64
,
674 [DEVLINK_ATTR_STATS_RX_DROPPED
] = MNL_TYPE_U64
,
677 static int attr_cb(const struct nlattr
*attr
, void *data
)
679 const struct nlattr
**tb
= data
;
682 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
685 type
= mnl_attr_get_type(attr
);
686 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
693 static int attr_stats_cb(const struct nlattr
*attr
, void *data
)
695 const struct nlattr
**tb
= data
;
698 /* Allow the tool to work on top of newer kernels that might contain
701 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_STATS_MAX
) < 0)
704 type
= mnl_attr_get_type(attr
);
705 if (mnl_attr_validate(attr
, devlink_stats_policy
[type
]) < 0)
712 static const enum mnl_attr_data_type
713 devlink_function_policy
[DEVLINK_PORT_FUNCTION_ATTR_MAX
+ 1] = {
714 [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
] = MNL_TYPE_BINARY
,
717 static int function_attr_cb(const struct nlattr
*attr
, void *data
)
719 const struct nlattr
**tb
= data
;
722 /* Allow the tool to work on top of newer kernels that might contain
725 if (mnl_attr_type_valid(attr
, DEVLINK_PORT_FUNCTION_ATTR_MAX
) < 0)
728 type
= mnl_attr_get_type(attr
);
729 if (mnl_attr_validate(attr
, devlink_function_policy
[type
]) < 0)
736 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
738 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
739 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
740 struct dl
*dl
= data
;
741 struct ifname_map
*ifname_map
;
742 const char *bus_name
;
743 const char *dev_name
;
744 uint32_t port_ifindex
;
745 const char *port_ifname
;
747 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
748 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
749 !tb
[DEVLINK_ATTR_PORT_INDEX
])
752 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
755 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
756 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
757 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
758 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
759 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
760 port_ifindex
, port_ifname
);
763 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
768 static void ifname_map_fini(struct dl
*dl
)
770 struct ifname_map
*ifname_map
, *tmp
;
772 list_for_each_entry_safe(ifname_map
, tmp
,
773 &dl
->ifname_map_list
, list
) {
774 list_del(&ifname_map
->list
);
775 ifname_map_free(ifname_map
);
779 static int ifname_map_init(struct dl
*dl
)
781 struct nlmsghdr
*nlh
;
784 INIT_LIST_HEAD(&dl
->ifname_map_list
);
786 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
787 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
789 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
797 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
798 char **p_bus_name
, char **p_dev_name
,
799 uint32_t *p_port_index
)
801 struct ifname_map
*ifname_map
;
803 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
804 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
805 *p_bus_name
= ifname_map
->bus_name
;
806 *p_dev_name
= ifname_map
->dev_name
;
807 *p_port_index
= ifname_map
->port_index
;
814 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
815 const char *dev_name
, uint32_t port_index
,
818 struct ifname_map
*ifname_map
;
820 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
821 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
822 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
823 port_index
== ifname_map
->port_index
) {
824 *p_ifname
= ifname_map
->ifname
;
831 static unsigned int strslashcount(char *str
)
833 unsigned int count
= 0;
836 while ((pos
= strchr(pos
, '/'))) {
843 static int strslashrsplit(char *str
, char **before
, char **after
)
847 slash
= strrchr(str
, '/');
856 static int strtouint64_t(const char *str
, uint64_t *p_val
)
859 unsigned long long int val
;
861 val
= strtoull(str
, &endptr
, 10);
862 if (endptr
== str
|| *endptr
!= '\0')
870 static int strtouint32_t(const char *str
, uint32_t *p_val
)
873 unsigned long int val
;
875 val
= strtoul(str
, &endptr
, 10);
876 if (endptr
== str
|| *endptr
!= '\0')
884 static int strtouint16_t(const char *str
, uint16_t *p_val
)
887 unsigned long int val
;
889 val
= strtoul(str
, &endptr
, 10);
890 if (endptr
== str
|| *endptr
!= '\0')
898 static int strtouint8_t(const char *str
, uint8_t *p_val
)
901 unsigned long int val
;
903 val
= strtoul(str
, &endptr
, 10);
904 if (endptr
== str
|| *endptr
!= '\0')
912 static int strtobool(const char *str
, bool *p_val
)
916 if (!strcmp(str
, "true") || !strcmp(str
, "1") ||
917 !strcmp(str
, "enable"))
919 else if (!strcmp(str
, "false") || !strcmp(str
, "0") ||
920 !strcmp(str
, "disable"))
928 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
930 strslashrsplit(str
, p_bus_name
, p_dev_name
);
934 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
936 char *str
= dl_argv_next(dl
);
939 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
942 if (strslashcount(str
) != 1) {
943 pr_err("Wrong devlink identification string format.\n");
944 pr_err("Expected \"bus_name/dev_name\".\n");
947 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
950 static int __dl_argv_handle_port(char *str
,
951 char **p_bus_name
, char **p_dev_name
,
952 uint32_t *p_port_index
)
958 err
= strslashrsplit(str
, &handlestr
, &portstr
);
960 pr_err("Port identification \"%s\" is invalid\n", str
);
963 err
= strtouint32_t(portstr
, p_port_index
);
965 pr_err("Port index \"%s\" is not a number or not within range\n",
969 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
971 pr_err("Port identification \"%s\" is invalid\n", str
);
977 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
978 char **p_bus_name
, char **p_dev_name
,
979 uint32_t *p_port_index
)
983 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
986 pr_err("Netdevice \"%s\" not found\n", str
);
992 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
993 char **p_dev_name
, uint32_t *p_port_index
)
995 char *str
= dl_argv_next(dl
);
996 unsigned int slash_count
;
999 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
1002 slash_count
= strslashcount(str
);
1003 switch (slash_count
) {
1005 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
1006 p_dev_name
, p_port_index
);
1008 return __dl_argv_handle_port(str
, p_bus_name
,
1009 p_dev_name
, p_port_index
);
1011 pr_err("Wrong port identification string format.\n");
1012 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1017 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
1018 char **p_dev_name
, uint32_t *p_port_index
,
1019 uint64_t *p_handle_bit
)
1021 char *str
= dl_argv_next(dl
);
1022 unsigned int slash_count
;
1026 pr_err("One of following identifications expected:\n"
1027 "Devlink identification (\"bus_name/dev_name\")\n"
1028 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
1031 slash_count
= strslashcount(str
);
1032 if (slash_count
== 1) {
1033 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
1036 *p_handle_bit
= DL_OPT_HANDLE
;
1037 } else if (slash_count
== 2) {
1038 err
= __dl_argv_handle_port(str
, p_bus_name
,
1039 p_dev_name
, p_port_index
);
1042 *p_handle_bit
= DL_OPT_HANDLEP
;
1043 } else if (slash_count
== 0) {
1044 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
1045 p_dev_name
, p_port_index
);
1048 *p_handle_bit
= DL_OPT_HANDLEP
;
1050 pr_err("Wrong port identification string format.\n");
1051 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1057 static int __dl_argv_handle_region(char *str
, char **p_bus_name
,
1058 char **p_dev_name
, char **p_region
)
1063 err
= strslashrsplit(str
, &handlestr
, p_region
);
1065 pr_err("Region identification \"%s\" is invalid\n", str
);
1068 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
1070 pr_err("Region identification \"%s\" is invalid\n", str
);
1076 static int dl_argv_handle_region(struct dl
*dl
, char **p_bus_name
,
1077 char **p_dev_name
, char **p_region
)
1079 char *str
= dl_argv_next(dl
);
1080 unsigned int slash_count
;
1083 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
1087 slash_count
= strslashcount(str
);
1088 if (slash_count
!= 2) {
1089 pr_err("Wrong region identification string format.\n");
1090 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
1094 return __dl_argv_handle_region(str
, p_bus_name
, p_dev_name
, p_region
);
1097 static int dl_argv_uint64_t(struct dl
*dl
, uint64_t *p_val
)
1099 char *str
= dl_argv_next(dl
);
1103 pr_err("Unsigned number argument expected\n");
1107 err
= strtouint64_t(str
, p_val
);
1109 pr_err("\"%s\" is not a number or not within range\n", str
);
1115 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
1117 char *str
= dl_argv_next(dl
);
1121 pr_err("Unsigned number argument expected\n");
1125 err
= strtouint32_t(str
, p_val
);
1127 pr_err("\"%s\" is not a number or not within range\n", str
);
1133 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
1135 char *str
= dl_argv_next(dl
);
1139 pr_err("Unsigned number argument expected\n");
1143 err
= strtouint16_t(str
, p_val
);
1145 pr_err("\"%s\" is not a number or not within range\n", str
);
1151 static int dl_argv_bool(struct dl
*dl
, bool *p_val
)
1153 char *str
= dl_argv_next(dl
);
1157 pr_err("Boolean argument expected\n");
1161 err
= strtobool(str
, p_val
);
1163 pr_err("\"%s\" is not a valid boolean value\n", str
);
1169 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
1171 const char *str
= dl_argv_next(dl
);
1174 pr_err("String parameter expected\n");
1181 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
1183 if (strcmp(typestr
, "auto") == 0) {
1184 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
1185 } else if (strcmp(typestr
, "eth") == 0) {
1186 *p_type
= DEVLINK_PORT_TYPE_ETH
;
1187 } else if (strcmp(typestr
, "ib") == 0) {
1188 *p_type
= DEVLINK_PORT_TYPE_IB
;
1190 pr_err("Unknown port type \"%s\"\n", typestr
);
1196 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
1198 if (strcmp(typestr
, "ingress") == 0) {
1199 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
1200 } else if (strcmp(typestr
, "egress") == 0) {
1201 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
1203 pr_err("Unknown pool type \"%s\"\n", typestr
);
1209 static int threshold_type_get(const char *typestr
,
1210 enum devlink_sb_threshold_type
*p_type
)
1212 if (strcmp(typestr
, "static") == 0) {
1213 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
1214 } else if (strcmp(typestr
, "dynamic") == 0) {
1215 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
1217 pr_err("Unknown threshold type \"%s\"\n", typestr
);
1223 static int eswitch_mode_get(const char *typestr
,
1224 enum devlink_eswitch_mode
*p_mode
)
1226 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
1227 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
1228 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
1229 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
1231 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
1237 static int eswitch_inline_mode_get(const char *typestr
,
1238 enum devlink_eswitch_inline_mode
*p_mode
)
1240 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
1241 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
1242 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
1243 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
1244 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
1245 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
1246 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
1247 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
1249 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
1256 eswitch_encap_mode_get(const char *typestr
,
1257 enum devlink_eswitch_encap_mode
*p_encap_mode
)
1259 /* The initial implementation incorrectly accepted "enable"/"disable".
1260 * Carry it to maintain backward compatibility.
1262 if (strcmp(typestr
, "disable") == 0 ||
1263 strcmp(typestr
, ESWITCH_ENCAP_MODE_NONE
) == 0) {
1264 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_NONE
;
1265 } else if (strcmp(typestr
, "enable") == 0 ||
1266 strcmp(typestr
, ESWITCH_ENCAP_MODE_BASIC
) == 0) {
1267 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_BASIC
;
1269 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
1275 static int param_cmode_get(const char *cmodestr
,
1276 enum devlink_param_cmode
*cmode
)
1278 if (strcmp(cmodestr
, PARAM_CMODE_RUNTIME_STR
) == 0) {
1279 *cmode
= DEVLINK_PARAM_CMODE_RUNTIME
;
1280 } else if (strcmp(cmodestr
, PARAM_CMODE_DRIVERINIT_STR
) == 0) {
1281 *cmode
= DEVLINK_PARAM_CMODE_DRIVERINIT
;
1282 } else if (strcmp(cmodestr
, PARAM_CMODE_PERMANENT_STR
) == 0) {
1283 *cmode
= DEVLINK_PARAM_CMODE_PERMANENT
;
1285 pr_err("Unknown configuration mode \"%s\"\n", cmodestr
);
1291 static int trap_action_get(const char *actionstr
,
1292 enum devlink_trap_action
*p_action
)
1294 if (strcmp(actionstr
, "drop") == 0) {
1295 *p_action
= DEVLINK_TRAP_ACTION_DROP
;
1296 } else if (strcmp(actionstr
, "trap") == 0) {
1297 *p_action
= DEVLINK_TRAP_ACTION_TRAP
;
1299 pr_err("Unknown trap action \"%s\"\n", actionstr
);
1305 struct dl_args_metadata
{
1307 char err_msg
[DL_ARGS_REQUIRED_MAX_ERR_LEN
];
1310 static const struct dl_args_metadata dl_args_required
[] = {
1311 {DL_OPT_PORT_TYPE
, "Port type not set."},
1312 {DL_OPT_PORT_COUNT
, "Port split count option expected."},
1313 {DL_OPT_SB_POOL
, "Pool index option expected."},
1314 {DL_OPT_SB_SIZE
, "Pool size option expected."},
1315 {DL_OPT_SB_TYPE
, "Pool type option expected."},
1316 {DL_OPT_SB_THTYPE
, "Pool threshold type option expected."},
1317 {DL_OPT_SB_TH
, "Threshold option expected."},
1318 {DL_OPT_SB_TC
, "TC index option expected."},
1319 {DL_OPT_ESWITCH_MODE
, "E-Switch mode option expected."},
1320 {DL_OPT_ESWITCH_INLINE_MODE
, "E-Switch inline-mode option expected."},
1321 {DL_OPT_DPIPE_TABLE_NAME
, "Dpipe table name expected."},
1322 {DL_OPT_DPIPE_TABLE_COUNTERS
, "Dpipe table counter state expected."},
1323 {DL_OPT_ESWITCH_ENCAP_MODE
, "E-Switch encapsulation option expected."},
1324 {DL_OPT_RESOURCE_PATH
, "Resource path expected."},
1325 {DL_OPT_RESOURCE_SIZE
, "Resource size expected."},
1326 {DL_OPT_PARAM_NAME
, "Parameter name expected."},
1327 {DL_OPT_PARAM_VALUE
, "Value to set expected."},
1328 {DL_OPT_PARAM_CMODE
, "Configuration mode expected."},
1329 {DL_OPT_REGION_SNAPSHOT_ID
, "Region snapshot id expected."},
1330 {DL_OPT_REGION_ADDRESS
, "Region address value expected."},
1331 {DL_OPT_REGION_LENGTH
, "Region length value expected."},
1332 {DL_OPT_HEALTH_REPORTER_NAME
, "Reporter's name is expected."},
1333 {DL_OPT_TRAP_NAME
, "Trap's name is expected."},
1334 {DL_OPT_TRAP_GROUP_NAME
, "Trap group's name is expected."},
1337 static int dl_args_finding_required_validate(uint64_t o_required
,
1343 for (i
= 0; i
< ARRAY_SIZE(dl_args_required
); i
++) {
1344 o_flag
= dl_args_required
[i
].o_flag
;
1345 if ((o_required
& o_flag
) && !(o_found
& o_flag
)) {
1346 pr_err("%s\n", dl_args_required
[i
].err_msg
);
1350 if (o_required
& ~o_found
) {
1351 pr_err("BUG: unknown argument required but not found\n");
1357 static int dl_argv_parse(struct dl
*dl
, uint64_t o_required
,
1358 uint64_t o_optional
)
1360 struct dl_opts
*opts
= &dl
->opts
;
1361 uint64_t o_all
= o_required
| o_optional
;
1362 uint64_t o_found
= 0;
1365 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
1366 uint64_t handle_bit
;
1368 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
1369 &opts
->port_index
, &handle_bit
);
1372 o_required
&= ~(DL_OPT_HANDLE
| DL_OPT_HANDLEP
) | handle_bit
;
1373 o_found
|= handle_bit
;
1374 } else if (o_required
& DL_OPT_HANDLE
) {
1375 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
1378 o_found
|= DL_OPT_HANDLE
;
1379 } else if (o_required
& DL_OPT_HANDLEP
) {
1380 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
1384 o_found
|= DL_OPT_HANDLEP
;
1385 } else if (o_required
& DL_OPT_HANDLE_REGION
) {
1386 err
= dl_argv_handle_region(dl
, &opts
->bus_name
,
1388 &opts
->region_name
);
1391 o_found
|= DL_OPT_HANDLE_REGION
;
1394 while (dl_argc(dl
)) {
1395 if (dl_argv_match(dl
, "type") &&
1396 (o_all
& DL_OPT_PORT_TYPE
)) {
1397 const char *typestr
;
1400 err
= dl_argv_str(dl
, &typestr
);
1403 err
= port_type_get(typestr
, &opts
->port_type
);
1406 o_found
|= DL_OPT_PORT_TYPE
;
1407 } else if (dl_argv_match(dl
, "count") &&
1408 (o_all
& DL_OPT_PORT_COUNT
)) {
1410 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
1413 o_found
|= DL_OPT_PORT_COUNT
;
1414 } else if (dl_argv_match(dl
, "sb") &&
1415 (o_all
& DL_OPT_SB
)) {
1417 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
1420 o_found
|= DL_OPT_SB
;
1421 } else if (dl_argv_match(dl
, "pool") &&
1422 (o_all
& DL_OPT_SB_POOL
)) {
1424 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
1427 o_found
|= DL_OPT_SB_POOL
;
1428 } else if (dl_argv_match(dl
, "size") &&
1429 (o_all
& DL_OPT_SB_SIZE
)) {
1431 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
1434 o_found
|= DL_OPT_SB_SIZE
;
1435 } else if (dl_argv_match(dl
, "type") &&
1436 (o_all
& DL_OPT_SB_TYPE
)) {
1437 const char *typestr
;
1440 err
= dl_argv_str(dl
, &typestr
);
1443 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
1446 o_found
|= DL_OPT_SB_TYPE
;
1447 } else if (dl_argv_match(dl
, "thtype") &&
1448 (o_all
& DL_OPT_SB_THTYPE
)) {
1449 const char *typestr
;
1452 err
= dl_argv_str(dl
, &typestr
);
1455 err
= threshold_type_get(typestr
,
1456 &opts
->sb_pool_thtype
);
1459 o_found
|= DL_OPT_SB_THTYPE
;
1460 } else if (dl_argv_match(dl
, "th") &&
1461 (o_all
& DL_OPT_SB_TH
)) {
1463 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
1466 o_found
|= DL_OPT_SB_TH
;
1467 } else if (dl_argv_match(dl
, "tc") &&
1468 (o_all
& DL_OPT_SB_TC
)) {
1470 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
1473 o_found
|= DL_OPT_SB_TC
;
1474 } else if (dl_argv_match(dl
, "mode") &&
1475 (o_all
& DL_OPT_ESWITCH_MODE
)) {
1476 const char *typestr
;
1479 err
= dl_argv_str(dl
, &typestr
);
1482 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
1485 o_found
|= DL_OPT_ESWITCH_MODE
;
1486 } else if (dl_argv_match(dl
, "inline-mode") &&
1487 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1488 const char *typestr
;
1491 err
= dl_argv_str(dl
, &typestr
);
1494 err
= eswitch_inline_mode_get(
1495 typestr
, &opts
->eswitch_inline_mode
);
1498 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
1499 } else if (dl_argv_match(dl
, "name") &&
1500 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
1502 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
1505 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
1506 } else if ((dl_argv_match(dl
, "counters") ||
1507 dl_argv_match(dl
, "counters_enabled")) &&
1508 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1510 err
= dl_argv_bool(dl
, &opts
->dpipe_counters_enabled
);
1513 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
1514 } else if ((dl_argv_match(dl
, "encap") || /* Original incorrect implementation */
1515 dl_argv_match(dl
, "encap-mode")) &&
1516 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1517 const char *typestr
;
1520 err
= dl_argv_str(dl
, &typestr
);
1523 err
= eswitch_encap_mode_get(typestr
,
1524 &opts
->eswitch_encap_mode
);
1527 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
1528 } else if (dl_argv_match(dl
, "path") &&
1529 (o_all
& DL_OPT_RESOURCE_PATH
)) {
1531 err
= dl_argv_str(dl
, &opts
->resource_path
);
1534 o_found
|= DL_OPT_RESOURCE_PATH
;
1535 } else if (dl_argv_match(dl
, "size") &&
1536 (o_all
& DL_OPT_RESOURCE_SIZE
)) {
1538 err
= dl_argv_uint64_t(dl
, &opts
->resource_size
);
1541 o_found
|= DL_OPT_RESOURCE_SIZE
;
1542 } else if (dl_argv_match(dl
, "name") &&
1543 (o_all
& DL_OPT_PARAM_NAME
)) {
1545 err
= dl_argv_str(dl
, &opts
->param_name
);
1548 o_found
|= DL_OPT_PARAM_NAME
;
1549 } else if (dl_argv_match(dl
, "value") &&
1550 (o_all
& DL_OPT_PARAM_VALUE
)) {
1552 err
= dl_argv_str(dl
, &opts
->param_value
);
1555 o_found
|= DL_OPT_PARAM_VALUE
;
1556 } else if (dl_argv_match(dl
, "cmode") &&
1557 (o_all
& DL_OPT_PARAM_CMODE
)) {
1558 const char *cmodestr
;
1561 err
= dl_argv_str(dl
, &cmodestr
);
1564 err
= param_cmode_get(cmodestr
, &opts
->cmode
);
1567 o_found
|= DL_OPT_PARAM_CMODE
;
1568 } else if (dl_argv_match(dl
, "snapshot") &&
1569 (o_all
& DL_OPT_REGION_SNAPSHOT_ID
)) {
1571 err
= dl_argv_uint32_t(dl
, &opts
->region_snapshot_id
);
1574 o_found
|= DL_OPT_REGION_SNAPSHOT_ID
;
1575 } else if (dl_argv_match(dl
, "address") &&
1576 (o_all
& DL_OPT_REGION_ADDRESS
)) {
1578 err
= dl_argv_uint64_t(dl
, &opts
->region_address
);
1581 o_found
|= DL_OPT_REGION_ADDRESS
;
1582 } else if (dl_argv_match(dl
, "length") &&
1583 (o_all
& DL_OPT_REGION_LENGTH
)) {
1585 err
= dl_argv_uint64_t(dl
, &opts
->region_length
);
1588 o_found
|= DL_OPT_REGION_LENGTH
;
1589 } else if (dl_argv_match(dl
, "file") &&
1590 (o_all
& DL_OPT_FLASH_FILE_NAME
)) {
1592 err
= dl_argv_str(dl
, &opts
->flash_file_name
);
1595 o_found
|= DL_OPT_FLASH_FILE_NAME
;
1596 } else if (dl_argv_match(dl
, "component") &&
1597 (o_all
& DL_OPT_FLASH_COMPONENT
)) {
1599 err
= dl_argv_str(dl
, &opts
->flash_component
);
1602 o_found
|= DL_OPT_FLASH_COMPONENT
;
1603 } else if (dl_argv_match(dl
, "reporter") &&
1604 (o_all
& DL_OPT_HEALTH_REPORTER_NAME
)) {
1606 err
= dl_argv_str(dl
, &opts
->reporter_name
);
1609 o_found
|= DL_OPT_HEALTH_REPORTER_NAME
;
1610 } else if (dl_argv_match(dl
, "grace_period") &&
1611 (o_all
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)) {
1613 err
= dl_argv_uint64_t(dl
,
1614 &opts
->reporter_graceful_period
);
1617 o_found
|= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
;
1618 } else if (dl_argv_match(dl
, "auto_recover") &&
1619 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)) {
1621 err
= dl_argv_bool(dl
, &opts
->reporter_auto_recover
);
1624 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
;
1625 } else if (dl_argv_match(dl
, "auto_dump") &&
1626 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_DUMP
)) {
1628 err
= dl_argv_bool(dl
, &opts
->reporter_auto_dump
);
1631 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_DUMP
;
1632 } else if (dl_argv_match(dl
, "trap") &&
1633 (o_all
& DL_OPT_TRAP_NAME
)) {
1635 err
= dl_argv_str(dl
, &opts
->trap_name
);
1638 o_found
|= DL_OPT_TRAP_NAME
;
1639 } else if (dl_argv_match(dl
, "group") &&
1640 (o_all
& DL_OPT_TRAP_GROUP_NAME
)) {
1642 err
= dl_argv_str(dl
, &opts
->trap_group_name
);
1645 o_found
|= DL_OPT_TRAP_GROUP_NAME
;
1646 } else if (dl_argv_match(dl
, "action") &&
1647 (o_all
& DL_OPT_TRAP_ACTION
)) {
1648 const char *actionstr
;
1651 err
= dl_argv_str(dl
, &actionstr
);
1654 err
= trap_action_get(actionstr
, &opts
->trap_action
);
1657 o_found
|= DL_OPT_TRAP_ACTION
;
1658 } else if (dl_argv_match(dl
, "netns") &&
1659 (o_all
& DL_OPT_NETNS
)) {
1660 const char *netns_str
;
1663 err
= dl_argv_str(dl
, &netns_str
);
1666 opts
->netns
= netns_get_fd(netns_str
);
1667 if ((int)opts
->netns
< 0) {
1669 err
= dl_argv_uint32_t(dl
, &opts
->netns
);
1672 opts
->netns_is_pid
= true;
1674 o_found
|= DL_OPT_NETNS
;
1675 } else if (dl_argv_match(dl
, "policer") &&
1676 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1678 err
= dl_argv_uint32_t(dl
, &opts
->trap_policer_id
);
1681 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1682 } else if (dl_argv_match(dl
, "nopolicer") &&
1683 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1685 opts
->trap_policer_id
= 0;
1686 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1687 } else if (dl_argv_match(dl
, "rate") &&
1688 (o_all
& DL_OPT_TRAP_POLICER_RATE
)) {
1690 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_rate
);
1693 o_found
|= DL_OPT_TRAP_POLICER_RATE
;
1694 } else if (dl_argv_match(dl
, "burst") &&
1695 (o_all
& DL_OPT_TRAP_POLICER_BURST
)) {
1697 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_burst
);
1700 o_found
|= DL_OPT_TRAP_POLICER_BURST
;
1702 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
1707 opts
->present
= o_found
;
1709 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
1711 opts
->present
|= DL_OPT_SB
;
1714 return dl_args_finding_required_validate(o_required
, o_found
);
1717 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1719 struct dl_opts
*opts
= &dl
->opts
;
1721 if (opts
->present
& DL_OPT_HANDLE
) {
1722 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1723 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1724 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1725 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1726 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1727 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1729 } else if (opts
->present
& DL_OPT_HANDLE_REGION
) {
1730 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1731 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1732 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_REGION_NAME
,
1735 if (opts
->present
& DL_OPT_PORT_TYPE
)
1736 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1738 if (opts
->present
& DL_OPT_PORT_COUNT
)
1739 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1741 if (opts
->present
& DL_OPT_SB
)
1742 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1744 if (opts
->present
& DL_OPT_SB_POOL
)
1745 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1746 opts
->sb_pool_index
);
1747 if (opts
->present
& DL_OPT_SB_SIZE
)
1748 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1749 opts
->sb_pool_size
);
1750 if (opts
->present
& DL_OPT_SB_TYPE
)
1751 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1752 opts
->sb_pool_type
);
1753 if (opts
->present
& DL_OPT_SB_THTYPE
)
1754 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1755 opts
->sb_pool_thtype
);
1756 if (opts
->present
& DL_OPT_SB_TH
)
1757 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1758 opts
->sb_threshold
);
1759 if (opts
->present
& DL_OPT_SB_TC
)
1760 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1762 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1763 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1764 opts
->eswitch_mode
);
1765 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1766 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1767 opts
->eswitch_inline_mode
);
1768 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1769 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1770 opts
->dpipe_table_name
);
1771 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1772 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1773 opts
->dpipe_counters_enabled
);
1774 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1775 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1776 opts
->eswitch_encap_mode
);
1777 if ((opts
->present
& DL_OPT_RESOURCE_PATH
) && opts
->resource_id_valid
)
1778 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_ID
,
1780 if (opts
->present
& DL_OPT_RESOURCE_SIZE
)
1781 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_SIZE
,
1782 opts
->resource_size
);
1783 if (opts
->present
& DL_OPT_PARAM_NAME
)
1784 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_NAME
,
1786 if (opts
->present
& DL_OPT_PARAM_CMODE
)
1787 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_CMODE
,
1789 if (opts
->present
& DL_OPT_REGION_SNAPSHOT_ID
)
1790 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_REGION_SNAPSHOT_ID
,
1791 opts
->region_snapshot_id
);
1792 if (opts
->present
& DL_OPT_REGION_ADDRESS
)
1793 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_ADDR
,
1794 opts
->region_address
);
1795 if (opts
->present
& DL_OPT_REGION_LENGTH
)
1796 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_LEN
,
1797 opts
->region_length
);
1798 if (opts
->present
& DL_OPT_FLASH_FILE_NAME
)
1799 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME
,
1800 opts
->flash_file_name
);
1801 if (opts
->present
& DL_OPT_FLASH_COMPONENT
)
1802 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
,
1803 opts
->flash_component
);
1804 if (opts
->present
& DL_OPT_HEALTH_REPORTER_NAME
)
1805 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
1806 opts
->reporter_name
);
1807 if (opts
->present
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)
1808 mnl_attr_put_u64(nlh
,
1809 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
,
1810 opts
->reporter_graceful_period
);
1811 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)
1812 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
,
1813 opts
->reporter_auto_recover
);
1814 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_DUMP
)
1815 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
,
1816 opts
->reporter_auto_dump
);
1817 if (opts
->present
& DL_OPT_TRAP_NAME
)
1818 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_NAME
,
1820 if (opts
->present
& DL_OPT_TRAP_GROUP_NAME
)
1821 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_GROUP_NAME
,
1822 opts
->trap_group_name
);
1823 if (opts
->present
& DL_OPT_TRAP_ACTION
)
1824 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_TRAP_ACTION
,
1826 if (opts
->present
& DL_OPT_NETNS
)
1827 mnl_attr_put_u32(nlh
,
1828 opts
->netns_is_pid
? DEVLINK_ATTR_NETNS_PID
:
1829 DEVLINK_ATTR_NETNS_FD
,
1831 if (opts
->present
& DL_OPT_TRAP_POLICER_ID
)
1832 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_TRAP_POLICER_ID
,
1833 opts
->trap_policer_id
);
1834 if (opts
->present
& DL_OPT_TRAP_POLICER_RATE
)
1835 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_RATE
,
1836 opts
->trap_policer_rate
);
1837 if (opts
->present
& DL_OPT_TRAP_POLICER_BURST
)
1838 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_BURST
,
1839 opts
->trap_policer_burst
);
1842 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1843 uint64_t o_required
, uint64_t o_optional
)
1847 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1850 dl_opts_put(nlh
, dl
);
1854 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1856 struct dl_opts
*opts
= &dl
->opts
;
1857 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1858 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1859 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1860 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1862 if (opts
->present
& DL_OPT_HANDLE
&&
1863 attr_bus_name
&& attr_dev_name
) {
1864 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1865 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1867 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1868 strcmp(dev_name
, opts
->dev_name
) != 0)
1871 if (opts
->present
& DL_OPT_HANDLEP
&&
1872 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1873 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1874 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1875 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1877 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1878 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1879 port_index
!= opts
->port_index
)
1882 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1883 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1885 if (sb_index
!= opts
->sb_index
)
1891 static void cmd_dev_help(void)
1893 pr_err("Usage: devlink dev show [ DEV ]\n");
1894 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1895 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1896 pr_err(" [ encap-mode { none | basic } ]\n");
1897 pr_err(" devlink dev eswitch show DEV\n");
1898 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1899 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1900 pr_err(" devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
1901 pr_err(" devlink dev info [ DEV ]\n");
1902 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1905 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1906 const char *dev_name
)
1908 if (!dl
->arr_last
.present
)
1910 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1911 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1914 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1915 const char *dev_name
)
1917 dl
->arr_last
.present
= true;
1918 free(dl
->arr_last
.dev_name
);
1919 free(dl
->arr_last
.bus_name
);
1920 dl
->arr_last
.bus_name
= strdup(bus_name
);
1921 dl
->arr_last
.dev_name
= strdup(dev_name
);
1924 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1925 const char *dev_name
)
1927 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1930 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1931 const char *dev_name
)
1933 return dl
->arr_last
.present
&&
1934 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1937 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1938 bool content
, bool array
)
1940 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1941 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1944 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
1946 if (dl
->json_output
) {
1948 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1949 close_json_array(PRINT_JSON
, NULL
);
1950 if (should_arr_last_handle_start(dl
, bus_name
,
1952 open_json_array(PRINT_JSON
, buf
);
1953 open_json_object(NULL
);
1954 arr_last_handle_set(dl
, bus_name
, dev_name
);
1956 open_json_object(NULL
);
1959 open_json_object(buf
);
1963 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1964 __pr_out_indent_dec();
1965 if (should_arr_last_handle_start(dl
, bus_name
,
1967 pr_out("%s%s", buf
, content
? ":" : "");
1969 __pr_out_indent_inc();
1970 arr_last_handle_set(dl
, bus_name
, dev_name
);
1973 pr_out("%s%s", buf
, content
? ":" : "");
1978 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
1980 __pr_out_handle_start(dl
, tb
, true, true);
1983 static void pr_out_handle_end(struct dl
*dl
)
1985 if (dl
->json_output
)
1986 close_json_object();
1991 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
1993 __pr_out_handle_start(dl
, tb
, false, false);
1994 pr_out_handle_end(dl
);
1997 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
1998 const char *dev_name
, uint32_t port_index
)
2000 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
2001 dl
->arr_last
.port_index
== port_index
;
2004 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
2005 const char *dev_name
, uint32_t port_index
)
2007 arr_last_handle_set(dl
, bus_name
, dev_name
);
2008 dl
->arr_last
.port_index
= port_index
;
2011 static bool should_arr_last_port_handle_start(struct dl
*dl
,
2012 const char *bus_name
,
2013 const char *dev_name
,
2014 uint32_t port_index
)
2016 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
2019 static bool should_arr_last_port_handle_end(struct dl
*dl
,
2020 const char *bus_name
,
2021 const char *dev_name
,
2022 uint32_t port_index
)
2024 return dl
->arr_last
.present
&&
2025 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
2028 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
2029 const char *dev_name
,
2030 uint32_t port_index
, bool try_nice
,
2033 static char buf
[64];
2034 char *ifname
= NULL
;
2036 if (dl
->no_nice_names
|| !try_nice
||
2037 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
2038 port_index
, &ifname
) != 0)
2039 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
2041 sprintf(buf
, "%s", ifname
);
2043 if (dl
->json_output
) {
2045 if (should_arr_last_port_handle_end(dl
, bus_name
,
2048 close_json_array(PRINT_JSON
, NULL
);
2049 if (should_arr_last_port_handle_start(dl
, bus_name
,
2052 open_json_array(PRINT_JSON
, buf
);
2053 open_json_object(NULL
);
2054 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
2057 open_json_object(NULL
);
2060 open_json_object(buf
);
2067 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
2069 const char *bus_name
;
2070 const char *dev_name
;
2071 uint32_t port_index
;
2073 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2074 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2075 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
2076 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
2079 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
2081 const char *bus_name
;
2082 const char *dev_name
;
2083 uint32_t port_index
;
2085 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2086 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2087 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
2088 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
2091 static void pr_out_port_handle_end(struct dl
*dl
)
2093 if (dl
->json_output
)
2094 close_json_object();
2099 static void pr_out_region_chunk_start(struct dl
*dl
, uint64_t addr
)
2101 if (dl
->json_output
) {
2102 print_uint(PRINT_JSON
, "address", NULL
, addr
);
2103 open_json_array(PRINT_JSON
, "data");
2107 static void pr_out_region_chunk_end(struct dl
*dl
)
2109 if (dl
->json_output
)
2110 close_json_array(PRINT_JSON
, NULL
);
2113 static void pr_out_region_chunk(struct dl
*dl
, uint8_t *data
, uint32_t len
,
2116 static uint64_t align_val
;
2119 pr_out_region_chunk_start(dl
, addr
);
2121 if (!dl
->json_output
)
2122 if (!(align_val
% 16))
2123 pr_out("%s%016"PRIx64
" ",
2124 align_val
? "\n" : "",
2129 if (dl
->json_output
)
2130 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
2132 pr_out("%02x ", data
[i
]);
2137 pr_out_region_chunk_end(dl
);
2140 static void pr_out_stats(struct dl
*dl
, struct nlattr
*nla_stats
)
2142 struct nlattr
*tb
[DEVLINK_ATTR_STATS_MAX
+ 1] = {};
2148 err
= mnl_attr_parse_nested(nla_stats
, attr_stats_cb
, tb
);
2149 if (err
!= MNL_CB_OK
)
2152 pr_out_object_start(dl
, "stats");
2153 pr_out_object_start(dl
, "rx");
2154 if (tb
[DEVLINK_ATTR_STATS_RX_BYTES
])
2155 pr_out_u64(dl
, "bytes",
2156 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_BYTES
]));
2157 if (tb
[DEVLINK_ATTR_STATS_RX_PACKETS
])
2158 pr_out_u64(dl
, "packets",
2159 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_PACKETS
]));
2160 if (tb
[DEVLINK_ATTR_STATS_RX_DROPPED
])
2161 pr_out_u64(dl
, "dropped",
2162 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_DROPPED
]));
2163 pr_out_object_end(dl
);
2164 pr_out_object_end(dl
);
2167 static const char *param_cmode_name(uint8_t cmode
)
2170 case DEVLINK_PARAM_CMODE_RUNTIME
:
2171 return PARAM_CMODE_RUNTIME_STR
;
2172 case DEVLINK_PARAM_CMODE_DRIVERINIT
:
2173 return PARAM_CMODE_DRIVERINIT_STR
;
2174 case DEVLINK_PARAM_CMODE_PERMANENT
:
2175 return PARAM_CMODE_PERMANENT_STR
;
2176 default: return "<unknown type>";
2180 static const char *eswitch_mode_name(uint32_t mode
)
2183 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
2184 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
2185 default: return "<unknown mode>";
2189 static const char *eswitch_inline_mode_name(uint32_t mode
)
2192 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
2193 return ESWITCH_INLINE_MODE_NONE
;
2194 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
2195 return ESWITCH_INLINE_MODE_LINK
;
2196 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
2197 return ESWITCH_INLINE_MODE_NETWORK
;
2198 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
2199 return ESWITCH_INLINE_MODE_TRANSPORT
;
2201 return "<unknown mode>";
2205 static const char *eswitch_encap_mode_name(uint32_t mode
)
2208 case DEVLINK_ESWITCH_ENCAP_MODE_NONE
:
2209 return ESWITCH_ENCAP_MODE_NONE
;
2210 case DEVLINK_ESWITCH_ENCAP_MODE_BASIC
:
2211 return ESWITCH_ENCAP_MODE_BASIC
;
2213 return "<unknown mode>";
2217 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
2219 __pr_out_handle_start(dl
, tb
, true, false);
2221 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
]) {
2222 check_indent_newline(dl
);
2223 print_string(PRINT_ANY
, "mode", "mode %s",
2224 eswitch_mode_name(mnl_attr_get_u16(
2225 tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
2227 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
]) {
2228 check_indent_newline(dl
);
2229 print_string(PRINT_ANY
, "inline-mode", "inline-mode %s",
2230 eswitch_inline_mode_name(mnl_attr_get_u8(
2231 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
2233 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
2234 check_indent_newline(dl
);
2235 print_string(PRINT_ANY
, "encap-mode", "encap-mode %s",
2236 eswitch_encap_mode_name(mnl_attr_get_u8(
2237 tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
])));
2240 pr_out_handle_end(dl
);
2243 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2245 struct dl
*dl
= data
;
2246 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2247 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2249 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2250 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2251 return MNL_CB_ERROR
;
2252 pr_out_eswitch(dl
, tb
);
2256 static int cmd_dev_eswitch_show(struct dl
*dl
)
2258 struct nlmsghdr
*nlh
;
2261 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
2262 NLM_F_REQUEST
| NLM_F_ACK
);
2264 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2268 pr_out_section_start(dl
, "dev");
2269 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
2270 pr_out_section_end(dl
);
2274 static int cmd_dev_eswitch_set(struct dl
*dl
)
2276 struct nlmsghdr
*nlh
;
2279 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
2280 NLM_F_REQUEST
| NLM_F_ACK
);
2282 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
2283 DL_OPT_ESWITCH_MODE
|
2284 DL_OPT_ESWITCH_INLINE_MODE
|
2285 DL_OPT_ESWITCH_ENCAP_MODE
);
2290 if (dl
->opts
.present
== 1) {
2291 pr_err("Need to set at least one option\n");
2295 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2298 static int cmd_dev_eswitch(struct dl
*dl
)
2300 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2303 } else if (dl_argv_match(dl
, "set")) {
2305 return cmd_dev_eswitch_set(dl
);
2306 } else if (dl_argv_match(dl
, "show")) {
2308 return cmd_dev_eswitch_show(dl
);
2310 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2314 struct param_val_conv
{
2320 static bool param_val_conv_exists(const struct param_val_conv
*param_val_conv
,
2321 uint32_t len
, const char *name
)
2325 for (i
= 0; i
< len
; i
++)
2326 if (!strcmp(param_val_conv
[i
].name
, name
))
2333 param_val_conv_uint_get(const struct param_val_conv
*param_val_conv
,
2334 uint32_t len
, const char *name
, const char *vstr
,
2339 for (i
= 0; i
< len
; i
++)
2340 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2341 !strcmp(param_val_conv
[i
].vstr
, vstr
)) {
2342 *vuint
= param_val_conv
[i
].vuint
;
2350 param_val_conv_str_get(const struct param_val_conv
*param_val_conv
,
2351 uint32_t len
, const char *name
, uint32_t vuint
,
2356 for (i
= 0; i
< len
; i
++)
2357 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2358 param_val_conv
[i
].vuint
== vuint
) {
2359 *vstr
= param_val_conv
[i
].vstr
;
2366 static const struct param_val_conv param_val_conv
[] = {
2368 .name
= "fw_load_policy",
2370 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER
,
2373 .name
= "fw_load_policy",
2375 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH
,
2378 .name
= "reset_dev_on_drv_probe",
2380 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN
,
2383 .name
= "fw_load_policy",
2385 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN
,
2388 .name
= "reset_dev_on_drv_probe",
2390 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS
,
2393 .name
= "reset_dev_on_drv_probe",
2395 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER
,
2398 .name
= "reset_dev_on_drv_probe",
2400 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK
,
2404 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2406 static void pr_out_param_value(struct dl
*dl
, const char *nla_name
,
2407 int nla_type
, struct nlattr
*nl
)
2409 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2410 struct nlattr
*val_attr
;
2415 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_value
);
2416 if (err
!= MNL_CB_OK
)
2419 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2420 (nla_type
!= MNL_TYPE_FLAG
&&
2421 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2424 check_indent_newline(dl
);
2425 print_string(PRINT_ANY
, "cmode", "cmode %s",
2426 param_cmode_name(mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
])));
2428 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2430 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2436 err
= param_val_conv_str_get(param_val_conv
,
2439 mnl_attr_get_u8(val_attr
),
2443 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2445 print_uint(PRINT_ANY
, "value", " value %u",
2446 mnl_attr_get_u8(val_attr
));
2451 err
= param_val_conv_str_get(param_val_conv
,
2454 mnl_attr_get_u16(val_attr
),
2458 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2460 print_uint(PRINT_ANY
, "value", " value %u",
2461 mnl_attr_get_u16(val_attr
));
2466 err
= param_val_conv_str_get(param_val_conv
,
2469 mnl_attr_get_u32(val_attr
),
2473 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2475 print_uint(PRINT_ANY
, "value", " value %u",
2476 mnl_attr_get_u32(val_attr
));
2479 case MNL_TYPE_STRING
:
2480 print_string(PRINT_ANY
, "value", " value %s",
2481 mnl_attr_get_str(val_attr
));
2484 print_bool(PRINT_ANY
, "value", " value %s", val_attr
);
2489 static void pr_out_param(struct dl
*dl
, struct nlattr
**tb
, bool array
)
2491 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2492 struct nlattr
*param_value_attr
;
2493 const char *nla_name
;
2497 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2498 if (err
!= MNL_CB_OK
)
2500 if (!nla_param
[DEVLINK_ATTR_PARAM_NAME
] ||
2501 !nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2502 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2506 pr_out_handle_start_arr(dl
, tb
);
2508 __pr_out_handle_start(dl
, tb
, true, false);
2510 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2512 nla_name
= mnl_attr_get_str(nla_param
[DEVLINK_ATTR_PARAM_NAME
]);
2513 check_indent_newline(dl
);
2514 print_string(PRINT_ANY
, "name", "name %s ", nla_name
);
2515 if (!nla_param
[DEVLINK_ATTR_PARAM_GENERIC
])
2516 print_string(PRINT_ANY
, "type", "type %s", "driver-specific");
2518 print_string(PRINT_ANY
, "type", "type %s", "generic");
2520 pr_out_array_start(dl
, "values");
2521 mnl_attr_for_each_nested(param_value_attr
,
2522 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2523 pr_out_entry_start(dl
);
2524 pr_out_param_value(dl
, nla_name
, nla_type
, param_value_attr
);
2525 pr_out_entry_end(dl
);
2527 pr_out_array_end(dl
);
2528 pr_out_handle_end(dl
);
2531 static int cmd_dev_param_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2533 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2534 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2535 struct dl
*dl
= data
;
2537 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2538 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2539 !tb
[DEVLINK_ATTR_PARAM
])
2540 return MNL_CB_ERROR
;
2541 pr_out_param(dl
, tb
, true);
2557 static int cmd_dev_param_set_cb(const struct nlmsghdr
*nlh
, void *data
)
2559 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2560 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2561 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2562 struct nlattr
*param_value_attr
;
2563 enum devlink_param_cmode cmode
;
2564 struct param_ctx
*ctx
= data
;
2565 struct dl
*dl
= ctx
->dl
;
2569 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2570 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2571 !tb
[DEVLINK_ATTR_PARAM
])
2572 return MNL_CB_ERROR
;
2574 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2575 if (err
!= MNL_CB_OK
)
2576 return MNL_CB_ERROR
;
2578 if (!nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2579 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2580 return MNL_CB_ERROR
;
2582 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2583 mnl_attr_for_each_nested(param_value_attr
,
2584 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2585 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2586 struct nlattr
*val_attr
;
2588 err
= mnl_attr_parse_nested(param_value_attr
,
2589 attr_cb
, nla_value
);
2590 if (err
!= MNL_CB_OK
)
2591 return MNL_CB_ERROR
;
2593 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2594 (nla_type
!= MNL_TYPE_FLAG
&&
2595 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2596 return MNL_CB_ERROR
;
2598 cmode
= mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
]);
2599 if (cmode
== dl
->opts
.cmode
) {
2600 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2603 ctx
->value
.vu8
= mnl_attr_get_u8(val_attr
);
2606 ctx
->value
.vu16
= mnl_attr_get_u16(val_attr
);
2609 ctx
->value
.vu32
= mnl_attr_get_u32(val_attr
);
2611 case MNL_TYPE_STRING
:
2612 ctx
->value
.vstr
= mnl_attr_get_str(val_attr
);
2615 ctx
->value
.vbool
= val_attr
? true : false;
2621 ctx
->nla_type
= nla_type
;
2625 static int cmd_dev_param_set(struct dl
*dl
)
2627 struct param_ctx ctx
= {};
2628 struct nlmsghdr
*nlh
;
2636 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
|
2638 DL_OPT_PARAM_VALUE
|
2639 DL_OPT_PARAM_CMODE
, 0);
2643 /* Get value type */
2644 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
,
2645 NLM_F_REQUEST
| NLM_F_ACK
);
2646 dl_opts_put(nlh
, dl
);
2649 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_set_cb
, &ctx
);
2653 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_SET
,
2654 NLM_F_REQUEST
| NLM_F_ACK
);
2655 dl_opts_put(nlh
, dl
);
2657 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2658 dl
->opts
.param_name
);
2660 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_TYPE
, ctx
.nla_type
);
2661 switch (ctx
.nla_type
) {
2664 err
= param_val_conv_uint_get(param_val_conv
,
2666 dl
->opts
.param_name
,
2667 dl
->opts
.param_value
,
2671 err
= strtouint8_t(dl
->opts
.param_value
, &val_u8
);
2674 goto err_param_value_parse
;
2675 if (val_u8
== ctx
.value
.vu8
)
2677 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u8
);
2681 err
= param_val_conv_uint_get(param_val_conv
,
2683 dl
->opts
.param_name
,
2684 dl
->opts
.param_value
,
2688 err
= strtouint16_t(dl
->opts
.param_value
, &val_u16
);
2691 goto err_param_value_parse
;
2692 if (val_u16
== ctx
.value
.vu16
)
2694 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u16
);
2698 err
= param_val_conv_uint_get(param_val_conv
,
2700 dl
->opts
.param_name
,
2701 dl
->opts
.param_value
,
2704 err
= strtouint32_t(dl
->opts
.param_value
, &val_u32
);
2706 goto err_param_value_parse
;
2707 if (val_u32
== ctx
.value
.vu32
)
2709 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u32
);
2712 err
= strtobool(dl
->opts
.param_value
, &val_bool
);
2714 goto err_param_value_parse
;
2715 if (val_bool
== ctx
.value
.vbool
)
2718 mnl_attr_put(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2721 case MNL_TYPE_STRING
:
2722 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2723 dl
->opts
.param_value
);
2724 if (!strcmp(dl
->opts
.param_value
, ctx
.value
.vstr
))
2728 printf("Value type not supported\n");
2731 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2733 err_param_value_parse
:
2734 pr_err("Value \"%s\" is not a number or not within range\n",
2735 dl
->opts
.param_value
);
2739 static int cmd_dev_param_show(struct dl
*dl
)
2741 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2742 struct nlmsghdr
*nlh
;
2745 if (dl_argc(dl
) == 0)
2746 flags
|= NLM_F_DUMP
;
2748 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
, flags
);
2750 if (dl_argc(dl
) > 0) {
2751 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
|
2752 DL_OPT_PARAM_NAME
, 0);
2757 pr_out_section_start(dl
, "param");
2758 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_show_cb
, dl
);
2759 pr_out_section_end(dl
);
2763 static int cmd_dev_param(struct dl
*dl
)
2765 if (dl_argv_match(dl
, "help")) {
2768 } else if (dl_argv_match(dl
, "show") ||
2769 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2771 return cmd_dev_param_show(dl
);
2772 } else if (dl_argv_match(dl
, "set")) {
2774 return cmd_dev_param_set(dl
);
2776 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2779 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2781 struct dl
*dl
= data
;
2782 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2783 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2784 uint8_t reload_failed
= 0;
2786 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2787 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2788 return MNL_CB_ERROR
;
2790 if (tb
[DEVLINK_ATTR_RELOAD_FAILED
])
2791 reload_failed
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_RELOAD_FAILED
]);
2793 if (reload_failed
) {
2794 __pr_out_handle_start(dl
, tb
, true, false);
2795 check_indent_newline(dl
);
2796 print_bool(PRINT_ANY
, "reload_failed", "reload_failed %s", true);
2797 pr_out_handle_end(dl
);
2799 pr_out_handle(dl
, tb
);
2805 static int cmd_dev_show(struct dl
*dl
)
2807 struct nlmsghdr
*nlh
;
2808 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2811 if (dl_argc(dl
) == 0)
2812 flags
|= NLM_F_DUMP
;
2814 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
2816 if (dl_argc(dl
) > 0) {
2817 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2822 pr_out_section_start(dl
, "dev");
2823 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
2824 pr_out_section_end(dl
);
2828 static int cmd_dev_reload(struct dl
*dl
)
2830 struct nlmsghdr
*nlh
;
2833 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2838 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RELOAD
,
2839 NLM_F_REQUEST
| NLM_F_ACK
);
2841 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_NETNS
);
2845 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2848 static void pr_out_versions_single(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2849 const char *name
, int type
)
2851 struct nlattr
*version
;
2853 mnl_attr_for_each(version
, nlh
, sizeof(struct genlmsghdr
)) {
2854 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2855 const char *ver_value
;
2856 const char *ver_name
;
2859 if (mnl_attr_get_type(version
) != type
)
2862 err
= mnl_attr_parse_nested(version
, attr_cb
, tb
);
2863 if (err
!= MNL_CB_OK
)
2866 if (!tb
[DEVLINK_ATTR_INFO_VERSION_NAME
] ||
2867 !tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
])
2871 pr_out_object_start(dl
, name
);
2875 ver_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_NAME
]);
2876 ver_value
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
]);
2878 check_indent_newline(dl
);
2879 print_string_name_value(ver_name
, ver_value
);
2880 if (!dl
->json_output
)
2885 pr_out_object_end(dl
);
2888 static void pr_out_info(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2889 struct nlattr
**tb
, bool has_versions
)
2891 __pr_out_handle_start(dl
, tb
, true, false);
2893 __pr_out_indent_inc();
2894 if (tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
]) {
2895 struct nlattr
*nla_drv
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
];
2897 if (!dl
->json_output
)
2899 check_indent_newline(dl
);
2900 print_string(PRINT_ANY
, "driver", "driver %s",
2901 mnl_attr_get_str(nla_drv
));
2904 if (tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
]) {
2905 struct nlattr
*nla_sn
= tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
];
2907 if (!dl
->json_output
)
2909 check_indent_newline(dl
);
2910 print_string(PRINT_ANY
, "serial_number", "serial_number %s",
2911 mnl_attr_get_str(nla_sn
));
2913 __pr_out_indent_dec();
2916 pr_out_object_start(dl
, "versions");
2918 pr_out_versions_single(dl
, nlh
, "fixed",
2919 DEVLINK_ATTR_INFO_VERSION_FIXED
);
2920 pr_out_versions_single(dl
, nlh
, "running",
2921 DEVLINK_ATTR_INFO_VERSION_RUNNING
);
2922 pr_out_versions_single(dl
, nlh
, "stored",
2923 DEVLINK_ATTR_INFO_VERSION_STORED
);
2925 pr_out_object_end(dl
);
2928 pr_out_handle_end(dl
);
2931 static int cmd_versions_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2933 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2934 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2935 bool has_versions
, has_info
;
2936 struct dl
*dl
= data
;
2938 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2940 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2941 return MNL_CB_ERROR
;
2943 has_versions
= tb
[DEVLINK_ATTR_INFO_VERSION_FIXED
] ||
2944 tb
[DEVLINK_ATTR_INFO_VERSION_RUNNING
] ||
2945 tb
[DEVLINK_ATTR_INFO_VERSION_STORED
];
2946 has_info
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
] ||
2947 tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
] ||
2951 pr_out_info(dl
, nlh
, tb
, has_versions
);
2956 static int cmd_dev_info(struct dl
*dl
)
2958 struct nlmsghdr
*nlh
;
2959 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2962 if (dl_argv_match(dl
, "help")) {
2967 if (dl_argc(dl
) == 0)
2968 flags
|= NLM_F_DUMP
;
2970 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_INFO_GET
, flags
);
2972 if (dl_argc(dl
) > 0) {
2973 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2978 pr_out_section_start(dl
, "info");
2979 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_versions_show_cb
, dl
);
2980 pr_out_section_end(dl
);
2984 struct cmd_dev_flash_status_ctx
{
2987 char *last_component
;
2988 uint8_t not_first
:1,
2994 static int nullstrcmp(const char *str1
, const char *str2
)
2997 return strcmp(str1
, str2
);
3000 return str1
? 1 : -1;
3003 static int cmd_dev_flash_status_cb(const struct nlmsghdr
*nlh
, void *data
)
3005 struct cmd_dev_flash_status_ctx
*ctx
= data
;
3006 struct dl_opts
*opts
= &ctx
->dl
->opts
;
3007 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3008 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3009 const char *component
= NULL
;
3010 uint64_t done
= 0, total
= 0;
3011 const char *msg
= NULL
;
3012 const char *bus_name
;
3013 const char *dev_name
;
3015 if (genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_STATUS
&&
3016 genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_END
)
3019 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3020 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
3021 return MNL_CB_ERROR
;
3022 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
3023 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
3024 if (strcmp(bus_name
, opts
->bus_name
) ||
3025 strcmp(dev_name
, opts
->dev_name
))
3026 return MNL_CB_ERROR
;
3028 if (genl
->cmd
== DEVLINK_CMD_FLASH_UPDATE_END
&& ctx
->not_first
) {
3030 free(ctx
->last_msg
);
3031 free(ctx
->last_component
);
3032 ctx
->received_end
= 1;
3036 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
])
3037 msg
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]);
3038 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
])
3039 component
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]);
3040 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
3041 done
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]);
3042 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
3043 total
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]);
3045 if (!nullstrcmp(msg
, ctx
->last_msg
) &&
3046 !nullstrcmp(component
, ctx
->last_component
) &&
3047 ctx
->last_pc
&& ctx
->not_first
) {
3048 pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3053 pr_out("[%s] ", component
);
3054 free(ctx
->last_component
);
3055 ctx
->last_component
= strdup(component
);
3059 free(ctx
->last_msg
);
3060 ctx
->last_msg
= strdup(msg
);
3064 pr_out_tty(" %3lu%%", (done
* 100) / total
);
3075 static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx
*ctx
,
3076 struct mnlg_socket
*nlg_ntf
,
3079 int nlfd
= mnlg_socket_get_fd(nlg_ntf
);
3086 for (i
= 0; i
< 3; i
++)
3088 FD_SET(pipe_r
, &fds
[0]);
3090 FD_SET(nlfd
, &fds
[0]);
3094 while (select(fdmax
, &fds
[0], &fds
[1], &fds
[2], NULL
) < 0) {
3097 pr_err("select() failed\n");
3100 if (FD_ISSET(nlfd
, &fds
[0])) {
3101 err
= _mnlg_socket_recv_run(nlg_ntf
,
3102 cmd_dev_flash_status_cb
, ctx
);
3106 if (FD_ISSET(pipe_r
, &fds
[0])) {
3107 err
= read(pipe_r
, &err2
, sizeof(err2
));
3109 pr_err("Failed to read pipe\n");
3114 ctx
->flash_done
= 1;
3120 static int cmd_dev_flash(struct dl
*dl
)
3122 struct cmd_dev_flash_status_ctx ctx
= {.dl
= dl
,};
3123 struct mnlg_socket
*nlg_ntf
;
3124 struct nlmsghdr
*nlh
;
3130 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3135 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_FLASH_UPDATE
,
3136 NLM_F_REQUEST
| NLM_F_ACK
);
3138 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_FLASH_FILE_NAME
,
3139 DL_OPT_FLASH_COMPONENT
);
3143 nlg_ntf
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
3147 err
= _mnlg_socket_group_add(nlg_ntf
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
3151 err
= pipe(pipe_fds
);
3154 pipe_r
= pipe_fds
[0];
3155 pipe_w
= pipe_fds
[1];
3163 /* In child, just execute the flash and pass returned
3164 * value through pipe once it is done.
3169 err
= _mnlg_socket_send(dl
->nlg
, nlh
);
3170 cc
= write(pipe_w
, &err
, sizeof(err
));
3172 exit(cc
!= sizeof(err
));
3177 err
= cmd_dev_flash_fds_process(&ctx
, nlg_ntf
, pipe_r
);
3180 } while (!ctx
.flash_done
|| (ctx
.not_first
&& !ctx
.received_end
));
3182 err
= _mnlg_socket_recv_run(dl
->nlg
, NULL
, NULL
);
3185 mnlg_socket_close(nlg_ntf
);
3189 static int cmd_dev(struct dl
*dl
)
3191 if (dl_argv_match(dl
, "help")) {
3194 } else if (dl_argv_match(dl
, "show") ||
3195 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3197 return cmd_dev_show(dl
);
3198 } else if (dl_argv_match(dl
, "eswitch")) {
3200 return cmd_dev_eswitch(dl
);
3201 } else if (dl_argv_match(dl
, "reload")) {
3203 return cmd_dev_reload(dl
);
3204 } else if (dl_argv_match(dl
, "param")) {
3206 return cmd_dev_param(dl
);
3207 } else if (dl_argv_match(dl
, "info")) {
3209 return cmd_dev_info(dl
);
3210 } else if (dl_argv_match(dl
, "flash")) {
3212 return cmd_dev_flash(dl
);
3214 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3218 static void cmd_port_help(void)
3220 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3221 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3222 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3223 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3226 static const char *port_type_name(uint32_t type
)
3229 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
3230 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
3231 case DEVLINK_PORT_TYPE_ETH
: return "eth";
3232 case DEVLINK_PORT_TYPE_IB
: return "ib";
3233 default: return "<unknown type>";
3237 static const char *port_flavour_name(uint16_t flavour
)
3240 case DEVLINK_PORT_FLAVOUR_PHYSICAL
:
3242 case DEVLINK_PORT_FLAVOUR_CPU
:
3244 case DEVLINK_PORT_FLAVOUR_DSA
:
3246 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3248 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3250 case DEVLINK_PORT_FLAVOUR_VIRTUAL
:
3253 return "<unknown flavour>";
3257 static void pr_out_port_pfvf_num(struct dl
*dl
, struct nlattr
**tb
)
3261 if (tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]) {
3262 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]);
3263 print_uint(PRINT_ANY
, "pfnum", " pfnum %u", fn_num
);
3265 if (tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]) {
3266 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]);
3267 print_uint(PRINT_ANY
, "vfnum", " vfnum %u", fn_num
);
3271 static void pr_out_port_function(struct dl
*dl
, struct nlattr
**tb_port
)
3273 struct nlattr
*tb
[DEVLINK_PORT_FUNCTION_ATTR_MAX
+ 1] = {};
3274 unsigned char *data
;
3275 SPRINT_BUF(hw_addr
);
3279 if (!tb_port
[DEVLINK_ATTR_PORT_FUNCTION
])
3282 err
= mnl_attr_parse_nested(tb_port
[DEVLINK_ATTR_PORT_FUNCTION
],
3283 function_attr_cb
, tb
);
3284 if (err
!= MNL_CB_OK
)
3287 if (!tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
])
3290 len
= mnl_attr_get_payload_len(tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
]);
3291 data
= mnl_attr_get_payload(tb
[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR
]);
3293 pr_out_object_start(dl
, "function");
3294 check_indent_newline(dl
);
3295 print_string(PRINT_ANY
, "hw_addr", "hw_addr %s",
3296 ll_addr_n2a(data
, len
, 0, hw_addr
, sizeof(hw_addr
)));
3297 if (!dl
->json_output
)
3298 __pr_out_indent_dec();
3299 pr_out_object_end(dl
);
3302 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
3304 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
3305 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
3307 pr_out_port_handle_start(dl
, tb
, false);
3308 check_indent_newline(dl
);
3310 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
3312 print_string(PRINT_ANY
, "type", "type %s",
3313 port_type_name(port_type
));
3315 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
3317 if (port_type
!= des_port_type
)
3318 print_string(PRINT_ANY
, "des_type", " des_type %s",
3319 port_type_name(des_port_type
));
3322 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]) {
3323 print_string(PRINT_ANY
, "netdev", " netdev %s",
3324 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
3326 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]) {
3327 print_string(PRINT_ANY
, "ibdev", " ibdev %s",
3328 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
3330 if (tb
[DEVLINK_ATTR_PORT_FLAVOUR
]) {
3331 uint16_t port_flavour
=
3332 mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_FLAVOUR
]);
3334 print_string(PRINT_ANY
, "flavour", " flavour %s",
3335 port_flavour_name(port_flavour
));
3337 switch (port_flavour
) {
3338 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3339 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3340 pr_out_port_pfvf_num(dl
, tb
);
3346 if (tb
[DEVLINK_ATTR_PORT_NUMBER
]) {
3347 uint32_t port_number
;
3349 port_number
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_NUMBER
]);
3350 print_uint(PRINT_ANY
, "port", " port %u", port_number
);
3352 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
3353 print_uint(PRINT_ANY
, "split_group", " split_group %u",
3354 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
3355 pr_out_port_function(dl
, tb
);
3356 pr_out_port_handle_end(dl
);
3359 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3361 struct dl
*dl
= data
;
3362 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3363 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3365 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3366 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3367 !tb
[DEVLINK_ATTR_PORT_INDEX
])
3368 return MNL_CB_ERROR
;
3369 pr_out_port(dl
, tb
);
3373 static int cmd_port_show(struct dl
*dl
)
3375 struct nlmsghdr
*nlh
;
3376 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3379 if (dl_argc(dl
) == 0)
3380 flags
|= NLM_F_DUMP
;
3382 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
3384 if (dl_argc(dl
) > 0) {
3385 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3390 pr_out_section_start(dl
, "port");
3391 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
3392 pr_out_section_end(dl
);
3396 static int cmd_port_set(struct dl
*dl
)
3398 struct nlmsghdr
*nlh
;
3401 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
3402 NLM_F_REQUEST
| NLM_F_ACK
);
3404 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
3408 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3411 static int cmd_port_split(struct dl
*dl
)
3413 struct nlmsghdr
*nlh
;
3416 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
3417 NLM_F_REQUEST
| NLM_F_ACK
);
3419 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
3423 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3426 static int cmd_port_unsplit(struct dl
*dl
)
3428 struct nlmsghdr
*nlh
;
3431 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
3432 NLM_F_REQUEST
| NLM_F_ACK
);
3434 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3438 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3441 static int cmd_port(struct dl
*dl
)
3443 if (dl_argv_match(dl
, "help")) {
3446 } else if (dl_argv_match(dl
, "show") ||
3447 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3449 return cmd_port_show(dl
);
3450 } else if (dl_argv_match(dl
, "set")) {
3452 return cmd_port_set(dl
);
3453 } else if (dl_argv_match(dl
, "split")) {
3455 return cmd_port_split(dl
);
3456 } else if (dl_argv_match(dl
, "unsplit")) {
3458 return cmd_port_unsplit(dl
);
3460 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3464 static void cmd_sb_help(void)
3466 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
3467 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
3468 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
3469 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
3470 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3471 pr_err(" pool POOL_INDEX ]\n");
3472 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3473 pr_err(" pool POOL_INDEX th THRESHOLD\n");
3474 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3475 pr_err(" type { ingress | egress } ]\n");
3476 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3477 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
3478 pr_err(" th THRESHOLD\n");
3479 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
3480 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
3481 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
3484 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
3486 pr_out_handle_start_arr(dl
, tb
);
3487 check_indent_newline(dl
);
3488 print_uint(PRINT_ANY
, "sb", "sb %u",
3489 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3490 print_uint(PRINT_ANY
, "size", " size %u",
3491 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
3492 print_uint(PRINT_ANY
, "ing_pools", " ing_pools %u",
3493 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
3494 print_uint(PRINT_ANY
, "eg_pools", " eg_pools %u",
3495 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
3496 print_uint(PRINT_ANY
, "ing_tcs", " ing_tcs %u",
3497 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
3498 print_uint(PRINT_ANY
, "eg_tcs", " eg_tcs %u",
3499 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
3500 pr_out_handle_end(dl
);
3503 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3505 struct dl
*dl
= data
;
3506 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3507 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3509 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3510 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3511 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
3512 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
3513 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
3514 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
3515 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
3516 return MNL_CB_ERROR
;
3521 static int cmd_sb_show(struct dl
*dl
)
3523 struct nlmsghdr
*nlh
;
3524 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3527 if (dl_argc(dl
) == 0)
3528 flags
|= NLM_F_DUMP
;
3530 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
3532 if (dl_argc(dl
) > 0) {
3533 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3538 pr_out_section_start(dl
, "sb");
3539 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
3540 pr_out_section_end(dl
);
3544 static const char *pool_type_name(uint8_t type
)
3547 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
3548 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
3549 default: return "<unknown type>";
3553 static const char *threshold_type_name(uint8_t type
)
3556 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
3557 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
3558 default: return "<unknown type>";
3562 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
3564 pr_out_handle_start_arr(dl
, tb
);
3565 check_indent_newline(dl
);
3566 print_uint(PRINT_ANY
, "sb", "sb %u",
3567 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3568 print_uint(PRINT_ANY
, "pool", " pool %u",
3569 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3570 print_string(PRINT_ANY
, "type", " type %s",
3571 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3572 print_uint(PRINT_ANY
, "size", " size %u",
3573 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
3574 print_string(PRINT_ANY
, "thtype", " thtype %s",
3575 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
3576 if (tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
])
3577 print_uint(PRINT_ANY
, "cell_size", " cell size %u",
3578 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
]));
3579 pr_out_handle_end(dl
);
3582 static int cmd_sb_pool_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_POOL_INDEX
] ||
3591 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
3592 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
3593 return MNL_CB_ERROR
;
3594 pr_out_sb_pool(dl
, tb
);
3598 static int cmd_sb_pool_show(struct dl
*dl
)
3600 struct nlmsghdr
*nlh
;
3601 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3604 if (dl_argc(dl
) == 0)
3605 flags
|= NLM_F_DUMP
;
3607 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
3609 if (dl_argc(dl
) > 0) {
3610 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
3616 pr_out_section_start(dl
, "pool");
3617 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
3618 pr_out_section_end(dl
);
3622 static int cmd_sb_pool_set(struct dl
*dl
)
3624 struct nlmsghdr
*nlh
;
3627 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
3628 NLM_F_REQUEST
| NLM_F_ACK
);
3630 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
3631 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
3635 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3638 static int cmd_sb_pool(struct dl
*dl
)
3640 if (dl_argv_match(dl
, "help")) {
3643 } else if (dl_argv_match(dl
, "show") ||
3644 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3646 return cmd_sb_pool_show(dl
);
3647 } else if (dl_argv_match(dl
, "set")) {
3649 return cmd_sb_pool_set(dl
);
3651 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3655 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
3657 pr_out_port_handle_start_arr(dl
, tb
, true);
3658 check_indent_newline(dl
);
3659 print_uint(PRINT_ANY
, "sb", "sb %u",
3660 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3661 print_uint(PRINT_ANY
, "pool", " pool %u",
3662 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3663 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3664 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3665 pr_out_port_handle_end(dl
);
3668 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3670 struct dl
*dl
= data
;
3671 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3672 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3674 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3675 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3676 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3677 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3678 return MNL_CB_ERROR
;
3679 pr_out_sb_port_pool(dl
, tb
);
3683 static int cmd_sb_port_pool_show(struct dl
*dl
)
3685 struct nlmsghdr
*nlh
;
3686 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3689 if (dl_argc(dl
) == 0)
3690 flags
|= NLM_F_DUMP
;
3692 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3694 if (dl_argc(dl
) > 0) {
3695 err
= dl_argv_parse_put(nlh
, dl
,
3696 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
3702 pr_out_section_start(dl
, "port_pool");
3703 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
3704 pr_out_section_end(dl
);
3708 static int cmd_sb_port_pool_set(struct dl
*dl
)
3710 struct nlmsghdr
*nlh
;
3713 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
3714 NLM_F_REQUEST
| NLM_F_ACK
);
3716 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
3717 DL_OPT_SB_TH
, DL_OPT_SB
);
3721 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3724 static int cmd_sb_port_pool(struct dl
*dl
)
3726 if (dl_argv_match(dl
, "help")) {
3729 } else if (dl_argv_match(dl
, "show") ||
3730 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3732 return cmd_sb_port_pool_show(dl
);
3733 } else if (dl_argv_match(dl
, "set")) {
3735 return cmd_sb_port_pool_set(dl
);
3737 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3741 static int cmd_sb_port(struct dl
*dl
)
3743 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3746 } else if (dl_argv_match(dl
, "pool")) {
3748 return cmd_sb_port_pool(dl
);
3750 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3754 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
3756 pr_out_port_handle_start_arr(dl
, tb
, true);
3757 check_indent_newline(dl
);
3758 print_uint(PRINT_ANY
, "sb", "sb %u",
3759 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3760 print_uint(PRINT_ANY
, "tc", " tc %u",
3761 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
3762 print_string(PRINT_ANY
, "type", " type %s",
3763 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3764 print_uint(PRINT_ANY
, "pool", " pool %u",
3765 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3766 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3767 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3768 pr_out_port_handle_end(dl
);
3771 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3773 struct dl
*dl
= data
;
3774 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3775 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3777 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3778 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3779 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3780 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3781 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3782 return MNL_CB_ERROR
;
3783 pr_out_sb_tc_bind(dl
, tb
);
3787 static int cmd_sb_tc_bind_show(struct dl
*dl
)
3789 struct nlmsghdr
*nlh
;
3790 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3793 if (dl_argc(dl
) == 0)
3794 flags
|= NLM_F_DUMP
;
3796 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3798 if (dl_argc(dl
) > 0) {
3799 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3800 DL_OPT_SB_TYPE
, DL_OPT_SB
);
3805 pr_out_section_start(dl
, "tc_bind");
3806 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
3807 pr_out_section_end(dl
);
3811 static int cmd_sb_tc_bind_set(struct dl
*dl
)
3813 struct nlmsghdr
*nlh
;
3816 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
3817 NLM_F_REQUEST
| NLM_F_ACK
);
3819 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3820 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
3825 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3828 static int cmd_sb_tc_bind(struct dl
*dl
)
3830 if (dl_argv_match(dl
, "help")) {
3833 } else if (dl_argv_match(dl
, "show") ||
3834 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3836 return cmd_sb_tc_bind_show(dl
);
3837 } else if (dl_argv_match(dl
, "set")) {
3839 return cmd_sb_tc_bind_set(dl
);
3841 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3845 static int cmd_sb_tc(struct dl
*dl
)
3847 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3850 } else if (dl_argv_match(dl
, "bind")) {
3852 return cmd_sb_tc_bind(dl
);
3854 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3859 struct list_head list
;
3863 uint32_t bound_pool_index
;
3867 struct list_head list
;
3870 uint32_t port_index
;
3872 struct list_head pool_list
;
3873 struct list_head ing_tc_list
;
3874 struct list_head eg_tc_list
;
3880 struct list_head port_list
;
3883 static struct occ_item
*occ_item_alloc(void)
3885 return calloc(1, sizeof(struct occ_item
));
3888 static void occ_item_free(struct occ_item
*occ_item
)
3893 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
3895 struct occ_port
*occ_port
;
3897 occ_port
= calloc(1, sizeof(*occ_port
));
3900 occ_port
->port_index
= port_index
;
3901 INIT_LIST_HEAD(&occ_port
->pool_list
);
3902 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
3903 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
3907 static void occ_port_free(struct occ_port
*occ_port
)
3909 struct occ_item
*occ_item
, *tmp
;
3911 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
3912 occ_item_free(occ_item
);
3913 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
3914 occ_item_free(occ_item
);
3915 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
3916 occ_item_free(occ_item
);
3919 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
3921 struct occ_show
*occ_show
;
3923 occ_show
= calloc(1, sizeof(*occ_show
));
3927 INIT_LIST_HEAD(&occ_show
->port_list
);
3931 static void occ_show_free(struct occ_show
*occ_show
)
3933 struct occ_port
*occ_port
, *tmp
;
3935 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
3936 occ_port_free(occ_port
);
3939 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
3942 struct occ_port
*occ_port
;
3943 uint32_t port_index
;
3945 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
3947 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
3948 if (occ_port
->port_index
== port_index
)
3951 occ_port
= occ_port_alloc(port_index
);
3954 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
3958 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
3961 struct occ_item
*occ_item
;
3964 pr_out_sp(7, " %s:", label
);
3965 list_for_each_entry(occ_item
, list
, list
) {
3966 if ((i
- 1) % 4 == 0 && i
!= 1)
3969 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
3970 occ_item
->bound_pool_index
);
3972 pr_out_sp(7, "%2u:", occ_item
->index
);
3973 pr_out_sp(21, "%10u/%u", occ_item
->cur
, occ_item
->max
);
3977 if ((i
- 1) % 4 != 0)
3981 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
3982 struct list_head
*list
,
3985 struct occ_item
*occ_item
;
3988 open_json_object(label
);
3989 list_for_each_entry(occ_item
, list
, list
) {
3990 sprintf(buf
, "%u", occ_item
->index
);
3991 open_json_object(buf
);
3993 print_uint(PRINT_JSON
, "bound_pool", NULL
,
3994 occ_item
->bound_pool_index
);
3995 print_uint(PRINT_JSON
, "current", NULL
, occ_item
->cur
);
3996 print_uint(PRINT_JSON
, "max", NULL
, occ_item
->max
);
3997 close_json_object();
3999 close_json_object();
4002 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
4004 if (dl
->json_output
) {
4005 pr_out_json_occ_show_item_list(dl
, "pool",
4006 &occ_port
->pool_list
, false);
4007 pr_out_json_occ_show_item_list(dl
, "itc",
4008 &occ_port
->ing_tc_list
, true);
4009 pr_out_json_occ_show_item_list(dl
, "etc",
4010 &occ_port
->eg_tc_list
, true);
4013 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
4014 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
4015 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
4019 static void pr_out_occ_show(struct occ_show
*occ_show
)
4021 struct dl
*dl
= occ_show
->dl
;
4022 struct dl_opts
*opts
= &dl
->opts
;
4023 struct occ_port
*occ_port
;
4025 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
4026 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
4027 occ_port
->port_index
, true, false);
4028 pr_out_occ_show_port(dl
, occ_port
);
4029 pr_out_port_handle_end(dl
);
4033 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
4036 struct occ_port
*occ_port
;
4037 struct occ_item
*occ_item
;
4039 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
4042 occ_port
= occ_port_get(occ_show
, tb
);
4044 occ_show
->err
= -ENOMEM
;
4048 occ_item
= occ_item_alloc();
4050 occ_show
->err
= -ENOMEM
;
4053 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4054 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4055 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4056 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
4059 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4061 struct occ_show
*occ_show
= data
;
4062 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4063 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4065 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4066 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4067 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4068 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4069 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4070 return MNL_CB_ERROR
;
4071 cmd_sb_occ_port_pool_process(occ_show
, tb
);
4075 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
4078 struct occ_port
*occ_port
;
4079 struct occ_item
*occ_item
;
4082 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
4085 occ_port
= occ_port_get(occ_show
, tb
);
4087 occ_show
->err
= -ENOMEM
;
4091 occ_item
= occ_item_alloc();
4093 occ_show
->err
= -ENOMEM
;
4096 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
4097 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4098 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4099 occ_item
->bound_pool_index
=
4100 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4101 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
4102 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
4103 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
4104 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
4105 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
4107 occ_item_free(occ_item
);
4110 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4112 struct occ_show
*occ_show
= data
;
4113 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4114 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4116 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4117 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4118 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4119 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
4120 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4121 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4122 return MNL_CB_ERROR
;
4123 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
4127 static int cmd_sb_occ_show(struct dl
*dl
)
4129 struct nlmsghdr
*nlh
;
4130 struct occ_show
*occ_show
;
4131 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
4134 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
4138 occ_show
= occ_show_alloc(dl
);
4142 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
4144 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4145 cmd_sb_occ_port_pool_process_cb
, occ_show
);
4149 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
4151 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4152 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
4156 pr_out_section_start(dl
, "occupancy");
4157 pr_out_occ_show(occ_show
);
4158 pr_out_section_end(dl
);
4161 occ_show_free(occ_show
);
4165 static int cmd_sb_occ_snapshot(struct dl
*dl
)
4167 struct nlmsghdr
*nlh
;
4170 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
4171 NLM_F_REQUEST
| NLM_F_ACK
);
4173 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4177 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4180 static int cmd_sb_occ_clearmax(struct dl
*dl
)
4182 struct nlmsghdr
*nlh
;
4185 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
4186 NLM_F_REQUEST
| NLM_F_ACK
);
4188 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4192 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4195 static int cmd_sb_occ(struct dl
*dl
)
4197 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4200 } else if (dl_argv_match(dl
, "show") ||
4201 dl_argv_match(dl
, "list")) {
4203 return cmd_sb_occ_show(dl
);
4204 } else if (dl_argv_match(dl
, "snapshot")) {
4206 return cmd_sb_occ_snapshot(dl
);
4207 } else if (dl_argv_match(dl
, "clearmax")) {
4209 return cmd_sb_occ_clearmax(dl
);
4211 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4215 static int cmd_sb(struct dl
*dl
)
4217 if (dl_argv_match(dl
, "help")) {
4220 } else if (dl_argv_match(dl
, "show") ||
4221 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
4223 return cmd_sb_show(dl
);
4224 } else if (dl_argv_match(dl
, "pool")) {
4226 return cmd_sb_pool(dl
);
4227 } else if (dl_argv_match(dl
, "port")) {
4229 return cmd_sb_port(dl
);
4230 } else if (dl_argv_match(dl
, "tc")) {
4232 return cmd_sb_tc(dl
);
4233 } else if (dl_argv_match(dl
, "occupancy")) {
4235 return cmd_sb_occ(dl
);
4237 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4241 static const char *cmd_name(uint8_t cmd
)
4244 case DEVLINK_CMD_UNSPEC
: return "unspec";
4245 case DEVLINK_CMD_GET
: return "get";
4246 case DEVLINK_CMD_SET
: return "set";
4247 case DEVLINK_CMD_NEW
: return "new";
4248 case DEVLINK_CMD_DEL
: return "del";
4249 case DEVLINK_CMD_PORT_GET
: return "get";
4250 case DEVLINK_CMD_PORT_SET
: return "set";
4251 case DEVLINK_CMD_PORT_NEW
: return "new";
4252 case DEVLINK_CMD_PORT_DEL
: return "del";
4253 case DEVLINK_CMD_PARAM_GET
: return "get";
4254 case DEVLINK_CMD_PARAM_SET
: return "set";
4255 case DEVLINK_CMD_PARAM_NEW
: return "new";
4256 case DEVLINK_CMD_PARAM_DEL
: return "del";
4257 case DEVLINK_CMD_REGION_GET
: return "get";
4258 case DEVLINK_CMD_REGION_SET
: return "set";
4259 case DEVLINK_CMD_REGION_NEW
: return "new";
4260 case DEVLINK_CMD_REGION_DEL
: return "del";
4261 case DEVLINK_CMD_FLASH_UPDATE
: return "begin";
4262 case DEVLINK_CMD_FLASH_UPDATE_END
: return "end";
4263 case DEVLINK_CMD_FLASH_UPDATE_STATUS
: return "status";
4264 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
: return "status";
4265 case DEVLINK_CMD_TRAP_GET
: return "get";
4266 case DEVLINK_CMD_TRAP_SET
: return "set";
4267 case DEVLINK_CMD_TRAP_NEW
: return "new";
4268 case DEVLINK_CMD_TRAP_DEL
: return "del";
4269 case DEVLINK_CMD_TRAP_GROUP_GET
: return "get";
4270 case DEVLINK_CMD_TRAP_GROUP_SET
: return "set";
4271 case DEVLINK_CMD_TRAP_GROUP_NEW
: return "new";
4272 case DEVLINK_CMD_TRAP_GROUP_DEL
: return "del";
4273 case DEVLINK_CMD_TRAP_POLICER_GET
: return "get";
4274 case DEVLINK_CMD_TRAP_POLICER_SET
: return "set";
4275 case DEVLINK_CMD_TRAP_POLICER_NEW
: return "new";
4276 case DEVLINK_CMD_TRAP_POLICER_DEL
: return "del";
4277 default: return "<unknown cmd>";
4281 static const char *cmd_obj(uint8_t cmd
)
4284 case DEVLINK_CMD_UNSPEC
: return "unspec";
4285 case DEVLINK_CMD_GET
:
4286 case DEVLINK_CMD_SET
:
4287 case DEVLINK_CMD_NEW
:
4288 case DEVLINK_CMD_DEL
:
4290 case DEVLINK_CMD_PORT_GET
:
4291 case DEVLINK_CMD_PORT_SET
:
4292 case DEVLINK_CMD_PORT_NEW
:
4293 case DEVLINK_CMD_PORT_DEL
:
4295 case DEVLINK_CMD_PARAM_GET
:
4296 case DEVLINK_CMD_PARAM_SET
:
4297 case DEVLINK_CMD_PARAM_NEW
:
4298 case DEVLINK_CMD_PARAM_DEL
:
4300 case DEVLINK_CMD_REGION_GET
:
4301 case DEVLINK_CMD_REGION_SET
:
4302 case DEVLINK_CMD_REGION_NEW
:
4303 case DEVLINK_CMD_REGION_DEL
:
4305 case DEVLINK_CMD_FLASH_UPDATE
:
4306 case DEVLINK_CMD_FLASH_UPDATE_END
:
4307 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4309 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4311 case DEVLINK_CMD_TRAP_GET
:
4312 case DEVLINK_CMD_TRAP_SET
:
4313 case DEVLINK_CMD_TRAP_NEW
:
4314 case DEVLINK_CMD_TRAP_DEL
:
4316 case DEVLINK_CMD_TRAP_GROUP_GET
:
4317 case DEVLINK_CMD_TRAP_GROUP_SET
:
4318 case DEVLINK_CMD_TRAP_GROUP_NEW
:
4319 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4320 return "trap-group";
4321 case DEVLINK_CMD_TRAP_POLICER_GET
:
4322 case DEVLINK_CMD_TRAP_POLICER_SET
:
4323 case DEVLINK_CMD_TRAP_POLICER_NEW
:
4324 case DEVLINK_CMD_TRAP_POLICER_DEL
:
4325 return "trap-policer";
4326 default: return "<unknown obj>";
4330 static void pr_out_mon_header(uint8_t cmd
)
4332 if (!is_json_context()) {
4333 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
4335 open_json_object(NULL
);
4336 print_string(PRINT_JSON
, "command", NULL
, cmd_name(cmd
));
4337 open_json_object(cmd_obj(cmd
));
4341 static void pr_out_mon_footer(void)
4343 if (is_json_context()) {
4344 close_json_object();
4345 close_json_object();
4349 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
4351 const char *obj
= cmd_obj(cmd
);
4352 unsigned int index
= 0;
4353 const char *cur_obj
;
4357 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4358 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
4364 static void pr_out_flash_update(struct dl
*dl
, struct nlattr
**tb
)
4366 __pr_out_handle_start(dl
, tb
, true, false);
4368 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]) {
4369 check_indent_newline(dl
);
4370 print_string(PRINT_ANY
, "msg", "msg %s",
4371 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]));
4373 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]) {
4374 check_indent_newline(dl
);
4375 print_string(PRINT_ANY
, "component", "component %s",
4376 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]));
4379 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
4380 pr_out_u64(dl
, "done",
4381 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]));
4383 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
4384 pr_out_u64(dl
, "total",
4385 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]));
4387 pr_out_handle_end(dl
);
4390 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
);
4391 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
);
4392 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4393 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4394 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4396 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
4398 struct dl
*dl
= data
;
4399 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4400 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4401 uint8_t cmd
= genl
->cmd
;
4403 if (!cmd_filter_check(dl
, cmd
))
4407 case DEVLINK_CMD_GET
: /* fall through */
4408 case DEVLINK_CMD_SET
: /* fall through */
4409 case DEVLINK_CMD_NEW
: /* fall through */
4410 case DEVLINK_CMD_DEL
:
4411 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4412 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4413 return MNL_CB_ERROR
;
4414 pr_out_mon_header(genl
->cmd
);
4415 pr_out_handle(dl
, tb
);
4416 pr_out_mon_footer();
4418 case DEVLINK_CMD_PORT_GET
: /* fall through */
4419 case DEVLINK_CMD_PORT_SET
: /* fall through */
4420 case DEVLINK_CMD_PORT_NEW
: /* fall through */
4421 case DEVLINK_CMD_PORT_DEL
:
4422 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4423 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4424 !tb
[DEVLINK_ATTR_PORT_INDEX
])
4425 return MNL_CB_ERROR
;
4426 pr_out_mon_header(genl
->cmd
);
4427 pr_out_port(dl
, tb
);
4428 pr_out_mon_footer();
4430 case DEVLINK_CMD_PARAM_GET
: /* fall through */
4431 case DEVLINK_CMD_PARAM_SET
: /* fall through */
4432 case DEVLINK_CMD_PARAM_NEW
: /* fall through */
4433 case DEVLINK_CMD_PARAM_DEL
:
4434 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4435 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4436 !tb
[DEVLINK_ATTR_PARAM
])
4437 return MNL_CB_ERROR
;
4438 pr_out_mon_header(genl
->cmd
);
4439 pr_out_param(dl
, tb
, false);
4440 pr_out_mon_footer();
4442 case DEVLINK_CMD_REGION_GET
: /* fall through */
4443 case DEVLINK_CMD_REGION_SET
: /* fall through */
4444 case DEVLINK_CMD_REGION_NEW
: /* fall through */
4445 case DEVLINK_CMD_REGION_DEL
:
4446 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4447 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4448 !tb
[DEVLINK_ATTR_REGION_NAME
])
4449 return MNL_CB_ERROR
;
4450 pr_out_mon_header(genl
->cmd
);
4451 pr_out_region(dl
, tb
);
4452 pr_out_mon_footer();
4454 case DEVLINK_CMD_FLASH_UPDATE
: /* fall through */
4455 case DEVLINK_CMD_FLASH_UPDATE_END
: /* fall through */
4456 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4457 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4458 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4459 return MNL_CB_ERROR
;
4460 pr_out_mon_header(genl
->cmd
);
4461 pr_out_flash_update(dl
, tb
);
4462 pr_out_mon_footer();
4464 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4465 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4466 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4467 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
4468 return MNL_CB_ERROR
;
4469 pr_out_mon_header(genl
->cmd
);
4470 pr_out_health(dl
, tb
);
4471 pr_out_mon_footer();
4473 case DEVLINK_CMD_TRAP_GET
: /* fall through */
4474 case DEVLINK_CMD_TRAP_SET
: /* fall through */
4475 case DEVLINK_CMD_TRAP_NEW
: /* fall through */
4476 case DEVLINK_CMD_TRAP_DEL
:
4477 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4478 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4479 !tb
[DEVLINK_ATTR_TRAP_NAME
] ||
4480 !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
4481 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
4482 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4483 !tb
[DEVLINK_ATTR_TRAP_METADATA
] ||
4484 !tb
[DEVLINK_ATTR_STATS
])
4485 return MNL_CB_ERROR
;
4486 pr_out_mon_header(genl
->cmd
);
4487 pr_out_trap(dl
, tb
, false);
4488 pr_out_mon_footer();
4490 case DEVLINK_CMD_TRAP_GROUP_GET
: /* fall through */
4491 case DEVLINK_CMD_TRAP_GROUP_SET
: /* fall through */
4492 case DEVLINK_CMD_TRAP_GROUP_NEW
: /* fall through */
4493 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4494 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4495 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4496 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4497 !tb
[DEVLINK_ATTR_STATS
])
4498 return MNL_CB_ERROR
;
4499 pr_out_mon_header(genl
->cmd
);
4500 pr_out_trap_group(dl
, tb
, false);
4501 pr_out_mon_footer();
4503 case DEVLINK_CMD_TRAP_POLICER_GET
: /* fall through */
4504 case DEVLINK_CMD_TRAP_POLICER_SET
: /* fall through */
4505 case DEVLINK_CMD_TRAP_POLICER_NEW
: /* fall through */
4506 case DEVLINK_CMD_TRAP_POLICER_DEL
: /* fall through */
4507 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4508 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4509 !tb
[DEVLINK_ATTR_TRAP_POLICER_ID
] ||
4510 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
4511 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
4512 return MNL_CB_ERROR
;
4513 pr_out_mon_header(genl
->cmd
);
4514 pr_out_trap_policer(dl
, tb
, false);
4520 static int cmd_mon_show(struct dl
*dl
)
4523 unsigned int index
= 0;
4524 const char *cur_obj
;
4526 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4527 if (strcmp(cur_obj
, "all") != 0 &&
4528 strcmp(cur_obj
, "dev") != 0 &&
4529 strcmp(cur_obj
, "port") != 0 &&
4530 strcmp(cur_obj
, "health") != 0 &&
4531 strcmp(cur_obj
, "trap") != 0 &&
4532 strcmp(cur_obj
, "trap-group") != 0 &&
4533 strcmp(cur_obj
, "trap-policer") != 0) {
4534 pr_err("Unknown object \"%s\"\n", cur_obj
);
4538 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
4541 open_json_object(NULL
);
4542 open_json_array(PRINT_JSON
, "mon");
4543 err
= _mnlg_socket_recv_run_intr(dl
->nlg
, cmd_mon_show_cb
, dl
);
4544 close_json_array(PRINT_JSON
, NULL
);
4545 close_json_object();
4551 static void cmd_mon_help(void)
4553 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
4554 "where OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
4557 static int cmd_mon(struct dl
*dl
)
4559 if (dl_argv_match(dl
, "help")) {
4563 return cmd_mon_show(dl
);
4566 struct dpipe_field
{
4569 unsigned int bitwidth
;
4570 enum devlink_dpipe_field_mapping_type mapping_type
;
4573 struct dpipe_header
{
4574 struct list_head list
;
4577 struct dpipe_field
*fields
;
4578 unsigned int fields_count
;
4581 struct dpipe_table
{
4582 struct list_head list
;
4584 unsigned int resource_id
;
4585 bool resource_valid
;
4588 struct dpipe_tables
{
4589 struct list_head table_list
;
4599 enum devlink_resource_unit unit
;
4604 struct list_head list
;
4605 struct list_head resource_list
;
4606 struct resource
*parent
;
4610 struct list_head resource_list
;
4613 struct resource_ctx
{
4616 struct resources
*resources
;
4617 struct dpipe_tables
*tables
;
4618 bool print_resources
;
4619 bool pending_change
;
4622 static struct resource
*resource_alloc(void)
4624 struct resource
*resource
;
4626 resource
= calloc(1, sizeof(struct resource
));
4629 INIT_LIST_HEAD(&resource
->resource_list
);
4633 static void resource_free(struct resource
*resource
)
4635 struct resource
*child_resource
, *tmp
;
4637 list_for_each_entry_safe(child_resource
, tmp
, &resource
->resource_list
,
4639 free(child_resource
->name
);
4640 resource_free(child_resource
);
4645 static struct resources
*resources_alloc(void)
4647 struct resources
*resources
;
4649 resources
= calloc(1, sizeof(struct resources
));
4652 INIT_LIST_HEAD(&resources
->resource_list
);
4656 static void resources_free(struct resources
*resources
)
4658 struct resource
*resource
, *tmp
;
4660 list_for_each_entry_safe(resource
, tmp
, &resources
->resource_list
, list
)
4661 resource_free(resource
);
4664 static int resource_ctx_init(struct resource_ctx
*ctx
, struct dl
*dl
)
4666 ctx
->resources
= resources_alloc();
4667 if (!ctx
->resources
)
4673 static void resource_ctx_fini(struct resource_ctx
*ctx
)
4675 resources_free(ctx
->resources
);
4681 struct list_head global_headers
;
4682 struct list_head local_headers
;
4683 struct dpipe_tables
*tables
;
4684 struct resources
*resources
;
4689 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
4691 struct dpipe_header
*header
;
4693 header
= calloc(1, sizeof(struct dpipe_header
));
4696 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
4697 if (!header
->fields
)
4698 goto err_fields_alloc
;
4699 header
->fields_count
= fields_count
;
4707 static void dpipe_header_free(struct dpipe_header
*header
)
4709 free(header
->fields
);
4713 static void dpipe_header_clear(struct dpipe_header
*header
)
4715 struct dpipe_field
*field
;
4718 for (i
= 0; i
< header
->fields_count
; i
++) {
4719 field
= &header
->fields
[i
];
4725 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
4726 struct dpipe_header
*header
, bool global
)
4729 list_add(&header
->list
, &ctx
->global_headers
);
4731 list_add(&header
->list
, &ctx
->local_headers
);
4734 static void dpipe_header_del(struct dpipe_header
*header
)
4736 list_del(&header
->list
);
4739 static struct dpipe_table
*dpipe_table_alloc(void)
4741 return calloc(1, sizeof(struct dpipe_table
));
4744 static void dpipe_table_free(struct dpipe_table
*table
)
4749 static struct dpipe_tables
*dpipe_tables_alloc(void)
4751 struct dpipe_tables
*tables
;
4753 tables
= calloc(1, sizeof(struct dpipe_tables
));
4756 INIT_LIST_HEAD(&tables
->table_list
);
4760 static void dpipe_tables_free(struct dpipe_tables
*tables
)
4762 struct dpipe_table
*table
, *tmp
;
4764 list_for_each_entry_safe(table
, tmp
, &tables
->table_list
, list
)
4765 dpipe_table_free(table
);
4769 static int dpipe_ctx_init(struct dpipe_ctx
*ctx
, struct dl
*dl
)
4771 ctx
->tables
= dpipe_tables_alloc();
4776 INIT_LIST_HEAD(&ctx
->global_headers
);
4777 INIT_LIST_HEAD(&ctx
->local_headers
);
4781 static void dpipe_ctx_fini(struct dpipe_ctx
*ctx
)
4783 struct dpipe_header
*header
, *tmp
;
4785 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
4787 dpipe_header_del(header
);
4788 dpipe_header_clear(header
);
4789 dpipe_header_free(header
);
4791 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
4793 dpipe_header_del(header
);
4794 dpipe_header_clear(header
);
4795 dpipe_header_free(header
);
4797 dpipe_tables_free(ctx
->tables
);
4800 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
4801 uint32_t header_id
, bool global
)
4803 struct list_head
*header_list
;
4804 struct dpipe_header
*header
;
4807 header_list
= &ctx
->global_headers
;
4809 header_list
= &ctx
->local_headers
;
4810 list_for_each_entry(header
, header_list
, list
) {
4811 if (header
->id
!= header_id
)
4813 return header
->name
;
4818 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
4820 uint32_t field_id
, bool global
)
4822 struct list_head
*header_list
;
4823 struct dpipe_header
*header
;
4826 header_list
= &ctx
->global_headers
;
4828 header_list
= &ctx
->local_headers
;
4829 list_for_each_entry(header
, header_list
, list
) {
4830 if (header
->id
!= header_id
)
4832 return header
->fields
[field_id
].name
;
4838 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
4840 switch (mapping_type
) {
4841 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
4843 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
4851 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
4852 uint32_t field_id
, bool global
)
4854 enum devlink_dpipe_field_mapping_type mapping_type
;
4855 struct list_head
*header_list
;
4856 struct dpipe_header
*header
;
4859 header_list
= &ctx
->global_headers
;
4861 header_list
= &ctx
->local_headers
;
4862 list_for_each_entry(header
, header_list
, list
) {
4863 if (header
->id
!= header_id
)
4865 mapping_type
= header
->fields
[field_id
].mapping_type
;
4866 return dpipe_field_mapping_e2s(mapping_type
);
4871 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
4872 struct dpipe_field
*fields
,
4873 unsigned int field_count
)
4875 struct dpipe_field
*field
;
4878 for (i
= 0; i
< field_count
; i
++) {
4880 pr_out_entry_start(ctx
->dl
);
4881 check_indent_newline(ctx
->dl
);
4882 print_string(PRINT_ANY
, "name", "name %s", field
->name
);
4883 if (ctx
->dl
->verbose
)
4884 print_uint(PRINT_ANY
, "id", " id %u", field
->id
);
4885 print_uint(PRINT_ANY
, "bitwidth", " bitwidth %u", field
->bitwidth
);
4886 if (field
->mapping_type
) {
4887 print_string(PRINT_ANY
, "mapping_type", " mapping_type %s",
4888 dpipe_field_mapping_e2s(field
->mapping_type
));
4890 pr_out_entry_end(ctx
->dl
);
4895 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
4896 struct dpipe_header
*header
, bool global
)
4898 pr_out_handle_start_arr(ctx
->dl
, tb
);
4899 check_indent_newline(ctx
->dl
);
4900 print_string(PRINT_ANY
, "name", "name %s", header
->name
);
4901 if (ctx
->dl
->verbose
) {
4902 print_uint(PRINT_ANY
, "id", " id %u", header
->id
);
4903 print_bool(PRINT_ANY
, "global", " global %s", global
);
4905 pr_out_array_start(ctx
->dl
, "field");
4906 pr_out_dpipe_fields(ctx
, header
->fields
,
4907 header
->fields_count
);
4908 pr_out_array_end(ctx
->dl
);
4909 pr_out_handle_end(ctx
->dl
);
4912 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
4915 struct dpipe_header
*header
;
4917 list_for_each_entry(header
, &ctx
->local_headers
, list
)
4918 pr_out_dpipe_header(ctx
, tb
, header
, false);
4920 list_for_each_entry(header
, &ctx
->global_headers
, list
)
4921 pr_out_dpipe_header(ctx
, tb
, header
, true);
4924 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
4926 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
4930 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
4931 if (err
!= MNL_CB_OK
)
4933 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
4934 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
4935 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
4936 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
4939 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
4940 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4941 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
4942 field
->name
= strdup(name
);
4945 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
4949 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
4950 struct dpipe_field
*fields
)
4952 struct nlattr
*nla_field
;
4956 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
4957 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
4965 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
4967 struct nlattr
*nla_field
;
4968 unsigned int count
= 0;
4970 mnl_attr_for_each_nested(nla_field
, nla_fields
)
4975 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
4977 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
4978 struct dpipe_header
*header
;
4979 unsigned int fields_count
;
4980 const char *header_name
;
4984 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
4985 if (err
!= MNL_CB_OK
)
4988 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
4989 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4990 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
4993 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
4994 header
= dpipe_header_alloc(fields_count
);
4998 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
4999 header
->name
= strdup(header_name
);
5000 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5001 header
->fields_count
= fields_count
;
5002 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5004 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
5008 dpipe_header_add(ctx
, header
, global
);
5012 dpipe_header_free(header
);
5016 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5018 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
5019 struct nlattr
*nla_header
;
5022 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
5023 err
= dpipe_header_get(ctx
, nla_header
);
5030 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
5032 struct dpipe_ctx
*ctx
= data
;
5033 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5034 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5037 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5038 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5039 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
5040 return MNL_CB_ERROR
;
5041 err
= dpipe_headers_get(ctx
, tb
);
5044 return MNL_CB_ERROR
;
5047 if (ctx
->print_headers
)
5048 pr_out_dpipe_headers(ctx
, tb
);
5052 static int cmd_dpipe_headers_show(struct dl
*dl
)
5054 struct nlmsghdr
*nlh
;
5055 struct dpipe_ctx ctx
= {};
5056 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5059 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5061 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
5065 err
= dpipe_ctx_init(&ctx
, dl
);
5069 ctx
.print_headers
= true;
5071 pr_out_section_start(dl
, "header");
5072 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5074 pr_err("error get headers %s\n", strerror(ctx
.err
));
5075 pr_out_section_end(dl
);
5077 dpipe_ctx_fini(&ctx
);
5081 static void cmd_dpipe_help(void)
5083 pr_err("Usage: devlink dpipe table show DEV [ name TABLE_NAME ]\n");
5084 pr_err(" devlink dpipe table set DEV name TABLE_NAME\n");
5085 pr_err(" [ counters_enabled { true | false } ]\n");
5086 pr_err(" devlink dpipe table dump DEV name TABLE_NAME\n");
5087 pr_err(" devlink dpipe header show DEV\n");
5090 static int cmd_dpipe_header(struct dl
*dl
)
5092 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5095 } else if (dl_argv_match(dl
, "show")) {
5097 return cmd_dpipe_headers_show(dl
);
5099 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5104 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
5106 switch (action_type
) {
5107 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
5108 return "field_modify";
5114 struct dpipe_op_info
{
5120 struct dpipe_action
{
5121 struct dpipe_op_info info
;
5125 static void pr_out_dpipe_action(struct dpipe_action
*action
,
5126 struct dpipe_ctx
*ctx
)
5128 struct dpipe_op_info
*op_info
= &action
->info
;
5129 const char *mapping
;
5131 check_indent_newline(ctx
->dl
);
5132 print_string(PRINT_ANY
, "type", "type %s",
5133 dpipe_action_type_e2s(action
->type
));
5134 print_string(PRINT_ANY
, "header", " header %s",
5135 dpipe_header_id2s(ctx
, op_info
->header_id
,
5136 op_info
->header_global
));
5137 print_string(PRINT_ANY
, "field", " field %s",
5138 dpipe_field_id2s(ctx
, op_info
->header_id
,
5140 op_info
->header_global
));
5141 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5143 op_info
->header_global
);
5145 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5148 static int dpipe_action_parse(struct dpipe_action
*action
, struct nlattr
*nl
)
5150 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
5153 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
5154 if (err
!= MNL_CB_OK
)
5157 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
5158 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5159 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5160 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5164 action
->type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
5165 action
->info
.header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5166 action
->info
.field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5167 action
->info
.header_global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5172 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
5173 struct nlattr
*nla_actions
)
5175 struct nlattr
*nla_action
;
5176 struct dpipe_action action
;
5178 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
5179 pr_out_entry_start(ctx
->dl
);
5180 if (dpipe_action_parse(&action
, nla_action
))
5181 goto err_action_parse
;
5182 pr_out_dpipe_action(&action
, ctx
);
5183 pr_out_entry_end(ctx
->dl
);
5188 pr_out_entry_end(ctx
->dl
);
5193 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
5195 switch (match_type
) {
5196 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
5197 return "field_exact";
5203 struct dpipe_match
{
5204 struct dpipe_op_info info
;
5208 static void pr_out_dpipe_match(struct dpipe_match
*match
,
5209 struct dpipe_ctx
*ctx
)
5211 struct dpipe_op_info
*op_info
= &match
->info
;
5212 const char *mapping
;
5214 check_indent_newline(ctx
->dl
);
5215 print_string(PRINT_ANY
, "type", "type %s",
5216 dpipe_match_type_e2s(match
->type
));
5217 print_string(PRINT_ANY
, "header", " header %s",
5218 dpipe_header_id2s(ctx
, op_info
->header_id
,
5219 op_info
->header_global
));
5220 print_string(PRINT_ANY
, "field", " field %s",
5221 dpipe_field_id2s(ctx
, op_info
->header_id
,
5223 op_info
->header_global
));
5224 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5226 op_info
->header_global
);
5228 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5231 static int dpipe_match_parse(struct dpipe_match
*match
,
5235 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
5238 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
5239 if (err
!= MNL_CB_OK
)
5242 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
5243 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5244 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5245 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5249 match
->type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
5250 match
->info
.header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5251 match
->info
.field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5252 match
->info
.header_global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5257 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
5258 struct nlattr
*nla_matches
)
5260 struct nlattr
*nla_match
;
5261 struct dpipe_match match
;
5263 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
5264 pr_out_entry_start(ctx
->dl
);
5265 if (dpipe_match_parse(&match
, nla_match
))
5266 goto err_match_parse
;
5267 pr_out_dpipe_match(&match
, ctx
);
5268 pr_out_entry_end(ctx
->dl
);
5273 pr_out_entry_end(ctx
->dl
);
5277 static struct resource
*
5278 resource_find(struct resources
*resources
, struct resource
*resource
,
5279 uint64_t resource_id
)
5281 struct list_head
*list_head
;
5284 list_head
= &resources
->resource_list
;
5286 list_head
= &resource
->resource_list
;
5288 list_for_each_entry(resource
, list_head
, list
) {
5289 struct resource
*child_resource
;
5291 if (resource
->id
== resource_id
)
5294 child_resource
= resource_find(resources
, resource
,
5297 return child_resource
;
5303 resource_path_print(struct dl
*dl
, struct resources
*resources
,
5304 uint64_t resource_id
)
5306 struct resource
*resource
, *parent_resource
;
5307 const char del
[] = "/";
5311 resource
= resource_find(resources
, NULL
, resource_id
);
5315 for (parent_resource
= resource
; parent_resource
;
5316 parent_resource
= parent_resource
->parent
)
5317 path_len
+= strlen(parent_resource
->name
) + 1;
5320 path
= calloc(1, path_len
);
5324 path
+= path_len
- 1;
5325 for (parent_resource
= resource
; parent_resource
;
5326 parent_resource
= parent_resource
->parent
) {
5327 path
-= strlen(parent_resource
->name
);
5328 memcpy(path
, parent_resource
->name
,
5329 strlen(parent_resource
->name
));
5330 path
-= strlen(del
);
5331 memcpy(path
, del
, strlen(del
));
5333 check_indent_newline(dl
);
5334 print_string(PRINT_ANY
, "resource_path", "resource_path %s", path
);
5338 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5340 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
5341 struct dpipe_table
*table
;
5342 uint32_t resource_units
;
5343 bool counters_enabled
;
5344 bool resource_valid
;
5348 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
5349 if (err
!= MNL_CB_OK
)
5352 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
5353 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
5354 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
5355 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
5356 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
5360 table
= dpipe_table_alloc();
5364 table
->name
= strdup(mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]));
5365 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
5366 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
5368 resource_valid
= nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
] &&
5370 if (resource_valid
) {
5371 table
->resource_id
= mnl_attr_get_u64(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
]);
5372 table
->resource_valid
= true;
5375 list_add_tail(&table
->list
, &ctx
->tables
->table_list
);
5376 if (!ctx
->print_tables
)
5379 check_indent_newline(ctx
->dl
);
5380 print_string(PRINT_ANY
, "name", "name %s", table
->name
);
5381 print_uint(PRINT_ANY
, "size", " size %u", size
);
5382 print_bool(PRINT_ANY
, "counters_enabled", " counters_enabled %s", counters_enabled
);
5384 if (resource_valid
) {
5385 resource_units
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS
]);
5386 resource_path_print(ctx
->dl
, ctx
->resources
,
5387 table
->resource_id
);
5388 print_uint(PRINT_ANY
, "resource_units", " resource_units %u",
5392 pr_out_array_start(ctx
->dl
, "match");
5393 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
5394 goto err_matches_show
;
5395 pr_out_array_end(ctx
->dl
);
5397 pr_out_array_start(ctx
->dl
, "action");
5398 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
5399 goto err_actions_show
;
5400 pr_out_array_end(ctx
->dl
);
5406 pr_out_array_end(ctx
->dl
);
5410 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5412 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
5413 struct nlattr
*nla_table
;
5415 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
5416 if (ctx
->print_tables
)
5417 pr_out_handle_start_arr(ctx
->dl
, tb
);
5418 if (dpipe_table_show(ctx
, nla_table
))
5419 goto err_table_show
;
5420 if (ctx
->print_tables
)
5421 pr_out_handle_end(ctx
->dl
);
5426 if (ctx
->print_tables
)
5427 pr_out_handle_end(ctx
->dl
);
5431 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5433 struct dpipe_ctx
*ctx
= data
;
5434 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5435 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5437 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5438 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5439 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
5440 return MNL_CB_ERROR
;
5442 if (dpipe_tables_show(ctx
, tb
))
5443 return MNL_CB_ERROR
;
5447 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
);
5449 static int cmd_dpipe_table_show(struct dl
*dl
)
5451 struct nlmsghdr
*nlh
;
5452 struct dpipe_ctx dpipe_ctx
= {};
5453 struct resource_ctx resource_ctx
= {};
5454 uint16_t flags
= NLM_F_REQUEST
;
5457 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
5461 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5463 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5467 dpipe_ctx
.print_tables
= true;
5469 dl_opts_put(nlh
, dl
);
5470 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
,
5473 pr_err("error get headers %s\n", strerror(dpipe_ctx
.err
));
5474 goto err_headers_get
;
5477 err
= resource_ctx_init(&resource_ctx
, dl
);
5479 goto err_resource_ctx_init
;
5481 resource_ctx
.print_resources
= false;
5482 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
, flags
);
5483 dl_opts_put(nlh
, dl
);
5484 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
5487 dpipe_ctx
.resources
= resource_ctx
.resources
;
5489 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5490 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
5491 dl_opts_put(nlh
, dl
);
5493 pr_out_section_start(dl
, "table");
5494 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, &dpipe_ctx
);
5495 pr_out_section_end(dl
);
5497 resource_ctx_fini(&resource_ctx
);
5498 dpipe_ctx_fini(&dpipe_ctx
);
5501 err_resource_ctx_init
:
5503 dpipe_ctx_fini(&dpipe_ctx
);
5507 static int cmd_dpipe_table_set(struct dl
*dl
)
5509 struct nlmsghdr
*nlh
;
5512 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
5513 NLM_F_REQUEST
| NLM_F_ACK
);
5515 err
= dl_argv_parse_put(nlh
, dl
,
5516 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
5517 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
5521 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5524 enum dpipe_value_type
{
5525 DPIPE_VALUE_TYPE_VALUE
,
5526 DPIPE_VALUE_TYPE_MASK
,
5530 dpipe_value_type_e2s(enum dpipe_value_type type
)
5533 case DPIPE_VALUE_TYPE_VALUE
:
5535 case DPIPE_VALUE_TYPE_MASK
:
5536 return "value_mask";
5542 struct dpipe_field_printer
{
5543 unsigned int field_id
;
5544 void (*printer
)(struct dpipe_ctx
*, enum dpipe_value_type
, void *);
5547 struct dpipe_header_printer
{
5548 struct dpipe_field_printer
*printers
;
5549 unsigned int printers_count
;
5550 unsigned int header_id
;
5553 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx
*ctx
,
5554 enum dpipe_value_type type
,
5557 struct in_addr ip_addr
;
5559 ip_addr
.s_addr
= htonl(*(uint32_t *)value
);
5560 check_indent_newline(ctx
->dl
);
5561 print_string_name_value(dpipe_value_type_e2s(type
), inet_ntoa(ip_addr
));
5565 dpipe_field_printer_ethernet_addr(struct dpipe_ctx
*ctx
,
5566 enum dpipe_value_type type
,
5569 check_indent_newline(ctx
->dl
);
5570 print_string_name_value(dpipe_value_type_e2s(type
),
5571 ether_ntoa((struct ether_addr
*)value
));
5574 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx
*ctx
,
5575 enum dpipe_value_type type
,
5578 char str
[INET6_ADDRSTRLEN
];
5580 inet_ntop(AF_INET6
, value
, str
, INET6_ADDRSTRLEN
);
5581 check_indent_newline(ctx
->dl
);
5582 print_string_name_value(dpipe_value_type_e2s(type
), str
);
5585 static struct dpipe_field_printer dpipe_field_printers_ipv4
[] = {
5587 .printer
= dpipe_field_printer_ipv4_addr
,
5588 .field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
,
5592 static struct dpipe_header_printer dpipe_header_printer_ipv4
= {
5593 .printers
= dpipe_field_printers_ipv4
,
5594 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv4
),
5595 .header_id
= DEVLINK_DPIPE_HEADER_IPV4
,
5598 static struct dpipe_field_printer dpipe_field_printers_ethernet
[] = {
5600 .printer
= dpipe_field_printer_ethernet_addr
,
5601 .field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
,
5605 static struct dpipe_header_printer dpipe_header_printer_ethernet
= {
5606 .printers
= dpipe_field_printers_ethernet
,
5607 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ethernet
),
5608 .header_id
= DEVLINK_DPIPE_HEADER_ETHERNET
,
5611 static struct dpipe_field_printer dpipe_field_printers_ipv6
[] = {
5613 .printer
= dpipe_field_printer_ipv6_addr
,
5614 .field_id
= DEVLINK_DPIPE_FIELD_IPV6_DST_IP
,
5618 static struct dpipe_header_printer dpipe_header_printer_ipv6
= {
5619 .printers
= dpipe_field_printers_ipv6
,
5620 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv6
),
5621 .header_id
= DEVLINK_DPIPE_HEADER_IPV6
,
5624 static struct dpipe_header_printer
*dpipe_header_printers
[] = {
5625 &dpipe_header_printer_ipv4
,
5626 &dpipe_header_printer_ethernet
,
5627 &dpipe_header_printer_ipv6
,
5630 static int dpipe_print_prot_header(struct dpipe_ctx
*ctx
,
5631 struct dpipe_op_info
*info
,
5632 enum dpipe_value_type type
,
5635 unsigned int header_printers_count
= ARRAY_SIZE(dpipe_header_printers
);
5636 struct dpipe_header_printer
*header_printer
;
5637 struct dpipe_field_printer
*field_printer
;
5638 unsigned int field_printers_count
;
5642 for (i
= 0; i
< header_printers_count
; i
++) {
5643 header_printer
= dpipe_header_printers
[i
];
5644 if (header_printer
->header_id
!= info
->header_id
)
5646 field_printers_count
= header_printer
->printers_count
;
5647 for (j
= 0; j
< field_printers_count
; j
++) {
5648 field_printer
= &header_printer
->printers
[j
];
5649 if (field_printer
->field_id
!= info
->field_id
)
5651 field_printer
->printer(ctx
, type
, value
);
5659 static void __pr_out_entry_value(struct dpipe_ctx
*ctx
,
5661 unsigned int value_len
,
5662 struct dpipe_op_info
*info
,
5663 enum dpipe_value_type type
)
5665 if (info
->header_global
&&
5666 !dpipe_print_prot_header(ctx
, info
, type
, value
))
5669 if (value_len
== sizeof(uint32_t)) {
5670 uint32_t *value_32
= value
;
5672 check_indent_newline(ctx
->dl
);
5673 print_uint_name_value(dpipe_value_type_e2s(type
), *value_32
);
5677 static void pr_out_dpipe_entry_value(struct dpipe_ctx
*ctx
,
5678 struct nlattr
**nla_match_value
,
5679 struct dpipe_op_info
*info
)
5681 void *value
, *value_mask
;
5682 uint32_t value_mapping
;
5686 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
5687 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
5689 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5690 value
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5693 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
5694 check_indent_newline(ctx
->dl
);
5695 print_uint(PRINT_ANY
, "mapping_value", "mapping_value %u", value_mapping
);
5699 value_mask
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5700 __pr_out_entry_value(ctx
, value_mask
, value_len
, info
,
5701 DPIPE_VALUE_TYPE_MASK
);
5704 __pr_out_entry_value(ctx
, value
, value_len
, info
, DPIPE_VALUE_TYPE_VALUE
);
5707 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
5710 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5711 struct dpipe_match match
;
5714 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
5715 if (err
!= MNL_CB_OK
)
5718 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
5719 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5723 pr_out_entry_start(ctx
->dl
);
5724 if (dpipe_match_parse(&match
,
5725 nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
5726 goto err_match_parse
;
5727 pr_out_dpipe_match(&match
, ctx
);
5728 pr_out_dpipe_entry_value(ctx
, nla_match_value
, &match
.info
);
5729 pr_out_entry_end(ctx
->dl
);
5734 pr_out_entry_end(ctx
->dl
);
5738 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
5741 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5742 struct dpipe_action action
;
5745 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
5746 if (err
!= MNL_CB_OK
)
5749 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
5750 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5754 pr_out_entry_start(ctx
->dl
);
5755 if (dpipe_action_parse(&action
,
5756 nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
5757 goto err_action_parse
;
5758 pr_out_dpipe_action(&action
, ctx
);
5759 pr_out_dpipe_entry_value(ctx
, nla_action_value
, &action
.info
);
5760 pr_out_entry_end(ctx
->dl
);
5765 pr_out_entry_end(ctx
->dl
);
5770 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
5771 struct nlattr
*nla_action_values
)
5773 struct nlattr
*nla_action_value
;
5775 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
5776 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
5783 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
5784 struct nlattr
*nla_match_values
)
5786 struct nlattr
*nla_match_value
;
5788 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
5789 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
5795 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5797 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
5798 uint32_t entry_index
;
5802 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
5803 if (err
!= MNL_CB_OK
)
5806 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
5807 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
5808 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
5812 check_indent_newline(ctx
->dl
);
5813 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
5814 print_uint(PRINT_ANY
, "index", "index %u", entry_index
);
5816 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
5817 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
5818 print_uint(PRINT_ANY
, "counter", " counter %u", counter
);
5821 pr_out_array_start(ctx
->dl
, "match_value");
5822 if (dpipe_tables_match_values_show(ctx
,
5823 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
5824 goto err_match_values_show
;
5825 pr_out_array_end(ctx
->dl
);
5827 pr_out_array_start(ctx
->dl
, "action_value");
5828 if (dpipe_tables_action_values_show(ctx
,
5829 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
5830 goto err_action_values_show
;
5831 pr_out_array_end(ctx
->dl
);
5834 err_action_values_show
:
5835 err_match_values_show
:
5836 pr_out_array_end(ctx
->dl
);
5840 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5842 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
5843 struct nlattr
*nla_entry
;
5845 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
5846 pr_out_handle_start_arr(ctx
->dl
, tb
);
5847 if (dpipe_entry_show(ctx
, nla_entry
))
5848 goto err_entry_show
;
5849 pr_out_handle_end(ctx
->dl
);
5854 pr_out_handle_end(ctx
->dl
);
5858 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5860 struct dpipe_ctx
*ctx
= data
;
5861 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5862 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5864 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5865 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5866 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
5867 return MNL_CB_ERROR
;
5869 if (dpipe_table_entries_show(ctx
, tb
))
5870 return MNL_CB_ERROR
;
5874 static int cmd_dpipe_table_dump(struct dl
*dl
)
5876 struct nlmsghdr
*nlh
;
5877 struct dpipe_ctx ctx
= {};
5878 uint16_t flags
= NLM_F_REQUEST
;
5881 err
= dpipe_ctx_init(&ctx
, dl
);
5885 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
5889 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5890 dl_opts_put(nlh
, dl
);
5891 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5893 pr_err("error get headers %s\n", strerror(ctx
.err
));
5897 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5898 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
5899 dl_opts_put(nlh
, dl
);
5901 pr_out_section_start(dl
, "table_entry");
5902 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, &ctx
);
5903 pr_out_section_end(dl
);
5905 dpipe_ctx_fini(&ctx
);
5909 static int cmd_dpipe_table(struct dl
*dl
)
5911 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5914 } else if (dl_argv_match(dl
, "show")) {
5916 return cmd_dpipe_table_show(dl
);
5917 } else if (dl_argv_match(dl
, "set")) {
5919 return cmd_dpipe_table_set(dl
);
5920 } else if (dl_argv_match(dl
, "dump")) {
5922 return cmd_dpipe_table_dump(dl
);
5924 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5928 static int cmd_dpipe(struct dl
*dl
)
5930 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5933 } else if (dl_argv_match(dl
, "header")) {
5935 return cmd_dpipe_header(dl
);
5936 } else if (dl_argv_match(dl
, "table")) {
5938 return cmd_dpipe_table(dl
);
5940 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5945 resource_parse(struct resource_ctx
*ctx
, struct resource
*resource
,
5946 struct nlattr
**nla_resource
)
5948 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
] ||
5949 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
] ||
5950 !nla_resource
[DEVLINK_ATTR_RESOURCE_ID
] ||
5951 !nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
] ||
5952 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
] ||
5953 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
] ||
5954 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]) {
5958 resource
->name
= strdup(mnl_attr_get_str(nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
]));
5959 resource
->size
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
]);
5960 resource
->id
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_ID
]);
5961 resource
->unit
= mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
]);
5962 resource
->size_min
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
]);
5963 resource
->size_max
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
]);
5964 resource
->size_gran
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]);
5966 if (nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
])
5967 resource
->size_new
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
]);
5969 resource
->size_new
= resource
->size
;
5971 if (nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]) {
5972 resource
->size_occ
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]);
5973 resource
->occ_valid
= true;
5976 if (resource
->size_new
!= resource
->size
)
5977 ctx
->pending_change
= true;
5983 resource_get(struct resource_ctx
*ctx
, struct resource
*resource
,
5984 struct resource
*parent_resource
, struct nlattr
*nl
)
5986 struct nlattr
*nla_resource
[DEVLINK_ATTR_MAX
+ 1] = {};
5987 struct nlattr
*nla_child_resource
;
5988 struct nlattr
*nla_resources
;
5998 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_resource
);
5999 if (err
!= MNL_CB_OK
)
6002 err
= resource_parse(ctx
, resource
, nla_resource
);
6006 resource
->parent
= parent_resource
;
6007 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
])
6010 resource
->size_valid
= !!mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_VALID
]);
6011 nla_resources
= nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
];
6013 mnl_attr_for_each_nested(nla_child_resource
, nla_resources
) {
6014 struct resource
*child_resource
;
6015 struct list_head
*list
;
6017 child_resource
= resource_alloc();
6018 if (!child_resource
)
6022 list
= &ctx
->resources
->resource_list
;
6024 list
= &resource
->resource_list
;
6026 list_add_tail(&child_resource
->list
, list
);
6027 err
= resource_get(ctx
, child_resource
, resource
,
6028 nla_child_resource
);
6036 static const char *resource_unit_str_get(enum devlink_resource_unit unit
)
6039 case DEVLINK_RESOURCE_UNIT_ENTRY
: return "entry";
6040 default: return "<unknown unit>";
6044 static void resource_show(struct resource
*resource
,
6045 struct resource_ctx
*ctx
)
6047 struct resource
*child_resource
;
6048 struct dpipe_table
*table
;
6049 struct dl
*dl
= ctx
->dl
;
6052 check_indent_newline(dl
);
6053 print_string(PRINT_ANY
, "name", "name %s", resource
->name
);
6055 resource_path_print(dl
, ctx
->resources
, resource
->id
);
6056 pr_out_u64(dl
, "size", resource
->size
);
6057 if (resource
->size
!= resource
->size_new
)
6058 pr_out_u64(dl
, "size_new", resource
->size_new
);
6059 if (resource
->occ_valid
)
6060 print_uint(PRINT_ANY
, "occ", " occ %u", resource
->size_occ
);
6061 print_string(PRINT_ANY
, "unit", " unit %s",
6062 resource_unit_str_get(resource
->unit
));
6064 if (resource
->size_min
!= resource
->size_max
) {
6065 print_uint(PRINT_ANY
, "size_min", " size_min %u",
6066 resource
->size_min
);
6067 pr_out_u64(dl
, "size_max", resource
->size_max
);
6068 print_uint(PRINT_ANY
, "size_gran", " size_gran %u",
6069 resource
->size_gran
);
6072 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
)
6073 if (table
->resource_id
== resource
->id
&&
6074 table
->resource_valid
)
6078 pr_out_array_start(dl
, "dpipe_tables");
6080 print_string(PRINT_ANY
, "dpipe_tables", " dpipe_tables none",
6083 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
) {
6084 if (table
->resource_id
!= resource
->id
||
6085 !table
->resource_valid
)
6087 pr_out_entry_start(dl
);
6088 check_indent_newline(dl
);
6089 print_string(PRINT_ANY
, "table_name", "table_name %s",
6091 pr_out_entry_end(dl
);
6094 pr_out_array_end(dl
);
6096 if (list_empty(&resource
->resource_list
))
6099 if (ctx
->pending_change
) {
6100 check_indent_newline(dl
);
6101 print_string(PRINT_ANY
, "size_valid", "size_valid %s",
6102 resource
->size_valid
? "true" : "false");
6104 pr_out_array_start(dl
, "resources");
6105 list_for_each_entry(child_resource
, &resource
->resource_list
, list
) {
6106 pr_out_entry_start(dl
);
6107 resource_show(child_resource
, ctx
);
6108 pr_out_entry_end(dl
);
6110 pr_out_array_end(dl
);
6114 resources_show(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6116 struct resources
*resources
= ctx
->resources
;
6117 struct resource
*resource
;
6119 list_for_each_entry(resource
, &resources
->resource_list
, list
) {
6120 pr_out_handle_start_arr(ctx
->dl
, tb
);
6121 resource_show(resource
, ctx
);
6122 pr_out_handle_end(ctx
->dl
);
6126 static int resources_get(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6128 return resource_get(ctx
, NULL
, NULL
, tb
[DEVLINK_ATTR_RESOURCE_LIST
]);
6131 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
6133 struct resource_ctx
*ctx
= data
;
6134 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6135 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6138 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6139 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6140 !tb
[DEVLINK_ATTR_RESOURCE_LIST
])
6141 return MNL_CB_ERROR
;
6143 err
= resources_get(ctx
, tb
);
6146 return MNL_CB_ERROR
;
6149 if (ctx
->print_resources
)
6150 resources_show(ctx
, tb
);
6155 static int cmd_resource_show(struct dl
*dl
)
6157 struct nlmsghdr
*nlh
;
6158 struct dpipe_ctx dpipe_ctx
= {};
6159 struct resource_ctx resource_ctx
= {};
6162 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, 0);
6166 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
,
6168 dl_opts_put(nlh
, dl
);
6170 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
6174 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
,
6177 pr_err("error get tables %s\n", strerror(dpipe_ctx
.err
));
6181 err
= resource_ctx_init(&resource_ctx
, dl
);
6185 resource_ctx
.print_resources
= true;
6186 resource_ctx
.tables
= dpipe_ctx
.tables
;
6187 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6188 NLM_F_REQUEST
| NLM_F_ACK
);
6189 dl_opts_put(nlh
, dl
);
6190 pr_out_section_start(dl
, "resources");
6191 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
6193 pr_out_section_end(dl
);
6194 resource_ctx_fini(&resource_ctx
);
6196 dpipe_ctx_fini(&dpipe_ctx
);
6200 static void cmd_resource_help(void)
6202 pr_err("Usage: devlink resource show DEV\n"
6203 " devlink resource set DEV path PATH size SIZE\n");
6206 static struct resource
*
6207 resource_find_by_name(struct list_head
*list
, char *name
)
6209 struct resource
*resource
;
6211 list_for_each_entry(resource
, list
, list
) {
6212 if (!strcmp(resource
->name
, name
))
6219 resource_path_parse(struct resource_ctx
*ctx
, const char *resource_path
,
6220 uint32_t *p_resource_id
, bool *p_resource_valid
)
6222 struct resource
*resource
;
6223 uint32_t resource_id
= 0;
6224 char *resource_path_dup
;
6225 struct list_head
*list
;
6226 const char del
[] = "/";
6227 char *resource_name
;
6229 resource_path_dup
= strdup(resource_path
);
6230 list
= &ctx
->resources
->resource_list
;
6231 resource_name
= strtok(resource_path_dup
, del
);
6232 while (resource_name
!= NULL
) {
6233 resource
= resource_find_by_name(list
, resource_name
);
6235 goto err_resource_lookup
;
6237 list
= &resource
->resource_list
;
6238 resource_name
= strtok(NULL
, del
);
6239 resource_id
= resource
->id
;
6241 free(resource_path_dup
);
6242 *p_resource_valid
= true;
6243 *p_resource_id
= resource_id
;
6246 err_resource_lookup
:
6247 free(resource_path_dup
);
6251 static int cmd_resource_set(struct dl
*dl
)
6253 struct nlmsghdr
*nlh
;
6254 struct resource_ctx ctx
= {};
6257 err
= resource_ctx_init(&ctx
, dl
);
6261 ctx
.print_resources
= false;
6262 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_RESOURCE_PATH
|
6263 DL_OPT_RESOURCE_SIZE
, 0);
6267 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6269 dl_opts_put(nlh
, dl
);
6270 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
, &ctx
);
6272 pr_err("error getting resources %s\n", strerror(ctx
.err
));
6276 err
= resource_path_parse(&ctx
, dl
->opts
.resource_path
,
6277 &dl
->opts
.resource_id
,
6278 &dl
->opts
.resource_id_valid
);
6280 pr_err("error parsing resource path %s\n", strerror(-err
));
6284 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_SET
,
6285 NLM_F_REQUEST
| NLM_F_ACK
);
6287 dl_opts_put(nlh
, dl
);
6288 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6290 resource_ctx_fini(&ctx
);
6294 static int cmd_resource(struct dl
*dl
)
6296 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6297 cmd_resource_help();
6299 } else if (dl_argv_match(dl
, "show")) {
6301 return cmd_resource_show(dl
);
6302 } else if (dl_argv_match(dl
, "set")) {
6304 return cmd_resource_set(dl
);
6306 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6310 static void pr_out_region_handle_start(struct dl
*dl
, struct nlattr
**tb
)
6312 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
6313 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
6314 const char *region_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_REGION_NAME
]);
6317 sprintf(buf
, "%s/%s/%s", bus_name
, dev_name
, region_name
);
6318 if (dl
->json_output
)
6319 open_json_object(buf
);
6324 static void pr_out_region_handle_end(struct dl
*dl
)
6326 if (dl
->json_output
)
6327 close_json_object();
6332 static void pr_out_region_snapshots_start(struct dl
*dl
, bool array
)
6334 __pr_out_indent_newline(dl
);
6335 if (dl
->json_output
)
6336 open_json_array(PRINT_JSON
, "snapshot");
6338 pr_out("snapshot %s", array
? "[" : "");
6341 static void pr_out_region_snapshots_end(struct dl
*dl
, bool array
)
6343 if (dl
->json_output
)
6344 close_json_array(PRINT_JSON
, NULL
);
6349 static void pr_out_region_snapshots_id(struct dl
*dl
, struct nlattr
**tb
, int index
)
6351 uint32_t snapshot_id
;
6353 if (!tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6356 snapshot_id
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
]);
6358 if (dl
->json_output
)
6359 print_uint(PRINT_JSON
, NULL
, NULL
, snapshot_id
);
6361 pr_out("%s%u", index
? " " : "", snapshot_id
);
6364 static void pr_out_snapshots(struct dl
*dl
, struct nlattr
**tb
)
6366 struct nlattr
*tb_snapshot
[DEVLINK_ATTR_MAX
+ 1] = {};
6367 struct nlattr
*nla_sanpshot
;
6370 pr_out_region_snapshots_start(dl
, true);
6371 mnl_attr_for_each_nested(nla_sanpshot
, tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
]) {
6372 err
= mnl_attr_parse_nested(nla_sanpshot
, attr_cb
, tb_snapshot
);
6373 if (err
!= MNL_CB_OK
)
6375 pr_out_region_snapshots_id(dl
, tb_snapshot
, index
++);
6377 pr_out_region_snapshots_end(dl
, true);
6380 static void pr_out_snapshot(struct dl
*dl
, struct nlattr
**tb
)
6382 pr_out_region_snapshots_start(dl
, false);
6383 pr_out_region_snapshots_id(dl
, tb
, 0);
6384 pr_out_region_snapshots_end(dl
, false);
6387 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
)
6389 pr_out_region_handle_start(dl
, tb
);
6391 if (tb
[DEVLINK_ATTR_REGION_SIZE
])
6392 pr_out_u64(dl
, "size",
6393 mnl_attr_get_u64(tb
[DEVLINK_ATTR_REGION_SIZE
]));
6395 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
])
6396 pr_out_snapshots(dl
, tb
);
6398 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6399 pr_out_snapshot(dl
, tb
);
6401 pr_out_region_handle_end(dl
);
6404 static int cmd_region_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6406 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6407 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6408 struct dl
*dl
= data
;
6410 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6411 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6412 !tb
[DEVLINK_ATTR_REGION_NAME
] || !tb
[DEVLINK_ATTR_REGION_SIZE
])
6413 return MNL_CB_ERROR
;
6415 pr_out_region(dl
, tb
);
6420 static int cmd_region_show(struct dl
*dl
)
6422 struct nlmsghdr
*nlh
;
6423 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6426 if (dl_argc(dl
) == 0)
6427 flags
|= NLM_F_DUMP
;
6429 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_GET
, flags
);
6431 if (dl_argc(dl
) > 0) {
6432 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
, 0);
6437 pr_out_section_start(dl
, "regions");
6438 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_show_cb
, dl
);
6439 pr_out_section_end(dl
);
6443 static int cmd_region_snapshot_del(struct dl
*dl
)
6445 struct nlmsghdr
*nlh
;
6448 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_DEL
,
6449 NLM_F_REQUEST
| NLM_F_ACK
);
6451 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6452 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6456 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6459 static int cmd_region_read_cb(const struct nlmsghdr
*nlh
, void *data
)
6461 struct nlattr
*nla_entry
, *nla_chunk_data
, *nla_chunk_addr
;
6462 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6463 struct nlattr
*tb_field
[DEVLINK_ATTR_MAX
+ 1] = {};
6464 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6465 struct dl
*dl
= data
;
6468 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6469 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6470 !tb
[DEVLINK_ATTR_REGION_CHUNKS
])
6471 return MNL_CB_ERROR
;
6473 mnl_attr_for_each_nested(nla_entry
, tb
[DEVLINK_ATTR_REGION_CHUNKS
]) {
6474 err
= mnl_attr_parse_nested(nla_entry
, attr_cb
, tb_field
);
6475 if (err
!= MNL_CB_OK
)
6476 return MNL_CB_ERROR
;
6478 nla_chunk_data
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_DATA
];
6479 if (!nla_chunk_data
)
6482 nla_chunk_addr
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_ADDR
];
6483 if (!nla_chunk_addr
)
6486 pr_out_region_chunk(dl
, mnl_attr_get_payload(nla_chunk_data
),
6487 mnl_attr_get_payload_len(nla_chunk_data
),
6488 mnl_attr_get_u64(nla_chunk_addr
));
6493 static int cmd_region_dump(struct dl
*dl
)
6495 struct nlmsghdr
*nlh
;
6498 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6499 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6501 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6502 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6506 pr_out_section_start(dl
, "dump");
6507 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6508 pr_out_section_end(dl
);
6509 if (!dl
->json_output
)
6514 static int cmd_region_read(struct dl
*dl
)
6516 struct nlmsghdr
*nlh
;
6519 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6520 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6522 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6523 DL_OPT_REGION_ADDRESS
| DL_OPT_REGION_LENGTH
|
6524 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6528 pr_out_section_start(dl
, "read");
6529 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6530 pr_out_section_end(dl
);
6531 if (!dl
->json_output
)
6536 static int cmd_region_snapshot_new_cb(const struct nlmsghdr
*nlh
, void *data
)
6538 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6539 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6540 struct dl
*dl
= data
;
6542 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6543 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6544 !tb
[DEVLINK_ATTR_REGION_NAME
] ||
6545 !tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6546 return MNL_CB_ERROR
;
6548 pr_out_region(dl
, tb
);
6553 static int cmd_region_snapshot_new(struct dl
*dl
)
6555 struct nlmsghdr
*nlh
;
6558 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_NEW
,
6559 NLM_F_REQUEST
| NLM_F_ACK
);
6561 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
,
6562 DL_OPT_REGION_SNAPSHOT_ID
);
6566 pr_out_section_start(dl
, "regions");
6567 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_snapshot_new_cb
, dl
);
6568 pr_out_section_end(dl
);
6572 static void cmd_region_help(void)
6574 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
6575 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
6576 pr_err(" devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
6577 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
6578 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
6581 static int cmd_region(struct dl
*dl
)
6583 if (dl_no_arg(dl
)) {
6584 return cmd_region_show(dl
);
6585 } else if (dl_argv_match(dl
, "help")) {
6588 } else if (dl_argv_match(dl
, "show")) {
6590 return cmd_region_show(dl
);
6591 } else if (dl_argv_match(dl
, "del")) {
6593 return cmd_region_snapshot_del(dl
);
6594 } else if (dl_argv_match(dl
, "dump")) {
6596 return cmd_region_dump(dl
);
6597 } else if (dl_argv_match(dl
, "read")) {
6599 return cmd_region_read(dl
);
6600 } else if (dl_argv_match(dl
, "new")) {
6602 return cmd_region_snapshot_new(dl
);
6604 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6608 static int cmd_health_set_params(struct dl
*dl
)
6610 struct nlmsghdr
*nlh
;
6613 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_SET
,
6614 NLM_F_REQUEST
| NLM_F_ACK
);
6615 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
,
6616 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
|
6617 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
|
6618 DL_OPT_HEALTH_REPORTER_AUTO_DUMP
);
6622 dl_opts_put(nlh
, dl
);
6623 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6626 static int cmd_health_dump_clear(struct dl
*dl
)
6628 struct nlmsghdr
*nlh
;
6631 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR
,
6632 NLM_F_REQUEST
| NLM_F_ACK
);
6634 err
= dl_argv_parse_put(nlh
, dl
,
6635 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6639 dl_opts_put(nlh
, dl
);
6640 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6643 static int fmsg_value_show(struct dl
*dl
, int type
, struct nlattr
*nl_data
)
6648 check_indent_newline(dl
);
6651 print_bool(PRINT_ANY
, NULL
, "%s", mnl_attr_get_u8(nl_data
));
6654 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u8(nl_data
));
6657 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u16(nl_data
));
6660 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u32(nl_data
));
6663 print_u64(PRINT_ANY
, NULL
, "%"PRIu64
, mnl_attr_get_u64(nl_data
));
6665 case MNL_TYPE_NUL_STRING
:
6666 print_string(PRINT_ANY
, NULL
, "%s", mnl_attr_get_str(nl_data
));
6668 case MNL_TYPE_BINARY
:
6669 len
= mnl_attr_get_payload_len(nl_data
);
6670 data
= mnl_attr_get_payload(nl_data
);
6671 pr_out_binary_value(dl
, data
, len
);
6679 static void pr_out_fmsg_name(struct dl
*dl
, char **name
)
6684 pr_out_name(dl
, *name
);
6691 struct list_head list
;
6694 struct fmsg_cb_data
{
6698 struct list_head entry_list
;
6701 static int cmd_fmsg_nest_queue(struct fmsg_cb_data
*fmsg_data
,
6702 uint8_t *attr_value
, bool insert
)
6704 struct nest_entry
*entry
;
6707 entry
= malloc(sizeof(struct nest_entry
));
6711 entry
->attr_type
= *attr_value
;
6712 list_add(&entry
->list
, &fmsg_data
->entry_list
);
6714 if (list_empty(&fmsg_data
->entry_list
))
6715 return MNL_CB_ERROR
;
6716 entry
= list_first_entry(&fmsg_data
->entry_list
,
6717 struct nest_entry
, list
);
6718 *attr_value
= entry
->attr_type
;
6719 list_del(&entry
->list
);
6725 static void pr_out_fmsg_group_start(struct dl
*dl
, char **name
)
6728 pr_out_fmsg_name(dl
, name
);
6730 __pr_out_indent_inc();
6733 static void pr_out_fmsg_group_end(struct dl
*dl
)
6736 __pr_out_indent_dec();
6739 static void pr_out_fmsg_start_object(struct dl
*dl
, char **name
)
6741 if (dl
->json_output
) {
6742 pr_out_fmsg_name(dl
, name
);
6743 open_json_object(NULL
);
6745 pr_out_fmsg_group_start(dl
, name
);
6749 static void pr_out_fmsg_end_object(struct dl
*dl
)
6751 if (dl
->json_output
)
6752 close_json_object();
6754 pr_out_fmsg_group_end(dl
);
6757 static void pr_out_fmsg_start_array(struct dl
*dl
, char **name
)
6759 if (dl
->json_output
) {
6760 pr_out_fmsg_name(dl
, name
);
6761 open_json_array(PRINT_JSON
, NULL
);
6763 pr_out_fmsg_group_start(dl
, name
);
6767 static void pr_out_fmsg_end_array(struct dl
*dl
)
6769 if (dl
->json_output
)
6770 close_json_array(PRINT_JSON
, NULL
);
6772 pr_out_fmsg_group_end(dl
);
6775 static int cmd_fmsg_nest(struct fmsg_cb_data
*fmsg_data
, uint8_t nest_value
,
6778 struct dl
*dl
= fmsg_data
->dl
;
6779 uint8_t value
= nest_value
;
6782 err
= cmd_fmsg_nest_queue(fmsg_data
, &value
, start
);
6783 if (err
!= MNL_CB_OK
)
6787 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6789 pr_out_fmsg_start_object(dl
, &fmsg_data
->name
);
6791 pr_out_fmsg_end_object(dl
);
6793 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6795 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6797 pr_out_fmsg_start_array(dl
, &fmsg_data
->name
);
6799 pr_out_fmsg_end_array(dl
);
6807 static int cmd_fmsg_object_cb(const struct nlmsghdr
*nlh
, void *data
)
6809 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6810 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6811 struct fmsg_cb_data
*fmsg_data
= data
;
6812 struct dl
*dl
= fmsg_data
->dl
;
6813 struct nlattr
*nla_object
;
6817 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6818 if (!tb
[DEVLINK_ATTR_FMSG
])
6819 return MNL_CB_ERROR
;
6821 mnl_attr_for_each_nested(nla_object
, tb
[DEVLINK_ATTR_FMSG
]) {
6822 attr_type
= mnl_attr_get_type(nla_object
);
6823 switch (attr_type
) {
6824 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6825 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6826 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6827 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, true);
6828 if (err
!= MNL_CB_OK
)
6831 case DEVLINK_ATTR_FMSG_NEST_END
:
6832 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, false);
6833 if (err
!= MNL_CB_OK
)
6836 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
6837 free(fmsg_data
->name
);
6838 fmsg_data
->name
= strdup(mnl_attr_get_str(nla_object
));
6839 if (!fmsg_data
->name
)
6842 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
:
6843 fmsg_data
->value_type
= mnl_attr_get_u8(nla_object
);
6845 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
6846 pr_out_fmsg_name(dl
, &fmsg_data
->name
);
6847 err
= fmsg_value_show(dl
, fmsg_data
->value_type
,
6849 if (err
!= MNL_CB_OK
)
6859 static void cmd_fmsg_init(struct dl
*dl
, struct fmsg_cb_data
*data
)
6861 /* FMSG is dynamic: opening of an object or array causes a
6862 * newline. JSON starts with an { or [, but plain text should
6863 * not start with a new line. Ensure this by setting
6864 * g_new_line_count to 1: avoiding newline before the first
6867 g_new_line_count
= 1;
6870 INIT_LIST_HEAD(&data
->entry_list
);
6873 static int cmd_health_object_common(struct dl
*dl
, uint8_t cmd
, uint16_t flags
)
6875 struct fmsg_cb_data data
;
6876 struct nlmsghdr
*nlh
;
6879 nlh
= mnlg_msg_prepare(dl
->nlg
, cmd
, flags
| NLM_F_REQUEST
| NLM_F_ACK
);
6881 err
= dl_argv_parse_put(nlh
, dl
,
6882 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6886 cmd_fmsg_init(dl
, &data
);
6887 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_fmsg_object_cb
, &data
);
6892 static int cmd_health_dump_show(struct dl
*dl
)
6894 return cmd_health_object_common(dl
,
6895 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
,
6899 static int cmd_health_diagnose(struct dl
*dl
)
6901 return cmd_health_object_common(dl
,
6902 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
,
6906 static int cmd_health_recover(struct dl
*dl
)
6908 struct nlmsghdr
*nlh
;
6911 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
,
6912 NLM_F_REQUEST
| NLM_F_ACK
);
6914 err
= dl_argv_parse_put(nlh
, dl
,
6915 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6919 dl_opts_put(nlh
, dl
);
6920 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6923 enum devlink_health_reporter_state
{
6924 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
,
6925 DEVLINK_HEALTH_REPORTER_STATE_ERROR
,
6928 static const char *health_state_name(uint8_t state
)
6931 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
:
6932 return HEALTH_REPORTER_STATE_HEALTHY_STR
;
6933 case DEVLINK_HEALTH_REPORTER_STATE_ERROR
:
6934 return HEALTH_REPORTER_STATE_ERROR_STR
;
6936 return "<unknown state>";
6940 static void pr_out_dump_reporter_format_logtime(struct dl
*dl
, const struct nlattr
*attr
)
6942 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6943 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6944 uint64_t time_ms
= mnl_attr_get_u64(attr
);
6945 struct sysinfo s_info
;
6951 info
= localtime(&now
);
6952 err
= sysinfo(&s_info
);
6955 /* Subtract uptime in sec from now yields the time of system
6956 * uptime. To this, add time_ms which is the amount of
6957 * milliseconds elapsed between uptime and the dump taken.
6959 sec
= now
- s_info
.uptime
+ time_ms
/ 1000;
6960 info
= localtime(&sec
);
6962 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", info
);
6963 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", info
);
6964 check_indent_newline(dl
);
6965 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
6966 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
6969 static void pr_out_dump_report_timestamp(struct dl
*dl
, const struct nlattr
*attr
)
6971 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6972 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6977 ts
= mnl_attr_get_u64(attr
);
6978 tv_sec
= ts
/ 1000000000;
6979 tm
= localtime(&tv_sec
);
6981 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", tm
);
6982 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", tm
);
6984 check_indent_newline(dl
);
6985 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
6986 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
6989 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
)
6991 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6992 enum devlink_health_reporter_state state
;
6995 err
= mnl_attr_parse_nested(tb_health
[DEVLINK_ATTR_HEALTH_REPORTER
],
6997 if (err
!= MNL_CB_OK
)
7000 if (!tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
] ||
7001 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] ||
7002 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] ||
7003 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
])
7006 pr_out_handle_start_arr(dl
, tb_health
);
7008 check_indent_newline(dl
);
7009 print_string(PRINT_ANY
, "reporter", "reporter %s",
7010 mnl_attr_get_str(tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]));
7011 if (!dl
->json_output
) {
7013 __pr_out_indent_inc();
7015 state
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
]);
7016 check_indent_newline(dl
);
7017 print_string(PRINT_ANY
, "state", "state %s", health_state_name(state
));
7018 pr_out_u64(dl
, "error",
7019 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
]));
7020 pr_out_u64(dl
, "recover",
7021 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
]));
7022 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
])
7023 pr_out_dump_report_timestamp(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
]);
7024 else if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
])
7025 pr_out_dump_reporter_format_logtime(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
]);
7026 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
7027 pr_out_u64(dl
, "grace_period",
7028 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]));
7029 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
7030 print_bool(PRINT_ANY
, "auto_recover", " auto_recover %s",
7031 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]));
7032 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
])
7033 print_bool(PRINT_ANY
, "auto_dump", " auto_dump %s",
7034 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP
]));
7036 __pr_out_indent_dec();
7037 pr_out_handle_end(dl
);
7040 static int cmd_health_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7042 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7043 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7044 struct dl
*dl
= data
;
7046 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7047 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7048 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
7049 return MNL_CB_ERROR
;
7051 pr_out_health(dl
, tb
);
7056 static int cmd_health_show(struct dl
*dl
)
7058 struct nlmsghdr
*nlh
;
7059 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7062 if (dl_argc(dl
) == 0)
7063 flags
|= NLM_F_DUMP
;
7064 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_GET
,
7067 if (dl_argc(dl
) > 0) {
7068 err
= dl_argv_parse_put(nlh
, dl
,
7070 DL_OPT_HEALTH_REPORTER_NAME
, 0);
7074 pr_out_section_start(dl
, "health");
7076 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_health_show_cb
, dl
);
7077 pr_out_section_end(dl
);
7081 static void cmd_health_help(void)
7083 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
7084 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
7085 pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n");
7086 pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n");
7087 pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n");
7088 pr_err(" devlink health set DEV reporter REPORTER_NAME\n");
7089 pr_err(" [ grace_period MSEC ]\n");
7090 pr_err(" [ auto_recover { true | false } ]\n");
7091 pr_err(" [ auto_dump { true | false } ]\n");
7094 static int cmd_health(struct dl
*dl
)
7096 if (dl_argv_match(dl
, "help")) {
7099 } else if (dl_argv_match(dl
, "show") ||
7100 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7102 return cmd_health_show(dl
);
7103 } else if (dl_argv_match(dl
, "recover")) {
7105 return cmd_health_recover(dl
);
7106 } else if (dl_argv_match(dl
, "diagnose")) {
7108 return cmd_health_diagnose(dl
);
7109 } else if (dl_argv_match(dl
, "dump")) {
7111 if (dl_argv_match(dl
, "show")) {
7113 return cmd_health_dump_show(dl
);
7114 } else if (dl_argv_match(dl
, "clear")) {
7116 return cmd_health_dump_clear(dl
);
7118 } else if (dl_argv_match(dl
, "set")) {
7120 return cmd_health_set_params(dl
);
7122 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7126 static const char *trap_type_name(uint8_t type
)
7129 case DEVLINK_TRAP_TYPE_DROP
:
7131 case DEVLINK_TRAP_TYPE_EXCEPTION
:
7134 return "<unknown type>";
7138 static const char *trap_action_name(uint8_t action
)
7141 case DEVLINK_TRAP_ACTION_DROP
:
7143 case DEVLINK_TRAP_ACTION_TRAP
:
7146 return "<unknown action>";
7150 static const char *trap_metadata_name(const struct nlattr
*attr
)
7152 switch (attr
->nla_type
) {
7153 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT
:
7154 return "input_port";
7155 case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE
:
7156 return "flow_action_cookie";
7158 return "<unknown metadata type>";
7161 static void pr_out_trap_metadata(struct dl
*dl
, struct nlattr
*attr
)
7163 struct nlattr
*attr_metadata
;
7165 pr_out_array_start(dl
, "metadata");
7166 mnl_attr_for_each_nested(attr_metadata
, attr
) {
7167 check_indent_newline(dl
);
7168 print_string(PRINT_ANY
, NULL
, "%s",
7169 trap_metadata_name(attr_metadata
));
7171 pr_out_array_end(dl
);
7174 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7176 uint8_t action
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_ACTION
]);
7177 uint8_t type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_TYPE
]);
7180 pr_out_handle_start_arr(dl
, tb
);
7182 __pr_out_handle_start(dl
, tb
, true, false);
7184 check_indent_newline(dl
);
7185 print_string(PRINT_ANY
, "name", "name %s",
7186 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_NAME
]));
7187 print_string(PRINT_ANY
, "type", " type %s", trap_type_name(type
));
7188 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7189 print_string(PRINT_ANY
, "action", " action %s", trap_action_name(action
));
7190 print_string(PRINT_ANY
, "group", " group %s",
7191 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7193 pr_out_trap_metadata(dl
, tb
[DEVLINK_ATTR_TRAP_METADATA
]);
7194 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7195 pr_out_handle_end(dl
);
7198 static int cmd_trap_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7200 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7201 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7202 struct dl
*dl
= data
;
7204 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7205 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7206 !tb
[DEVLINK_ATTR_TRAP_NAME
] || !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
7207 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
7208 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
7209 !tb
[DEVLINK_ATTR_TRAP_METADATA
] || !tb
[DEVLINK_ATTR_STATS
])
7210 return MNL_CB_ERROR
;
7212 pr_out_trap(dl
, tb
, true);
7217 static void cmd_trap_help(void)
7219 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop } ]\n");
7220 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
7221 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop } ]\n");
7222 pr_err(" [ policer POLICER ] [ nopolicer ]\n");
7223 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
7224 pr_err(" devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
7225 pr_err(" devlink trap policer show DEV policer POLICER\n");
7228 static int cmd_trap_show(struct dl
*dl
)
7230 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7231 struct nlmsghdr
*nlh
;
7234 if (dl_argc(dl
) == 0)
7235 flags
|= NLM_F_DUMP
;
7237 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GET
, flags
);
7239 if (dl_argc(dl
) > 0) {
7240 err
= dl_argv_parse_put(nlh
, dl
,
7241 DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
, 0);
7246 pr_out_section_start(dl
, "trap");
7247 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_show_cb
, dl
);
7248 pr_out_section_end(dl
);
7253 static int cmd_trap_set(struct dl
*dl
)
7255 struct nlmsghdr
*nlh
;
7258 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_SET
,
7259 NLM_F_REQUEST
| NLM_F_ACK
);
7261 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
,
7262 DL_OPT_TRAP_ACTION
);
7266 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7269 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7272 pr_out_handle_start_arr(dl
, tb
);
7274 __pr_out_handle_start(dl
, tb
, true, false);
7276 check_indent_newline(dl
);
7277 print_string(PRINT_ANY
, "name", "name %s",
7278 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7279 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7280 if (tb
[DEVLINK_ATTR_TRAP_POLICER_ID
])
7281 print_uint(PRINT_ANY
, "policer", " policer %u",
7282 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7283 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7284 pr_out_handle_end(dl
);
7287 static int cmd_trap_group_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7289 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7290 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7291 struct dl
*dl
= data
;
7293 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7294 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7295 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] || !tb
[DEVLINK_ATTR_STATS
])
7296 return MNL_CB_ERROR
;
7298 pr_out_trap_group(dl
, tb
, true);
7303 static int cmd_trap_group_show(struct dl
*dl
)
7305 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7306 struct nlmsghdr
*nlh
;
7309 if (dl_argc(dl
) == 0)
7310 flags
|= NLM_F_DUMP
;
7312 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_GET
, flags
);
7314 if (dl_argc(dl
) > 0) {
7315 err
= dl_argv_parse_put(nlh
, dl
,
7316 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7322 pr_out_section_start(dl
, "trap_group");
7323 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_group_show_cb
, dl
);
7324 pr_out_section_end(dl
);
7329 static int cmd_trap_group_set(struct dl
*dl
)
7331 struct nlmsghdr
*nlh
;
7334 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_SET
,
7335 NLM_F_REQUEST
| NLM_F_ACK
);
7337 err
= dl_argv_parse_put(nlh
, dl
,
7338 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7339 DL_OPT_TRAP_ACTION
| DL_OPT_TRAP_POLICER_ID
);
7343 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7346 static int cmd_trap_group(struct dl
*dl
)
7348 if (dl_argv_match(dl
, "help")) {
7351 } else if (dl_argv_match(dl
, "show") ||
7352 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7354 return cmd_trap_group_show(dl
);
7355 } else if (dl_argv_match(dl
, "set")) {
7357 return cmd_trap_group_set(dl
);
7359 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7363 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7366 pr_out_handle_start_arr(dl
, tb
);
7368 __pr_out_handle_start(dl
, tb
, true, false);
7370 check_indent_newline(dl
);
7371 print_uint(PRINT_ANY
, "policer", "policer %u",
7372 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7373 print_u64(PRINT_ANY
, "rate", " rate %llu",
7374 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
]));
7375 print_u64(PRINT_ANY
, "burst", " burst %llu",
7376 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
]));
7377 if (tb
[DEVLINK_ATTR_STATS
])
7378 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7379 pr_out_handle_end(dl
);
7382 static int cmd_trap_policer_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7384 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7385 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7386 struct dl
*dl
= data
;
7388 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7389 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7390 !tb
[DEVLINK_ATTR_TRAP_POLICER_ID
] ||
7391 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
7392 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
7393 return MNL_CB_ERROR
;
7395 pr_out_trap_policer(dl
, tb
, true);
7400 static int cmd_trap_policer_show(struct dl
*dl
)
7402 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7403 struct nlmsghdr
*nlh
;
7406 if (dl_argc(dl
) == 0)
7407 flags
|= NLM_F_DUMP
;
7409 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_GET
, flags
);
7411 if (dl_argc(dl
) > 0) {
7412 err
= dl_argv_parse_put(nlh
, dl
,
7413 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7419 pr_out_section_start(dl
, "trap_policer");
7420 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_policer_show_cb
, dl
);
7421 pr_out_section_end(dl
);
7426 static int cmd_trap_policer_set(struct dl
*dl
)
7428 struct nlmsghdr
*nlh
;
7431 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_SET
,
7432 NLM_F_REQUEST
| NLM_F_ACK
);
7434 err
= dl_argv_parse_put(nlh
, dl
,
7435 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7436 DL_OPT_TRAP_POLICER_RATE
|
7437 DL_OPT_TRAP_POLICER_BURST
);
7441 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7444 static int cmd_trap_policer(struct dl
*dl
)
7446 if (dl_argv_match(dl
, "help")) {
7449 } else if (dl_argv_match(dl
, "show") ||
7450 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7452 return cmd_trap_policer_show(dl
);
7453 } else if (dl_argv_match(dl
, "set")) {
7455 return cmd_trap_policer_set(dl
);
7457 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7461 static int cmd_trap(struct dl
*dl
)
7463 if (dl_argv_match(dl
, "help")) {
7466 } else if (dl_argv_match(dl
, "show") ||
7467 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7469 return cmd_trap_show(dl
);
7470 } else if (dl_argv_match(dl
, "set")) {
7472 return cmd_trap_set(dl
);
7473 } else if (dl_argv_match(dl
, "group")) {
7475 return cmd_trap_group(dl
);
7476 } else if (dl_argv_match(dl
, "policer")) {
7478 return cmd_trap_policer(dl
);
7480 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7484 static void help(void)
7486 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
7487 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
7488 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
7489 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
7492 static int dl_cmd(struct dl
*dl
, int argc
, char **argv
)
7497 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
7500 } else if (dl_argv_match(dl
, "dev")) {
7503 } else if (dl_argv_match(dl
, "port")) {
7505 return cmd_port(dl
);
7506 } else if (dl_argv_match(dl
, "sb")) {
7509 } else if (dl_argv_match(dl
, "monitor")) {
7512 } else if (dl_argv_match(dl
, "dpipe")) {
7514 return cmd_dpipe(dl
);
7515 } else if (dl_argv_match(dl
, "resource")) {
7517 return cmd_resource(dl
);
7518 } else if (dl_argv_match(dl
, "region")) {
7520 return cmd_region(dl
);
7521 } else if (dl_argv_match(dl
, "health")) {
7523 return cmd_health(dl
);
7524 } else if (dl_argv_match(dl
, "trap")) {
7526 return cmd_trap(dl
);
7528 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
7532 static int dl_init(struct dl
*dl
)
7536 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
7538 pr_err("Failed to connect to devlink Netlink\n");
7542 err
= ifname_map_init(dl
);
7544 pr_err("Failed to create index map\n");
7545 goto err_ifname_map_create
;
7547 new_json_obj_plain(dl
->json_output
);
7550 err_ifname_map_create
:
7551 mnlg_socket_close(dl
->nlg
);
7555 static void dl_fini(struct dl
*dl
)
7557 delete_json_obj_plain();
7558 ifname_map_fini(dl
);
7559 mnlg_socket_close(dl
->nlg
);
7562 static struct dl
*dl_alloc(void)
7566 dl
= calloc(1, sizeof(*dl
));
7572 static void dl_free(struct dl
*dl
)
7577 static int dl_batch(struct dl
*dl
, const char *name
, bool force
)
7581 int ret
= EXIT_SUCCESS
;
7583 if (name
&& strcmp(name
, "-") != 0) {
7584 if (freopen(name
, "r", stdin
) == NULL
) {
7586 "Cannot open file \"%s\" for reading: %s\n",
7587 name
, strerror(errno
));
7588 return EXIT_FAILURE
;
7593 while (getcmdline(&line
, &len
, stdin
) != -1) {
7597 largc
= makeargs(line
, largv
, 100);
7599 continue; /* blank line */
7601 if (dl_cmd(dl
, largc
, largv
)) {
7602 fprintf(stderr
, "Command failed %s:%d\n",
7616 int main(int argc
, char **argv
)
7618 static const struct option long_options
[] = {
7619 { "Version", no_argument
, NULL
, 'V' },
7620 { "force", no_argument
, NULL
, 'f' },
7621 { "batch", required_argument
, NULL
, 'b' },
7622 { "no-nice-names", no_argument
, NULL
, 'n' },
7623 { "json", no_argument
, NULL
, 'j' },
7624 { "pretty", no_argument
, NULL
, 'p' },
7625 { "verbose", no_argument
, NULL
, 'v' },
7626 { "statistics", no_argument
, NULL
, 's' },
7627 { "Netns", required_argument
, NULL
, 'N' },
7628 { NULL
, 0, NULL
, 0 }
7630 const char *batch_file
= NULL
;
7639 pr_err("Failed to allocate memory for devlink\n");
7640 return EXIT_FAILURE
;
7643 while ((opt
= getopt_long(argc
, argv
, "Vfb:njpvsN:",
7644 long_options
, NULL
)) >= 0) {
7648 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
7655 batch_file
= optarg
;
7658 dl
->no_nice_names
= true;
7661 dl
->json_output
= true;
7673 if (netns_switch(optarg
)) {
7679 pr_err("Unknown option.\n");
7696 err
= dl_batch(dl
, batch_file
, force
);
7698 err
= dl_cmd(dl
, argc
, argv
);