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>
33 #include "json_writer.h"
35 #include "namespace.h"
37 #define ESWITCH_MODE_LEGACY "legacy"
38 #define ESWITCH_MODE_SWITCHDEV "switchdev"
39 #define ESWITCH_INLINE_MODE_NONE "none"
40 #define ESWITCH_INLINE_MODE_LINK "link"
41 #define ESWITCH_INLINE_MODE_NETWORK "network"
42 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
44 #define PARAM_CMODE_RUNTIME_STR "runtime"
45 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
46 #define PARAM_CMODE_PERMANENT_STR "permanent"
47 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
49 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
50 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
51 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
53 static int g_new_line_count
;
54 static int g_indent_level
;
55 static bool g_indent_newline
;
57 #define INDENT_STR_STEP 2
58 #define INDENT_STR_MAXLEN 32
59 static char g_indent_str
[INDENT_STR_MAXLEN
+ 1] = "";
61 static void __attribute__((format(printf
, 1, 2)))
62 pr_err(const char *fmt
, ...)
67 vfprintf(stderr
, fmt
, ap
);
71 static void __attribute__((format(printf
, 1, 2)))
72 pr_out(const char *fmt
, ...)
76 if (g_indent_newline
) {
77 printf("%s", g_indent_str
);
78 g_indent_newline
= false;
86 static void __attribute__((format(printf
, 2, 3)))
87 pr_out_sp(unsigned int num
, const char *fmt
, ...)
93 ret
= vprintf(fmt
, ap
);
97 printf("%*s", num
- ret
, "");
98 g_new_line_count
= 0; \
101 static void __attribute__((format(printf
, 1, 2)))
102 pr_out_tty(const char *fmt
, ...)
106 if (!isatty(STDOUT_FILENO
))
113 static void __pr_out_indent_inc(void)
115 if (g_indent_level
+ INDENT_STR_STEP
> INDENT_STR_MAXLEN
)
117 g_indent_level
+= INDENT_STR_STEP
;
118 memset(g_indent_str
, ' ', sizeof(g_indent_str
));
119 g_indent_str
[g_indent_level
] = '\0';
122 static void __pr_out_indent_dec(void)
124 if (g_indent_level
- INDENT_STR_STEP
< 0)
126 g_indent_level
-= INDENT_STR_STEP
;
127 g_indent_str
[g_indent_level
] = '\0';
130 static void __pr_out_newline(void)
132 if (g_new_line_count
< 1) {
134 g_indent_newline
= true;
139 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
140 mnl_cb_t data_cb
, void *data
)
144 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
146 pr_err("devlink answers: %s\n", strerror(errno
));
152 static int _mnlg_socket_send(struct mnlg_socket
*nlg
,
153 const struct nlmsghdr
*nlh
)
157 err
= mnlg_socket_send(nlg
, nlh
);
159 pr_err("Failed to call mnlg_socket_send\n");
165 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
166 const struct nlmsghdr
*nlh
,
167 mnl_cb_t data_cb
, void *data
)
171 err
= _mnlg_socket_send(nlg
, nlh
);
174 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
177 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
178 const char *group_name
)
182 err
= mnlg_socket_group_add(nlg
, group_name
);
184 pr_err("Failed to call mnlg_socket_group_add\n");
191 struct list_head list
;
198 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
199 const char *dev_name
,
203 struct ifname_map
*ifname_map
;
205 ifname_map
= calloc(1, sizeof(*ifname_map
));
208 ifname_map
->bus_name
= strdup(bus_name
);
209 ifname_map
->dev_name
= strdup(dev_name
);
210 ifname_map
->port_index
= port_index
;
211 ifname_map
->ifname
= strdup(ifname
);
212 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
213 !ifname_map
->ifname
) {
214 free(ifname_map
->ifname
);
215 free(ifname_map
->dev_name
);
216 free(ifname_map
->bus_name
);
223 static void ifname_map_free(struct ifname_map
*ifname_map
)
225 free(ifname_map
->ifname
);
226 free(ifname_map
->dev_name
);
227 free(ifname_map
->bus_name
);
231 #define DL_OPT_HANDLE BIT(0)
232 #define DL_OPT_HANDLEP BIT(1)
233 #define DL_OPT_PORT_TYPE BIT(2)
234 #define DL_OPT_PORT_COUNT BIT(3)
235 #define DL_OPT_SB BIT(4)
236 #define DL_OPT_SB_POOL BIT(5)
237 #define DL_OPT_SB_SIZE BIT(6)
238 #define DL_OPT_SB_TYPE BIT(7)
239 #define DL_OPT_SB_THTYPE BIT(8)
240 #define DL_OPT_SB_TH BIT(9)
241 #define DL_OPT_SB_TC BIT(10)
242 #define DL_OPT_ESWITCH_MODE BIT(11)
243 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
244 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
245 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
246 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
247 #define DL_OPT_RESOURCE_PATH BIT(16)
248 #define DL_OPT_RESOURCE_SIZE BIT(17)
249 #define DL_OPT_PARAM_NAME BIT(18)
250 #define DL_OPT_PARAM_VALUE BIT(19)
251 #define DL_OPT_PARAM_CMODE BIT(20)
252 #define DL_OPT_HANDLE_REGION BIT(21)
253 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
254 #define DL_OPT_REGION_ADDRESS BIT(23)
255 #define DL_OPT_REGION_LENGTH BIT(24)
256 #define DL_OPT_FLASH_FILE_NAME BIT(25)
257 #define DL_OPT_FLASH_COMPONENT BIT(26)
258 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
259 #define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(28)
260 #define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(29)
261 #define DL_OPT_TRAP_NAME BIT(30)
262 #define DL_OPT_TRAP_ACTION BIT(31)
263 #define DL_OPT_TRAP_GROUP_NAME BIT(32)
264 #define DL_OPT_NETNS BIT(33)
267 uint64_t present
; /* flags of present items */
271 enum devlink_port_type port_type
;
274 uint16_t sb_pool_index
;
275 uint32_t sb_pool_size
;
276 enum devlink_sb_pool_type sb_pool_type
;
277 enum devlink_sb_threshold_type sb_pool_thtype
;
278 uint32_t sb_threshold
;
279 uint16_t sb_tc_index
;
280 enum devlink_eswitch_mode eswitch_mode
;
281 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
282 const char *dpipe_table_name
;
283 bool dpipe_counters_enable
;
284 bool eswitch_encap_mode
;
285 const char *resource_path
;
286 uint64_t resource_size
;
287 uint32_t resource_id
;
288 bool resource_id_valid
;
289 const char *param_name
;
290 const char *param_value
;
291 enum devlink_param_cmode cmode
;
293 uint32_t region_snapshot_id
;
294 uint64_t region_address
;
295 uint64_t region_length
;
296 const char *flash_file_name
;
297 const char *flash_component
;
298 const char *reporter_name
;
299 uint64_t reporter_graceful_period
;
300 bool reporter_auto_recover
;
301 const char *trap_name
;
302 const char *trap_group_name
;
303 enum devlink_trap_action trap_action
;
309 struct mnlg_socket
*nlg
;
310 struct list_head ifname_map_list
;
328 static int dl_argc(struct dl
*dl
)
333 static char *dl_argv(struct dl
*dl
)
335 if (dl_argc(dl
) == 0)
340 static void dl_arg_inc(struct dl
*dl
)
342 if (dl_argc(dl
) == 0)
348 static void dl_arg_dec(struct dl
*dl
)
354 static char *dl_argv_next(struct dl
*dl
)
358 if (dl_argc(dl
) == 0)
366 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
368 if (index
>= dl_argc(dl
))
370 return dl
->argv
[index
];
373 static int strcmpx(const char *str1
, const char *str2
)
375 if (strlen(str1
) > strlen(str2
))
377 return strncmp(str1
, str2
, strlen(str1
));
380 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
382 if (dl_argc(dl
) == 0)
384 return strcmpx(dl_argv(dl
), pattern
) == 0;
387 static bool dl_no_arg(struct dl
*dl
)
389 return dl_argc(dl
) == 0;
392 static void __pr_out_indent_newline(struct dl
*dl
)
394 if (!g_indent_newline
&& !dl
->json_output
)
398 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
399 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
400 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
401 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
402 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
403 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
404 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
405 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
406 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
407 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
408 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
409 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
410 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
411 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
412 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
413 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
414 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
415 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
416 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
417 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
418 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
419 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
420 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
421 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
422 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
423 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
424 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
425 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
426 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
427 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
428 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
429 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
430 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
431 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
432 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
433 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
434 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
435 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
436 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
437 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
438 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
439 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
440 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
441 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
442 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
443 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
444 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
445 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
446 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
447 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
448 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
449 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
450 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
451 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
452 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
453 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
454 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
455 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
456 [DEVLINK_ATTR_PARAM
] = MNL_TYPE_NESTED
,
457 [DEVLINK_ATTR_PARAM_NAME
] = MNL_TYPE_STRING
,
458 [DEVLINK_ATTR_PARAM_TYPE
] = MNL_TYPE_U8
,
459 [DEVLINK_ATTR_PARAM_VALUES_LIST
] = MNL_TYPE_NESTED
,
460 [DEVLINK_ATTR_PARAM_VALUE
] = MNL_TYPE_NESTED
,
461 [DEVLINK_ATTR_PARAM_VALUE_CMODE
] = MNL_TYPE_U8
,
462 [DEVLINK_ATTR_REGION_NAME
] = MNL_TYPE_STRING
,
463 [DEVLINK_ATTR_REGION_SIZE
] = MNL_TYPE_U64
,
464 [DEVLINK_ATTR_REGION_SNAPSHOTS
] = MNL_TYPE_NESTED
,
465 [DEVLINK_ATTR_REGION_SNAPSHOT
] = MNL_TYPE_NESTED
,
466 [DEVLINK_ATTR_REGION_SNAPSHOT_ID
] = MNL_TYPE_U32
,
467 [DEVLINK_ATTR_REGION_CHUNKS
] = MNL_TYPE_NESTED
,
468 [DEVLINK_ATTR_REGION_CHUNK
] = MNL_TYPE_NESTED
,
469 [DEVLINK_ATTR_REGION_CHUNK_DATA
] = MNL_TYPE_BINARY
,
470 [DEVLINK_ATTR_REGION_CHUNK_ADDR
] = MNL_TYPE_U64
,
471 [DEVLINK_ATTR_REGION_CHUNK_LEN
] = MNL_TYPE_U64
,
472 [DEVLINK_ATTR_INFO_DRIVER_NAME
] = MNL_TYPE_STRING
,
473 [DEVLINK_ATTR_INFO_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
474 [DEVLINK_ATTR_INFO_VERSION_FIXED
] = MNL_TYPE_NESTED
,
475 [DEVLINK_ATTR_INFO_VERSION_RUNNING
] = MNL_TYPE_NESTED
,
476 [DEVLINK_ATTR_INFO_VERSION_STORED
] = MNL_TYPE_NESTED
,
477 [DEVLINK_ATTR_INFO_VERSION_NAME
] = MNL_TYPE_STRING
,
478 [DEVLINK_ATTR_INFO_VERSION_VALUE
] = MNL_TYPE_STRING
,
479 [DEVLINK_ATTR_HEALTH_REPORTER
] = MNL_TYPE_NESTED
,
480 [DEVLINK_ATTR_HEALTH_REPORTER_NAME
] = MNL_TYPE_STRING
,
481 [DEVLINK_ATTR_HEALTH_REPORTER_STATE
] = MNL_TYPE_U8
,
482 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] = MNL_TYPE_U64
,
483 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] = MNL_TYPE_U64
,
484 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
] = MNL_TYPE_U64
,
485 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] = MNL_TYPE_U64
,
486 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
] = MNL_TYPE_STRING
,
487 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
] = MNL_TYPE_STRING
,
488 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
] = MNL_TYPE_U64
,
489 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
] = MNL_TYPE_U64
,
490 [DEVLINK_ATTR_STATS
] = MNL_TYPE_NESTED
,
491 [DEVLINK_ATTR_TRAP_NAME
] = MNL_TYPE_STRING
,
492 [DEVLINK_ATTR_TRAP_ACTION
] = MNL_TYPE_U8
,
493 [DEVLINK_ATTR_TRAP_TYPE
] = MNL_TYPE_U8
,
494 [DEVLINK_ATTR_TRAP_GENERIC
] = MNL_TYPE_FLAG
,
495 [DEVLINK_ATTR_TRAP_METADATA
] = MNL_TYPE_NESTED
,
496 [DEVLINK_ATTR_TRAP_GROUP_NAME
] = MNL_TYPE_STRING
,
497 [DEVLINK_ATTR_RELOAD_FAILED
] = MNL_TYPE_U8
,
500 static const enum mnl_attr_data_type
501 devlink_stats_policy
[DEVLINK_ATTR_STATS_MAX
+ 1] = {
502 [DEVLINK_ATTR_STATS_RX_PACKETS
] = MNL_TYPE_U64
,
503 [DEVLINK_ATTR_STATS_RX_BYTES
] = MNL_TYPE_U64
,
506 static int attr_cb(const struct nlattr
*attr
, void *data
)
508 const struct nlattr
**tb
= data
;
511 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
514 type
= mnl_attr_get_type(attr
);
515 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
522 static int attr_stats_cb(const struct nlattr
*attr
, void *data
)
524 const struct nlattr
**tb
= data
;
527 /* Allow the tool to work on top of newer kernels that might contain
530 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_STATS_MAX
) < 0)
533 type
= mnl_attr_get_type(attr
);
534 if (mnl_attr_validate(attr
, devlink_stats_policy
[type
]) < 0)
541 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
543 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
544 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
545 struct dl
*dl
= data
;
546 struct ifname_map
*ifname_map
;
547 const char *bus_name
;
548 const char *dev_name
;
549 uint32_t port_ifindex
;
550 const char *port_ifname
;
552 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
553 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
554 !tb
[DEVLINK_ATTR_PORT_INDEX
])
557 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
560 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
561 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
562 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
563 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
564 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
565 port_ifindex
, port_ifname
);
568 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
573 static void ifname_map_fini(struct dl
*dl
)
575 struct ifname_map
*ifname_map
, *tmp
;
577 list_for_each_entry_safe(ifname_map
, tmp
,
578 &dl
->ifname_map_list
, list
) {
579 list_del(&ifname_map
->list
);
580 ifname_map_free(ifname_map
);
584 static int ifname_map_init(struct dl
*dl
)
586 struct nlmsghdr
*nlh
;
589 INIT_LIST_HEAD(&dl
->ifname_map_list
);
591 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
592 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
594 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
602 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
603 char **p_bus_name
, char **p_dev_name
,
604 uint32_t *p_port_index
)
606 struct ifname_map
*ifname_map
;
608 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
609 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
610 *p_bus_name
= ifname_map
->bus_name
;
611 *p_dev_name
= ifname_map
->dev_name
;
612 *p_port_index
= ifname_map
->port_index
;
619 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
620 const char *dev_name
, uint32_t port_index
,
623 struct ifname_map
*ifname_map
;
625 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
626 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
627 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
628 port_index
== ifname_map
->port_index
) {
629 *p_ifname
= ifname_map
->ifname
;
636 static unsigned int strslashcount(char *str
)
638 unsigned int count
= 0;
641 while ((pos
= strchr(pos
, '/'))) {
648 static int strslashrsplit(char *str
, char **before
, char **after
)
652 slash
= strrchr(str
, '/');
661 static int strtouint64_t(const char *str
, uint64_t *p_val
)
664 unsigned long long int val
;
666 val
= strtoull(str
, &endptr
, 10);
667 if (endptr
== str
|| *endptr
!= '\0')
675 static int strtouint32_t(const char *str
, uint32_t *p_val
)
678 unsigned long int val
;
680 val
= strtoul(str
, &endptr
, 10);
681 if (endptr
== str
|| *endptr
!= '\0')
689 static int strtouint16_t(const char *str
, uint16_t *p_val
)
692 unsigned long int val
;
694 val
= strtoul(str
, &endptr
, 10);
695 if (endptr
== str
|| *endptr
!= '\0')
703 static int strtouint8_t(const char *str
, uint8_t *p_val
)
706 unsigned long int val
;
708 val
= strtoul(str
, &endptr
, 10);
709 if (endptr
== str
|| *endptr
!= '\0')
717 static int strtobool(const char *str
, bool *p_val
)
721 if (!strcmp(str
, "true") || !strcmp(str
, "1"))
723 else if (!strcmp(str
, "false") || !strcmp(str
, "0"))
731 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
733 strslashrsplit(str
, p_bus_name
, p_dev_name
);
737 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
739 char *str
= dl_argv_next(dl
);
742 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
745 if (strslashcount(str
) != 1) {
746 pr_err("Wrong devlink identification string format.\n");
747 pr_err("Expected \"bus_name/dev_name\".\n");
750 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
753 static int __dl_argv_handle_port(char *str
,
754 char **p_bus_name
, char **p_dev_name
,
755 uint32_t *p_port_index
)
761 err
= strslashrsplit(str
, &handlestr
, &portstr
);
763 pr_err("Port identification \"%s\" is invalid\n", str
);
766 err
= strtouint32_t(portstr
, p_port_index
);
768 pr_err("Port index \"%s\" is not a number or not within range\n",
772 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
774 pr_err("Port identification \"%s\" is invalid\n", str
);
780 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
781 char **p_bus_name
, char **p_dev_name
,
782 uint32_t *p_port_index
)
786 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
789 pr_err("Netdevice \"%s\" not found\n", str
);
795 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
796 char **p_dev_name
, uint32_t *p_port_index
)
798 char *str
= dl_argv_next(dl
);
799 unsigned int slash_count
;
802 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
805 slash_count
= strslashcount(str
);
806 switch (slash_count
) {
808 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
809 p_dev_name
, p_port_index
);
811 return __dl_argv_handle_port(str
, p_bus_name
,
812 p_dev_name
, p_port_index
);
814 pr_err("Wrong port identification string format.\n");
815 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
820 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
821 char **p_dev_name
, uint32_t *p_port_index
,
822 uint64_t *p_handle_bit
)
824 char *str
= dl_argv_next(dl
);
825 unsigned int slash_count
;
829 pr_err("One of following identifications expected:\n"
830 "Devlink identification (\"bus_name/dev_name\")\n"
831 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
834 slash_count
= strslashcount(str
);
835 if (slash_count
== 1) {
836 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
839 *p_handle_bit
= DL_OPT_HANDLE
;
840 } else if (slash_count
== 2) {
841 err
= __dl_argv_handle_port(str
, p_bus_name
,
842 p_dev_name
, p_port_index
);
845 *p_handle_bit
= DL_OPT_HANDLEP
;
846 } else if (slash_count
== 0) {
847 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
848 p_dev_name
, p_port_index
);
851 *p_handle_bit
= DL_OPT_HANDLEP
;
853 pr_err("Wrong port identification string format.\n");
854 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
860 static int __dl_argv_handle_region(char *str
, char **p_bus_name
,
861 char **p_dev_name
, char **p_region
)
866 err
= strslashrsplit(str
, &handlestr
, p_region
);
868 pr_err("Region identification \"%s\" is invalid\n", str
);
871 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
873 pr_err("Region identification \"%s\" is invalid\n", str
);
879 static int dl_argv_handle_region(struct dl
*dl
, char **p_bus_name
,
880 char **p_dev_name
, char **p_region
)
882 char *str
= dl_argv_next(dl
);
883 unsigned int slash_count
;
886 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
890 slash_count
= strslashcount(str
);
891 if (slash_count
!= 2) {
892 pr_err("Wrong region identification string format.\n");
893 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
897 return __dl_argv_handle_region(str
, p_bus_name
, p_dev_name
, p_region
);
900 static int dl_argv_uint64_t(struct dl
*dl
, uint64_t *p_val
)
902 char *str
= dl_argv_next(dl
);
906 pr_err("Unsigned number argument expected\n");
910 err
= strtouint64_t(str
, p_val
);
912 pr_err("\"%s\" is not a number or not within range\n", str
);
918 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
920 char *str
= dl_argv_next(dl
);
924 pr_err("Unsigned number argument expected\n");
928 err
= strtouint32_t(str
, p_val
);
930 pr_err("\"%s\" is not a number or not within range\n", str
);
936 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
938 char *str
= dl_argv_next(dl
);
942 pr_err("Unsigned number argument expected\n");
946 err
= strtouint16_t(str
, p_val
);
948 pr_err("\"%s\" is not a number or not within range\n", str
);
954 static int dl_argv_bool(struct dl
*dl
, bool *p_val
)
956 char *str
= dl_argv_next(dl
);
960 pr_err("Boolean argument expected\n");
964 err
= strtobool(str
, p_val
);
966 pr_err("\"%s\" is not a valid boolean value\n", str
);
972 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
974 const char *str
= dl_argv_next(dl
);
977 pr_err("String parameter expected\n");
984 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
986 if (strcmp(typestr
, "auto") == 0) {
987 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
988 } else if (strcmp(typestr
, "eth") == 0) {
989 *p_type
= DEVLINK_PORT_TYPE_ETH
;
990 } else if (strcmp(typestr
, "ib") == 0) {
991 *p_type
= DEVLINK_PORT_TYPE_IB
;
993 pr_err("Unknown port type \"%s\"\n", typestr
);
999 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
1001 if (strcmp(typestr
, "ingress") == 0) {
1002 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
1003 } else if (strcmp(typestr
, "egress") == 0) {
1004 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
1006 pr_err("Unknown pool type \"%s\"\n", typestr
);
1012 static int threshold_type_get(const char *typestr
,
1013 enum devlink_sb_threshold_type
*p_type
)
1015 if (strcmp(typestr
, "static") == 0) {
1016 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
1017 } else if (strcmp(typestr
, "dynamic") == 0) {
1018 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
1020 pr_err("Unknown threshold type \"%s\"\n", typestr
);
1026 static int eswitch_mode_get(const char *typestr
,
1027 enum devlink_eswitch_mode
*p_mode
)
1029 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
1030 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
1031 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
1032 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
1034 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
1040 static int eswitch_inline_mode_get(const char *typestr
,
1041 enum devlink_eswitch_inline_mode
*p_mode
)
1043 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
1044 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
1045 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
1046 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
1047 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
1048 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
1049 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
1050 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
1052 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
1058 static int dpipe_counters_enable_get(const char *typestr
,
1059 bool *counters_enable
)
1061 if (strcmp(typestr
, "enable") == 0) {
1062 *counters_enable
= 1;
1063 } else if (strcmp(typestr
, "disable") == 0) {
1064 *counters_enable
= 0;
1066 pr_err("Unknown counter_state \"%s\"\n", typestr
);
1072 static int eswitch_encap_mode_get(const char *typestr
, bool *p_mode
)
1074 if (strcmp(typestr
, "enable") == 0) {
1076 } else if (strcmp(typestr
, "disable") == 0) {
1079 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
1085 static int param_cmode_get(const char *cmodestr
,
1086 enum devlink_param_cmode
*cmode
)
1088 if (strcmp(cmodestr
, PARAM_CMODE_RUNTIME_STR
) == 0) {
1089 *cmode
= DEVLINK_PARAM_CMODE_RUNTIME
;
1090 } else if (strcmp(cmodestr
, PARAM_CMODE_DRIVERINIT_STR
) == 0) {
1091 *cmode
= DEVLINK_PARAM_CMODE_DRIVERINIT
;
1092 } else if (strcmp(cmodestr
, PARAM_CMODE_PERMANENT_STR
) == 0) {
1093 *cmode
= DEVLINK_PARAM_CMODE_PERMANENT
;
1095 pr_err("Unknown configuration mode \"%s\"\n", cmodestr
);
1101 static int trap_action_get(const char *actionstr
,
1102 enum devlink_trap_action
*p_action
)
1104 if (strcmp(actionstr
, "drop") == 0) {
1105 *p_action
= DEVLINK_TRAP_ACTION_DROP
;
1106 } else if (strcmp(actionstr
, "trap") == 0) {
1107 *p_action
= DEVLINK_TRAP_ACTION_TRAP
;
1109 pr_err("Unknown trap action \"%s\"\n", actionstr
);
1115 struct dl_args_metadata
{
1117 char err_msg
[DL_ARGS_REQUIRED_MAX_ERR_LEN
];
1120 static const struct dl_args_metadata dl_args_required
[] = {
1121 {DL_OPT_PORT_TYPE
, "Port type not set."},
1122 {DL_OPT_PORT_COUNT
, "Port split count option expected."},
1123 {DL_OPT_SB_POOL
, "Pool index option expected."},
1124 {DL_OPT_SB_SIZE
, "Pool size option expected."},
1125 {DL_OPT_SB_TYPE
, "Pool type option expected."},
1126 {DL_OPT_SB_THTYPE
, "Pool threshold type option expected."},
1127 {DL_OPT_SB_TH
, "Threshold option expected."},
1128 {DL_OPT_SB_TC
, "TC index option expected."},
1129 {DL_OPT_ESWITCH_MODE
, "E-Switch mode option expected."},
1130 {DL_OPT_ESWITCH_INLINE_MODE
, "E-Switch inline-mode option expected."},
1131 {DL_OPT_DPIPE_TABLE_NAME
, "Dpipe table name expected."},
1132 {DL_OPT_DPIPE_TABLE_COUNTERS
, "Dpipe table counter state expected."},
1133 {DL_OPT_ESWITCH_ENCAP_MODE
, "E-Switch encapsulation option expected."},
1134 {DL_OPT_RESOURCE_PATH
, "Resource path expected."},
1135 {DL_OPT_RESOURCE_SIZE
, "Resource size expected."},
1136 {DL_OPT_PARAM_NAME
, "Parameter name expected."},
1137 {DL_OPT_PARAM_VALUE
, "Value to set expected."},
1138 {DL_OPT_PARAM_CMODE
, "Configuration mode expected."},
1139 {DL_OPT_REGION_SNAPSHOT_ID
, "Region snapshot id expected."},
1140 {DL_OPT_REGION_ADDRESS
, "Region address value expected."},
1141 {DL_OPT_REGION_LENGTH
, "Region length value expected."},
1142 {DL_OPT_HEALTH_REPORTER_NAME
, "Reporter's name is expected."},
1143 {DL_OPT_TRAP_NAME
, "Trap's name is expected."},
1144 {DL_OPT_TRAP_GROUP_NAME
, "Trap group's name is expected."},
1147 static int dl_args_finding_required_validate(uint64_t o_required
,
1153 for (i
= 0; i
< ARRAY_SIZE(dl_args_required
); i
++) {
1154 o_flag
= dl_args_required
[i
].o_flag
;
1155 if ((o_required
& o_flag
) && !(o_found
& o_flag
)) {
1156 pr_err("%s\n", dl_args_required
[i
].err_msg
);
1160 if (o_required
& ~o_found
) {
1161 pr_err("BUG: unknown argument required but not found\n");
1167 static int dl_argv_parse(struct dl
*dl
, uint64_t o_required
,
1168 uint64_t o_optional
)
1170 struct dl_opts
*opts
= &dl
->opts
;
1171 uint64_t o_all
= o_required
| o_optional
;
1172 uint64_t o_found
= 0;
1175 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
1176 uint64_t handle_bit
;
1178 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
1179 &opts
->port_index
, &handle_bit
);
1182 o_required
&= ~(DL_OPT_HANDLE
| DL_OPT_HANDLEP
) | handle_bit
;
1183 o_found
|= handle_bit
;
1184 } else if (o_required
& DL_OPT_HANDLE
) {
1185 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
1188 o_found
|= DL_OPT_HANDLE
;
1189 } else if (o_required
& DL_OPT_HANDLEP
) {
1190 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
1194 o_found
|= DL_OPT_HANDLEP
;
1195 } else if (o_required
& DL_OPT_HANDLE_REGION
) {
1196 err
= dl_argv_handle_region(dl
, &opts
->bus_name
,
1198 &opts
->region_name
);
1201 o_found
|= DL_OPT_HANDLE_REGION
;
1204 while (dl_argc(dl
)) {
1205 if (dl_argv_match(dl
, "type") &&
1206 (o_all
& DL_OPT_PORT_TYPE
)) {
1207 const char *typestr
;
1210 err
= dl_argv_str(dl
, &typestr
);
1213 err
= port_type_get(typestr
, &opts
->port_type
);
1216 o_found
|= DL_OPT_PORT_TYPE
;
1217 } else if (dl_argv_match(dl
, "count") &&
1218 (o_all
& DL_OPT_PORT_COUNT
)) {
1220 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
1223 o_found
|= DL_OPT_PORT_COUNT
;
1224 } else if (dl_argv_match(dl
, "sb") &&
1225 (o_all
& DL_OPT_SB
)) {
1227 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
1230 o_found
|= DL_OPT_SB
;
1231 } else if (dl_argv_match(dl
, "pool") &&
1232 (o_all
& DL_OPT_SB_POOL
)) {
1234 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
1237 o_found
|= DL_OPT_SB_POOL
;
1238 } else if (dl_argv_match(dl
, "size") &&
1239 (o_all
& DL_OPT_SB_SIZE
)) {
1241 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
1244 o_found
|= DL_OPT_SB_SIZE
;
1245 } else if (dl_argv_match(dl
, "type") &&
1246 (o_all
& DL_OPT_SB_TYPE
)) {
1247 const char *typestr
;
1250 err
= dl_argv_str(dl
, &typestr
);
1253 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
1256 o_found
|= DL_OPT_SB_TYPE
;
1257 } else if (dl_argv_match(dl
, "thtype") &&
1258 (o_all
& DL_OPT_SB_THTYPE
)) {
1259 const char *typestr
;
1262 err
= dl_argv_str(dl
, &typestr
);
1265 err
= threshold_type_get(typestr
,
1266 &opts
->sb_pool_thtype
);
1269 o_found
|= DL_OPT_SB_THTYPE
;
1270 } else if (dl_argv_match(dl
, "th") &&
1271 (o_all
& DL_OPT_SB_TH
)) {
1273 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
1276 o_found
|= DL_OPT_SB_TH
;
1277 } else if (dl_argv_match(dl
, "tc") &&
1278 (o_all
& DL_OPT_SB_TC
)) {
1280 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
1283 o_found
|= DL_OPT_SB_TC
;
1284 } else if (dl_argv_match(dl
, "mode") &&
1285 (o_all
& DL_OPT_ESWITCH_MODE
)) {
1286 const char *typestr
;
1289 err
= dl_argv_str(dl
, &typestr
);
1292 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
1295 o_found
|= DL_OPT_ESWITCH_MODE
;
1296 } else if (dl_argv_match(dl
, "inline-mode") &&
1297 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1298 const char *typestr
;
1301 err
= dl_argv_str(dl
, &typestr
);
1304 err
= eswitch_inline_mode_get(
1305 typestr
, &opts
->eswitch_inline_mode
);
1308 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
1309 } else if (dl_argv_match(dl
, "name") &&
1310 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
1312 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
1315 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
1316 } else if (dl_argv_match(dl
, "counters") &&
1317 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1318 const char *typestr
;
1321 err
= dl_argv_str(dl
, &typestr
);
1324 err
= dpipe_counters_enable_get(typestr
,
1325 &opts
->dpipe_counters_enable
);
1328 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
1329 } else if (dl_argv_match(dl
, "encap") &&
1330 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1331 const char *typestr
;
1334 err
= dl_argv_str(dl
, &typestr
);
1337 err
= eswitch_encap_mode_get(typestr
,
1338 &opts
->eswitch_encap_mode
);
1341 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
1342 } else if (dl_argv_match(dl
, "path") &&
1343 (o_all
& DL_OPT_RESOURCE_PATH
)) {
1345 err
= dl_argv_str(dl
, &opts
->resource_path
);
1348 o_found
|= DL_OPT_RESOURCE_PATH
;
1349 } else if (dl_argv_match(dl
, "size") &&
1350 (o_all
& DL_OPT_RESOURCE_SIZE
)) {
1352 err
= dl_argv_uint64_t(dl
, &opts
->resource_size
);
1355 o_found
|= DL_OPT_RESOURCE_SIZE
;
1356 } else if (dl_argv_match(dl
, "name") &&
1357 (o_all
& DL_OPT_PARAM_NAME
)) {
1359 err
= dl_argv_str(dl
, &opts
->param_name
);
1362 o_found
|= DL_OPT_PARAM_NAME
;
1363 } else if (dl_argv_match(dl
, "value") &&
1364 (o_all
& DL_OPT_PARAM_VALUE
)) {
1366 err
= dl_argv_str(dl
, &opts
->param_value
);
1369 o_found
|= DL_OPT_PARAM_VALUE
;
1370 } else if (dl_argv_match(dl
, "cmode") &&
1371 (o_all
& DL_OPT_PARAM_CMODE
)) {
1372 const char *cmodestr
;
1375 err
= dl_argv_str(dl
, &cmodestr
);
1378 err
= param_cmode_get(cmodestr
, &opts
->cmode
);
1381 o_found
|= DL_OPT_PARAM_CMODE
;
1382 } else if (dl_argv_match(dl
, "snapshot") &&
1383 (o_all
& DL_OPT_REGION_SNAPSHOT_ID
)) {
1385 err
= dl_argv_uint32_t(dl
, &opts
->region_snapshot_id
);
1388 o_found
|= DL_OPT_REGION_SNAPSHOT_ID
;
1389 } else if (dl_argv_match(dl
, "address") &&
1390 (o_all
& DL_OPT_REGION_ADDRESS
)) {
1392 err
= dl_argv_uint64_t(dl
, &opts
->region_address
);
1395 o_found
|= DL_OPT_REGION_ADDRESS
;
1396 } else if (dl_argv_match(dl
, "length") &&
1397 (o_all
& DL_OPT_REGION_LENGTH
)) {
1399 err
= dl_argv_uint64_t(dl
, &opts
->region_length
);
1402 o_found
|= DL_OPT_REGION_LENGTH
;
1403 } else if (dl_argv_match(dl
, "file") &&
1404 (o_all
& DL_OPT_FLASH_FILE_NAME
)) {
1406 err
= dl_argv_str(dl
, &opts
->flash_file_name
);
1409 o_found
|= DL_OPT_FLASH_FILE_NAME
;
1410 } else if (dl_argv_match(dl
, "component") &&
1411 (o_all
& DL_OPT_FLASH_COMPONENT
)) {
1413 err
= dl_argv_str(dl
, &opts
->flash_component
);
1416 o_found
|= DL_OPT_FLASH_COMPONENT
;
1417 } else if (dl_argv_match(dl
, "reporter") &&
1418 (o_all
& DL_OPT_HEALTH_REPORTER_NAME
)) {
1420 err
= dl_argv_str(dl
, &opts
->reporter_name
);
1423 o_found
|= DL_OPT_HEALTH_REPORTER_NAME
;
1424 } else if (dl_argv_match(dl
, "grace_period") &&
1425 (o_all
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)) {
1427 err
= dl_argv_uint64_t(dl
,
1428 &opts
->reporter_graceful_period
);
1431 o_found
|= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
;
1432 } else if (dl_argv_match(dl
, "auto_recover") &&
1433 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)) {
1435 err
= dl_argv_bool(dl
, &opts
->reporter_auto_recover
);
1438 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
;
1439 } else if (dl_argv_match(dl
, "trap") &&
1440 (o_all
& DL_OPT_TRAP_NAME
)) {
1442 err
= dl_argv_str(dl
, &opts
->trap_name
);
1445 o_found
|= DL_OPT_TRAP_NAME
;
1446 } else if (dl_argv_match(dl
, "group") &&
1447 (o_all
& DL_OPT_TRAP_GROUP_NAME
)) {
1449 err
= dl_argv_str(dl
, &opts
->trap_group_name
);
1452 o_found
|= DL_OPT_TRAP_GROUP_NAME
;
1453 } else if (dl_argv_match(dl
, "action") &&
1454 (o_all
& DL_OPT_TRAP_ACTION
)) {
1455 const char *actionstr
;
1458 err
= dl_argv_str(dl
, &actionstr
);
1461 err
= trap_action_get(actionstr
, &opts
->trap_action
);
1464 o_found
|= DL_OPT_TRAP_ACTION
;
1465 } else if (dl_argv_match(dl
, "netns") &&
1466 (o_all
& DL_OPT_NETNS
)) {
1467 const char *netns_str
;
1470 err
= dl_argv_str(dl
, &netns_str
);
1473 opts
->netns
= netns_get_fd(netns_str
);
1474 if ((int)opts
->netns
< 0) {
1476 err
= dl_argv_uint32_t(dl
, &opts
->netns
);
1479 opts
->netns_is_pid
= true;
1481 o_found
|= DL_OPT_NETNS
;
1483 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
1488 opts
->present
= o_found
;
1490 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
1492 opts
->present
|= DL_OPT_SB
;
1495 return dl_args_finding_required_validate(o_required
, o_found
);
1498 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1500 struct dl_opts
*opts
= &dl
->opts
;
1502 if (opts
->present
& DL_OPT_HANDLE
) {
1503 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1504 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1505 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1506 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1507 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1508 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1510 } else if (opts
->present
& DL_OPT_HANDLE_REGION
) {
1511 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1512 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1513 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_REGION_NAME
,
1516 if (opts
->present
& DL_OPT_PORT_TYPE
)
1517 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1519 if (opts
->present
& DL_OPT_PORT_COUNT
)
1520 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1522 if (opts
->present
& DL_OPT_SB
)
1523 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1525 if (opts
->present
& DL_OPT_SB_POOL
)
1526 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1527 opts
->sb_pool_index
);
1528 if (opts
->present
& DL_OPT_SB_SIZE
)
1529 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1530 opts
->sb_pool_size
);
1531 if (opts
->present
& DL_OPT_SB_TYPE
)
1532 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1533 opts
->sb_pool_type
);
1534 if (opts
->present
& DL_OPT_SB_THTYPE
)
1535 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1536 opts
->sb_pool_thtype
);
1537 if (opts
->present
& DL_OPT_SB_TH
)
1538 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1539 opts
->sb_threshold
);
1540 if (opts
->present
& DL_OPT_SB_TC
)
1541 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1543 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1544 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1545 opts
->eswitch_mode
);
1546 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1547 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1548 opts
->eswitch_inline_mode
);
1549 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1550 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1551 opts
->dpipe_table_name
);
1552 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1553 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1554 opts
->dpipe_counters_enable
);
1555 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1556 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1557 opts
->eswitch_encap_mode
);
1558 if ((opts
->present
& DL_OPT_RESOURCE_PATH
) && opts
->resource_id_valid
)
1559 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_ID
,
1561 if (opts
->present
& DL_OPT_RESOURCE_SIZE
)
1562 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_SIZE
,
1563 opts
->resource_size
);
1564 if (opts
->present
& DL_OPT_PARAM_NAME
)
1565 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_NAME
,
1567 if (opts
->present
& DL_OPT_PARAM_CMODE
)
1568 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_CMODE
,
1570 if (opts
->present
& DL_OPT_REGION_SNAPSHOT_ID
)
1571 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_REGION_SNAPSHOT_ID
,
1572 opts
->region_snapshot_id
);
1573 if (opts
->present
& DL_OPT_REGION_ADDRESS
)
1574 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_ADDR
,
1575 opts
->region_address
);
1576 if (opts
->present
& DL_OPT_REGION_LENGTH
)
1577 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_LEN
,
1578 opts
->region_length
);
1579 if (opts
->present
& DL_OPT_FLASH_FILE_NAME
)
1580 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME
,
1581 opts
->flash_file_name
);
1582 if (opts
->present
& DL_OPT_FLASH_COMPONENT
)
1583 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
,
1584 opts
->flash_component
);
1585 if (opts
->present
& DL_OPT_HEALTH_REPORTER_NAME
)
1586 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
1587 opts
->reporter_name
);
1588 if (opts
->present
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)
1589 mnl_attr_put_u64(nlh
,
1590 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
,
1591 opts
->reporter_graceful_period
);
1592 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)
1593 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
,
1594 opts
->reporter_auto_recover
);
1595 if (opts
->present
& DL_OPT_TRAP_NAME
)
1596 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_NAME
,
1598 if (opts
->present
& DL_OPT_TRAP_GROUP_NAME
)
1599 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_GROUP_NAME
,
1600 opts
->trap_group_name
);
1601 if (opts
->present
& DL_OPT_TRAP_ACTION
)
1602 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_TRAP_ACTION
,
1604 if (opts
->present
& DL_OPT_NETNS
)
1605 mnl_attr_put_u32(nlh
,
1606 opts
->netns_is_pid
? DEVLINK_ATTR_NETNS_PID
:
1607 DEVLINK_ATTR_NETNS_FD
,
1611 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1612 uint64_t o_required
, uint64_t o_optional
)
1616 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1619 dl_opts_put(nlh
, dl
);
1623 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1625 struct dl_opts
*opts
= &dl
->opts
;
1626 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1627 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1628 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1629 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1631 if (opts
->present
& DL_OPT_HANDLE
&&
1632 attr_bus_name
&& attr_dev_name
) {
1633 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1634 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1636 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1637 strcmp(dev_name
, opts
->dev_name
) != 0)
1640 if (opts
->present
& DL_OPT_HANDLEP
&&
1641 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1642 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1643 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1644 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1646 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1647 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1648 port_index
!= opts
->port_index
)
1651 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1652 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1654 if (sb_index
!= opts
->sb_index
)
1660 static void cmd_dev_help(void)
1662 pr_err("Usage: devlink dev show [ DEV ]\n");
1663 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1664 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1665 pr_err(" [ encap { disable | enable } ]\n");
1666 pr_err(" devlink dev eswitch show DEV\n");
1667 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1668 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1669 pr_err(" devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
1670 pr_err(" devlink dev info [ DEV ]\n");
1671 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1674 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1675 const char *dev_name
)
1677 if (!dl
->arr_last
.present
)
1679 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1680 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1683 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1684 const char *dev_name
)
1686 dl
->arr_last
.present
= true;
1687 free(dl
->arr_last
.dev_name
);
1688 free(dl
->arr_last
.bus_name
);
1689 dl
->arr_last
.bus_name
= strdup(bus_name
);
1690 dl
->arr_last
.dev_name
= strdup(dev_name
);
1693 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1694 const char *dev_name
)
1696 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1699 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1700 const char *dev_name
)
1702 return dl
->arr_last
.present
&&
1703 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1706 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1707 bool content
, bool array
)
1709 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1710 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1713 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
1715 if (dl
->json_output
) {
1717 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1718 jsonw_end_array(dl
->jw
);
1719 if (should_arr_last_handle_start(dl
, bus_name
,
1721 jsonw_name(dl
->jw
, buf
);
1722 jsonw_start_array(dl
->jw
);
1723 jsonw_start_object(dl
->jw
);
1724 arr_last_handle_set(dl
, bus_name
, dev_name
);
1726 jsonw_start_object(dl
->jw
);
1729 jsonw_name(dl
->jw
, buf
);
1730 jsonw_start_object(dl
->jw
);
1734 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1735 __pr_out_indent_dec();
1736 if (should_arr_last_handle_start(dl
, bus_name
,
1738 pr_out("%s%s", buf
, content
? ":" : "");
1740 __pr_out_indent_inc();
1741 arr_last_handle_set(dl
, bus_name
, dev_name
);
1744 pr_out("%s%s", buf
, content
? ":" : "");
1749 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
1751 __pr_out_handle_start(dl
, tb
, true, true);
1754 static void pr_out_handle_end(struct dl
*dl
)
1756 if (dl
->json_output
)
1757 jsonw_end_object(dl
->jw
);
1762 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
1764 __pr_out_handle_start(dl
, tb
, false, false);
1765 pr_out_handle_end(dl
);
1768 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
1769 const char *dev_name
, uint32_t port_index
)
1771 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
1772 dl
->arr_last
.port_index
== port_index
;
1775 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
1776 const char *dev_name
, uint32_t port_index
)
1778 arr_last_handle_set(dl
, bus_name
, dev_name
);
1779 dl
->arr_last
.port_index
= port_index
;
1782 static bool should_arr_last_port_handle_start(struct dl
*dl
,
1783 const char *bus_name
,
1784 const char *dev_name
,
1785 uint32_t port_index
)
1787 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1790 static bool should_arr_last_port_handle_end(struct dl
*dl
,
1791 const char *bus_name
,
1792 const char *dev_name
,
1793 uint32_t port_index
)
1795 return dl
->arr_last
.present
&&
1796 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1799 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
1800 const char *dev_name
,
1801 uint32_t port_index
, bool try_nice
,
1804 static char buf
[64];
1805 char *ifname
= NULL
;
1807 if (dl
->no_nice_names
|| !try_nice
||
1808 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
1809 port_index
, &ifname
) != 0)
1810 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
1812 sprintf(buf
, "%s", ifname
);
1814 if (dl
->json_output
) {
1816 if (should_arr_last_port_handle_end(dl
, bus_name
,
1819 jsonw_end_array(dl
->jw
);
1820 if (should_arr_last_port_handle_start(dl
, bus_name
,
1823 jsonw_name(dl
->jw
, buf
);
1824 jsonw_start_array(dl
->jw
);
1825 jsonw_start_object(dl
->jw
);
1826 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
1829 jsonw_start_object(dl
->jw
);
1832 jsonw_name(dl
->jw
, buf
);
1833 jsonw_start_object(dl
->jw
);
1840 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1842 const char *bus_name
;
1843 const char *dev_name
;
1844 uint32_t port_index
;
1846 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1847 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1848 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1849 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
1852 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1854 const char *bus_name
;
1855 const char *dev_name
;
1856 uint32_t port_index
;
1858 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1859 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1860 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1861 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
1864 static void pr_out_port_handle_end(struct dl
*dl
)
1866 if (dl
->json_output
)
1867 jsonw_end_object(dl
->jw
);
1873 static void pr_out_str(struct dl
*dl
, const char *name
, const char *val
)
1875 __pr_out_indent_newline(dl
);
1876 if (dl
->json_output
)
1877 jsonw_string_field(dl
->jw
, name
, val
);
1879 pr_out("%s %s", name
, val
);
1882 static void pr_out_bool(struct dl
*dl
, const char *name
, bool val
)
1884 if (dl
->json_output
)
1885 jsonw_bool_field(dl
->jw
, name
, val
);
1887 pr_out_str(dl
, name
, val
? "true" : "false");
1890 static void pr_out_uint(struct dl
*dl
, const char *name
, unsigned int val
)
1892 __pr_out_indent_newline(dl
);
1893 if (dl
->json_output
)
1894 jsonw_uint_field(dl
->jw
, name
, val
);
1896 pr_out("%s %u", name
, val
);
1899 static void pr_out_u64(struct dl
*dl
, const char *name
, uint64_t val
)
1901 __pr_out_indent_newline(dl
);
1902 if (val
== (uint64_t) -1)
1903 return pr_out_str(dl
, name
, "unlimited");
1905 if (dl
->json_output
)
1906 jsonw_u64_field(dl
->jw
, name
, val
);
1908 pr_out("%s %"PRIu64
, name
, val
);
1911 static void pr_out_bool_value(struct dl
*dl
, bool value
)
1913 __pr_out_indent_newline(dl
);
1914 if (dl
->json_output
)
1915 jsonw_bool(dl
->jw
, value
);
1917 pr_out("%s", value
? "true" : "false");
1920 static void pr_out_uint_value(struct dl
*dl
, unsigned int value
)
1922 __pr_out_indent_newline(dl
);
1923 if (dl
->json_output
)
1924 jsonw_uint(dl
->jw
, value
);
1926 pr_out("%u", value
);
1929 static void pr_out_uint64_value(struct dl
*dl
, uint64_t value
)
1931 __pr_out_indent_newline(dl
);
1932 if (dl
->json_output
)
1933 jsonw_u64(dl
->jw
, value
);
1935 pr_out("%"PRIu64
, value
);
1938 static bool is_binary_eol(int i
)
1943 static void pr_out_binary_value(struct dl
*dl
, uint8_t *data
, uint32_t len
)
1948 if (dl
->json_output
)
1949 jsonw_printf(dl
->jw
, "%d", data
[i
]);
1951 pr_out("%02x ", data
[i
]);
1953 if (!dl
->json_output
&& is_binary_eol(i
))
1956 if (!dl
->json_output
&& !is_binary_eol(i
))
1960 static void pr_out_str_value(struct dl
*dl
, const char *value
)
1962 __pr_out_indent_newline(dl
);
1963 if (dl
->json_output
)
1964 jsonw_string(dl
->jw
, value
);
1966 pr_out("%s", value
);
1969 static void pr_out_name(struct dl
*dl
, const char *name
)
1971 __pr_out_indent_newline(dl
);
1972 if (dl
->json_output
)
1973 jsonw_name(dl
->jw
, name
);
1975 pr_out("%s:", name
);
1978 static void pr_out_region_chunk_start(struct dl
*dl
, uint64_t addr
)
1980 if (dl
->json_output
) {
1981 jsonw_name(dl
->jw
, "address");
1982 jsonw_uint(dl
->jw
, addr
);
1983 jsonw_name(dl
->jw
, "data");
1984 jsonw_start_array(dl
->jw
);
1988 static void pr_out_region_chunk_end(struct dl
*dl
)
1990 if (dl
->json_output
)
1991 jsonw_end_array(dl
->jw
);
1994 static void pr_out_region_chunk(struct dl
*dl
, uint8_t *data
, uint32_t len
,
1997 static uint64_t align_val
;
2000 pr_out_region_chunk_start(dl
, addr
);
2002 if (!dl
->json_output
)
2003 if (!(align_val
% 16))
2004 pr_out("%s%016"PRIx64
" ",
2005 align_val
? "\n" : "",
2010 if (dl
->json_output
)
2011 jsonw_printf(dl
->jw
, "%d", data
[i
]);
2013 pr_out("%02x ", data
[i
]);
2018 pr_out_region_chunk_end(dl
);
2021 static void pr_out_section_start(struct dl
*dl
, const char *name
)
2023 if (dl
->json_output
) {
2024 jsonw_start_object(dl
->jw
);
2025 jsonw_name(dl
->jw
, name
);
2026 jsonw_start_object(dl
->jw
);
2030 static void pr_out_section_end(struct dl
*dl
)
2032 if (dl
->json_output
) {
2033 if (dl
->arr_last
.present
)
2034 jsonw_end_array(dl
->jw
);
2035 jsonw_end_object(dl
->jw
);
2036 jsonw_end_object(dl
->jw
);
2040 static void pr_out_array_start(struct dl
*dl
, const char *name
)
2042 if (dl
->json_output
) {
2043 jsonw_name(dl
->jw
, name
);
2044 jsonw_start_array(dl
->jw
);
2046 __pr_out_indent_inc();
2048 pr_out("%s:", name
);
2049 __pr_out_indent_inc();
2054 static void pr_out_array_end(struct dl
*dl
)
2056 if (dl
->json_output
) {
2057 jsonw_end_array(dl
->jw
);
2059 __pr_out_indent_dec();
2060 __pr_out_indent_dec();
2064 static void pr_out_object_start(struct dl
*dl
, const char *name
)
2066 if (dl
->json_output
) {
2067 jsonw_name(dl
->jw
, name
);
2068 jsonw_start_object(dl
->jw
);
2070 __pr_out_indent_inc();
2072 pr_out("%s:", name
);
2073 __pr_out_indent_inc();
2078 static void pr_out_object_end(struct dl
*dl
)
2080 if (dl
->json_output
) {
2081 jsonw_end_object(dl
->jw
);
2083 __pr_out_indent_dec();
2084 __pr_out_indent_dec();
2088 static void pr_out_entry_start(struct dl
*dl
)
2090 if (dl
->json_output
)
2091 jsonw_start_object(dl
->jw
);
2094 static void pr_out_entry_end(struct dl
*dl
)
2096 if (dl
->json_output
)
2097 jsonw_end_object(dl
->jw
);
2102 static void pr_out_stats(struct dl
*dl
, struct nlattr
*nla_stats
)
2104 struct nlattr
*tb
[DEVLINK_ATTR_STATS_MAX
+ 1] = {};
2110 err
= mnl_attr_parse_nested(nla_stats
, attr_stats_cb
, tb
);
2111 if (err
!= MNL_CB_OK
)
2114 pr_out_object_start(dl
, "stats");
2115 pr_out_object_start(dl
, "rx");
2116 if (tb
[DEVLINK_ATTR_STATS_RX_BYTES
])
2117 pr_out_u64(dl
, "bytes",
2118 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_BYTES
]));
2119 if (tb
[DEVLINK_ATTR_STATS_RX_PACKETS
])
2120 pr_out_u64(dl
, "packets",
2121 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_PACKETS
]));
2122 pr_out_object_end(dl
);
2123 pr_out_object_end(dl
);
2126 static const char *param_cmode_name(uint8_t cmode
)
2129 case DEVLINK_PARAM_CMODE_RUNTIME
:
2130 return PARAM_CMODE_RUNTIME_STR
;
2131 case DEVLINK_PARAM_CMODE_DRIVERINIT
:
2132 return PARAM_CMODE_DRIVERINIT_STR
;
2133 case DEVLINK_PARAM_CMODE_PERMANENT
:
2134 return PARAM_CMODE_PERMANENT_STR
;
2135 default: return "<unknown type>";
2139 static const char *eswitch_mode_name(uint32_t mode
)
2142 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
2143 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
2144 default: return "<unknown mode>";
2148 static const char *eswitch_inline_mode_name(uint32_t mode
)
2151 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
2152 return ESWITCH_INLINE_MODE_NONE
;
2153 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
2154 return ESWITCH_INLINE_MODE_LINK
;
2155 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
2156 return ESWITCH_INLINE_MODE_NETWORK
;
2157 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
2158 return ESWITCH_INLINE_MODE_TRANSPORT
;
2160 return "<unknown mode>";
2164 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
2166 __pr_out_handle_start(dl
, tb
, true, false);
2168 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
])
2169 pr_out_str(dl
, "mode",
2170 eswitch_mode_name(mnl_attr_get_u16(tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
2172 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])
2173 pr_out_str(dl
, "inline-mode",
2174 eswitch_inline_mode_name(mnl_attr_get_u8(
2175 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
2177 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
2178 bool encap_mode
= !!mnl_attr_get_u8(tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]);
2180 pr_out_str(dl
, "encap", encap_mode
? "enable" : "disable");
2183 pr_out_handle_end(dl
);
2186 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2188 struct dl
*dl
= data
;
2189 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2190 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2192 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2193 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2194 return MNL_CB_ERROR
;
2195 pr_out_eswitch(dl
, tb
);
2199 static int cmd_dev_eswitch_show(struct dl
*dl
)
2201 struct nlmsghdr
*nlh
;
2204 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
2205 NLM_F_REQUEST
| NLM_F_ACK
);
2207 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2211 pr_out_section_start(dl
, "dev");
2212 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
2213 pr_out_section_end(dl
);
2217 static int cmd_dev_eswitch_set(struct dl
*dl
)
2219 struct nlmsghdr
*nlh
;
2222 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
2223 NLM_F_REQUEST
| NLM_F_ACK
);
2225 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
2226 DL_OPT_ESWITCH_MODE
|
2227 DL_OPT_ESWITCH_INLINE_MODE
|
2228 DL_OPT_ESWITCH_ENCAP_MODE
);
2233 if (dl
->opts
.present
== 1) {
2234 pr_err("Need to set at least one option\n");
2238 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2241 static int cmd_dev_eswitch(struct dl
*dl
)
2243 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2246 } else if (dl_argv_match(dl
, "set")) {
2248 return cmd_dev_eswitch_set(dl
);
2249 } else if (dl_argv_match(dl
, "show")) {
2251 return cmd_dev_eswitch_show(dl
);
2253 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2257 struct param_val_conv
{
2263 static bool param_val_conv_exists(const struct param_val_conv
*param_val_conv
,
2264 uint32_t len
, const char *name
)
2268 for (i
= 0; i
< len
; i
++)
2269 if (!strcmp(param_val_conv
[i
].name
, name
))
2276 param_val_conv_uint_get(const struct param_val_conv
*param_val_conv
,
2277 uint32_t len
, const char *name
, const char *vstr
,
2282 for (i
= 0; i
< len
; i
++)
2283 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2284 !strcmp(param_val_conv
[i
].vstr
, vstr
)) {
2285 *vuint
= param_val_conv
[i
].vuint
;
2293 param_val_conv_str_get(const struct param_val_conv
*param_val_conv
,
2294 uint32_t len
, const char *name
, uint32_t vuint
,
2299 for (i
= 0; i
< len
; i
++)
2300 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2301 param_val_conv
[i
].vuint
== vuint
) {
2302 *vstr
= param_val_conv
[i
].vstr
;
2309 static const struct param_val_conv param_val_conv
[] = {
2311 .name
= "fw_load_policy",
2313 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER
,
2316 .name
= "fw_load_policy",
2318 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH
,
2321 .name
= "reset_dev_on_drv_probe",
2323 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN
,
2326 .name
= "fw_load_policy",
2328 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN
,
2331 .name
= "reset_dev_on_drv_probe",
2333 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS
,
2336 .name
= "reset_dev_on_drv_probe",
2338 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER
,
2341 .name
= "reset_dev_on_drv_probe",
2343 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK
,
2347 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2349 static void pr_out_param_value(struct dl
*dl
, const char *nla_name
,
2350 int nla_type
, struct nlattr
*nl
)
2352 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2353 struct nlattr
*val_attr
;
2358 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_value
);
2359 if (err
!= MNL_CB_OK
)
2362 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2363 (nla_type
!= MNL_TYPE_FLAG
&&
2364 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2367 pr_out_str(dl
, "cmode",
2368 param_cmode_name(mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
])));
2369 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2371 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2377 err
= param_val_conv_str_get(param_val_conv
,
2380 mnl_attr_get_u8(val_attr
),
2384 pr_out_str(dl
, "value", vstr
);
2386 pr_out_uint(dl
, "value", mnl_attr_get_u8(val_attr
));
2391 err
= param_val_conv_str_get(param_val_conv
,
2394 mnl_attr_get_u16(val_attr
),
2398 pr_out_str(dl
, "value", vstr
);
2400 pr_out_uint(dl
, "value", mnl_attr_get_u16(val_attr
));
2405 err
= param_val_conv_str_get(param_val_conv
,
2408 mnl_attr_get_u32(val_attr
),
2412 pr_out_str(dl
, "value", vstr
);
2414 pr_out_uint(dl
, "value", mnl_attr_get_u32(val_attr
));
2417 case MNL_TYPE_STRING
:
2418 pr_out_str(dl
, "value", mnl_attr_get_str(val_attr
));
2421 pr_out_bool(dl
, "value", val_attr
? true : false);
2426 static void pr_out_param(struct dl
*dl
, struct nlattr
**tb
, bool array
)
2428 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2429 struct nlattr
*param_value_attr
;
2430 const char *nla_name
;
2434 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2435 if (err
!= MNL_CB_OK
)
2437 if (!nla_param
[DEVLINK_ATTR_PARAM_NAME
] ||
2438 !nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2439 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2443 pr_out_handle_start_arr(dl
, tb
);
2445 __pr_out_handle_start(dl
, tb
, true, false);
2447 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2449 nla_name
= mnl_attr_get_str(nla_param
[DEVLINK_ATTR_PARAM_NAME
]);
2450 pr_out_str(dl
, "name", nla_name
);
2452 if (!nla_param
[DEVLINK_ATTR_PARAM_GENERIC
])
2453 pr_out_str(dl
, "type", "driver-specific");
2455 pr_out_str(dl
, "type", "generic");
2457 pr_out_array_start(dl
, "values");
2458 mnl_attr_for_each_nested(param_value_attr
,
2459 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2460 pr_out_entry_start(dl
);
2461 pr_out_param_value(dl
, nla_name
, nla_type
, param_value_attr
);
2462 pr_out_entry_end(dl
);
2464 pr_out_array_end(dl
);
2465 pr_out_handle_end(dl
);
2468 static int cmd_dev_param_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2470 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2471 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2472 struct dl
*dl
= data
;
2474 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2475 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2476 !tb
[DEVLINK_ATTR_PARAM
])
2477 return MNL_CB_ERROR
;
2478 pr_out_param(dl
, tb
, true);
2494 static int cmd_dev_param_set_cb(const struct nlmsghdr
*nlh
, void *data
)
2496 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2497 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2498 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2499 struct nlattr
*param_value_attr
;
2500 enum devlink_param_cmode cmode
;
2501 struct param_ctx
*ctx
= data
;
2502 struct dl
*dl
= ctx
->dl
;
2506 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2507 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2508 !tb
[DEVLINK_ATTR_PARAM
])
2509 return MNL_CB_ERROR
;
2511 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2512 if (err
!= MNL_CB_OK
)
2513 return MNL_CB_ERROR
;
2515 if (!nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2516 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2517 return MNL_CB_ERROR
;
2519 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2520 mnl_attr_for_each_nested(param_value_attr
,
2521 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2522 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2523 struct nlattr
*val_attr
;
2525 err
= mnl_attr_parse_nested(param_value_attr
,
2526 attr_cb
, nla_value
);
2527 if (err
!= MNL_CB_OK
)
2528 return MNL_CB_ERROR
;
2530 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2531 (nla_type
!= MNL_TYPE_FLAG
&&
2532 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2533 return MNL_CB_ERROR
;
2535 cmode
= mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
]);
2536 if (cmode
== dl
->opts
.cmode
) {
2537 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2540 ctx
->value
.vu8
= mnl_attr_get_u8(val_attr
);
2543 ctx
->value
.vu16
= mnl_attr_get_u16(val_attr
);
2546 ctx
->value
.vu32
= mnl_attr_get_u32(val_attr
);
2548 case MNL_TYPE_STRING
:
2549 ctx
->value
.vstr
= mnl_attr_get_str(val_attr
);
2552 ctx
->value
.vbool
= val_attr
? true : false;
2558 ctx
->nla_type
= nla_type
;
2562 static int cmd_dev_param_set(struct dl
*dl
)
2564 struct param_ctx ctx
= {};
2565 struct nlmsghdr
*nlh
;
2573 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
|
2575 DL_OPT_PARAM_VALUE
|
2576 DL_OPT_PARAM_CMODE
, 0);
2580 /* Get value type */
2581 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
,
2582 NLM_F_REQUEST
| NLM_F_ACK
);
2583 dl_opts_put(nlh
, dl
);
2586 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_set_cb
, &ctx
);
2590 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_SET
,
2591 NLM_F_REQUEST
| NLM_F_ACK
);
2592 dl_opts_put(nlh
, dl
);
2594 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2595 dl
->opts
.param_name
);
2597 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_TYPE
, ctx
.nla_type
);
2598 switch (ctx
.nla_type
) {
2601 err
= param_val_conv_uint_get(param_val_conv
,
2603 dl
->opts
.param_name
,
2604 dl
->opts
.param_value
,
2608 err
= strtouint8_t(dl
->opts
.param_value
, &val_u8
);
2611 goto err_param_value_parse
;
2612 if (val_u8
== ctx
.value
.vu8
)
2614 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u8
);
2618 err
= param_val_conv_uint_get(param_val_conv
,
2620 dl
->opts
.param_name
,
2621 dl
->opts
.param_value
,
2625 err
= strtouint16_t(dl
->opts
.param_value
, &val_u16
);
2628 goto err_param_value_parse
;
2629 if (val_u16
== ctx
.value
.vu16
)
2631 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u16
);
2635 err
= param_val_conv_uint_get(param_val_conv
,
2637 dl
->opts
.param_name
,
2638 dl
->opts
.param_value
,
2641 err
= strtouint32_t(dl
->opts
.param_value
, &val_u32
);
2643 goto err_param_value_parse
;
2644 if (val_u32
== ctx
.value
.vu32
)
2646 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u32
);
2649 err
= strtobool(dl
->opts
.param_value
, &val_bool
);
2651 goto err_param_value_parse
;
2652 if (val_bool
== ctx
.value
.vbool
)
2655 mnl_attr_put(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2658 case MNL_TYPE_STRING
:
2659 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2660 dl
->opts
.param_value
);
2661 if (!strcmp(dl
->opts
.param_value
, ctx
.value
.vstr
))
2665 printf("Value type not supported\n");
2668 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2670 err_param_value_parse
:
2671 pr_err("Value \"%s\" is not a number or not within range\n",
2672 dl
->opts
.param_value
);
2676 static int cmd_dev_param_show(struct dl
*dl
)
2678 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2679 struct nlmsghdr
*nlh
;
2682 if (dl_argc(dl
) == 0)
2683 flags
|= NLM_F_DUMP
;
2685 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
, flags
);
2687 if (dl_argc(dl
) > 0) {
2688 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
|
2689 DL_OPT_PARAM_NAME
, 0);
2694 pr_out_section_start(dl
, "param");
2695 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_show_cb
, dl
);
2696 pr_out_section_end(dl
);
2700 static int cmd_dev_param(struct dl
*dl
)
2702 if (dl_argv_match(dl
, "help")) {
2705 } else if (dl_argv_match(dl
, "show") ||
2706 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2708 return cmd_dev_param_show(dl
);
2709 } else if (dl_argv_match(dl
, "set")) {
2711 return cmd_dev_param_set(dl
);
2713 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2716 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2718 struct dl
*dl
= data
;
2719 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2720 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2721 uint8_t reload_failed
= 0;
2723 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2724 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2725 return MNL_CB_ERROR
;
2727 if (tb
[DEVLINK_ATTR_RELOAD_FAILED
])
2728 reload_failed
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_RELOAD_FAILED
]);
2730 if (reload_failed
) {
2731 __pr_out_handle_start(dl
, tb
, true, false);
2732 pr_out_bool(dl
, "reload_failed", true);
2733 pr_out_handle_end(dl
);
2735 pr_out_handle(dl
, tb
);
2741 static int cmd_dev_show(struct dl
*dl
)
2743 struct nlmsghdr
*nlh
;
2744 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2747 if (dl_argc(dl
) == 0)
2748 flags
|= NLM_F_DUMP
;
2750 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
2752 if (dl_argc(dl
) > 0) {
2753 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2758 pr_out_section_start(dl
, "dev");
2759 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
2760 pr_out_section_end(dl
);
2764 static void cmd_dev_reload_help(void)
2766 pr_err("Usage: devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
2769 static int cmd_dev_reload(struct dl
*dl
)
2771 struct nlmsghdr
*nlh
;
2774 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2775 cmd_dev_reload_help();
2779 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RELOAD
,
2780 NLM_F_REQUEST
| NLM_F_ACK
);
2782 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_NETNS
);
2786 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2789 static void pr_out_versions_single(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2790 const char *name
, int type
)
2792 struct nlattr
*version
;
2794 mnl_attr_for_each(version
, nlh
, sizeof(struct genlmsghdr
)) {
2795 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2796 const char *ver_value
;
2797 const char *ver_name
;
2800 if (mnl_attr_get_type(version
) != type
)
2803 err
= mnl_attr_parse_nested(version
, attr_cb
, tb
);
2804 if (err
!= MNL_CB_OK
)
2807 if (!tb
[DEVLINK_ATTR_INFO_VERSION_NAME
] ||
2808 !tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
])
2812 pr_out_object_start(dl
, name
);
2816 ver_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_NAME
]);
2817 ver_value
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
]);
2819 pr_out_str(dl
, ver_name
, ver_value
);
2820 if (!dl
->json_output
)
2825 pr_out_object_end(dl
);
2828 static void pr_out_info(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2829 struct nlattr
**tb
, bool has_versions
)
2831 __pr_out_handle_start(dl
, tb
, true, false);
2833 __pr_out_indent_inc();
2834 if (tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
]) {
2835 struct nlattr
*nla_drv
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
];
2837 if (!dl
->json_output
)
2839 pr_out_str(dl
, "driver", mnl_attr_get_str(nla_drv
));
2842 if (tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
]) {
2843 struct nlattr
*nla_sn
= tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
];
2845 if (!dl
->json_output
)
2847 pr_out_str(dl
, "serial_number", mnl_attr_get_str(nla_sn
));
2849 __pr_out_indent_dec();
2852 pr_out_object_start(dl
, "versions");
2854 pr_out_versions_single(dl
, nlh
, "fixed",
2855 DEVLINK_ATTR_INFO_VERSION_FIXED
);
2856 pr_out_versions_single(dl
, nlh
, "running",
2857 DEVLINK_ATTR_INFO_VERSION_RUNNING
);
2858 pr_out_versions_single(dl
, nlh
, "stored",
2859 DEVLINK_ATTR_INFO_VERSION_STORED
);
2861 pr_out_object_end(dl
);
2864 pr_out_handle_end(dl
);
2867 static int cmd_versions_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2869 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2870 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2871 bool has_versions
, has_info
;
2872 struct dl
*dl
= data
;
2874 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2876 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2877 return MNL_CB_ERROR
;
2879 has_versions
= tb
[DEVLINK_ATTR_INFO_VERSION_FIXED
] ||
2880 tb
[DEVLINK_ATTR_INFO_VERSION_RUNNING
] ||
2881 tb
[DEVLINK_ATTR_INFO_VERSION_STORED
];
2882 has_info
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
] ||
2883 tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
] ||
2887 pr_out_info(dl
, nlh
, tb
, has_versions
);
2892 static void cmd_dev_info_help(void)
2894 pr_err("Usage: devlink dev info [ DEV ]\n");
2897 static int cmd_dev_info(struct dl
*dl
)
2899 struct nlmsghdr
*nlh
;
2900 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2903 if (dl_argv_match(dl
, "help")) {
2904 cmd_dev_info_help();
2908 if (dl_argc(dl
) == 0)
2909 flags
|= NLM_F_DUMP
;
2911 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_INFO_GET
, flags
);
2913 if (dl_argc(dl
) > 0) {
2914 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2919 pr_out_section_start(dl
, "info");
2920 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_versions_show_cb
, dl
);
2921 pr_out_section_end(dl
);
2925 static void cmd_dev_flash_help(void)
2927 pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
2931 struct cmd_dev_flash_status_ctx
{
2934 char *last_component
;
2935 uint8_t not_first
:1,
2941 static int nullstrcmp(const char *str1
, const char *str2
)
2944 return strcmp(str1
, str2
);
2947 return str1
? 1 : -1;
2950 static int cmd_dev_flash_status_cb(const struct nlmsghdr
*nlh
, void *data
)
2952 struct cmd_dev_flash_status_ctx
*ctx
= data
;
2953 struct dl_opts
*opts
= &ctx
->dl
->opts
;
2954 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2955 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2956 const char *component
= NULL
;
2957 uint64_t done
= 0, total
= 0;
2958 const char *msg
= NULL
;
2959 const char *bus_name
;
2960 const char *dev_name
;
2962 if (genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_STATUS
&&
2963 genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_END
)
2966 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2967 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2968 return MNL_CB_ERROR
;
2969 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2970 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2971 if (strcmp(bus_name
, opts
->bus_name
) ||
2972 strcmp(dev_name
, opts
->dev_name
))
2973 return MNL_CB_ERROR
;
2975 if (genl
->cmd
== DEVLINK_CMD_FLASH_UPDATE_END
&& ctx
->not_first
) {
2977 free(ctx
->last_msg
);
2978 free(ctx
->last_component
);
2979 ctx
->received_end
= 1;
2983 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
])
2984 msg
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]);
2985 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
])
2986 component
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]);
2987 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
2988 done
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]);
2989 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
2990 total
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]);
2992 if (!nullstrcmp(msg
, ctx
->last_msg
) &&
2993 !nullstrcmp(component
, ctx
->last_component
) &&
2994 ctx
->last_pc
&& ctx
->not_first
) {
2995 pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3000 pr_out("[%s] ", component
);
3001 free(ctx
->last_component
);
3002 ctx
->last_component
= strdup(component
);
3006 free(ctx
->last_msg
);
3007 ctx
->last_msg
= strdup(msg
);
3011 pr_out_tty(" %3lu%%", (done
* 100) / total
);
3022 static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx
*ctx
,
3023 struct mnlg_socket
*nlg_ntf
,
3026 int nlfd
= mnlg_socket_get_fd(nlg_ntf
);
3033 for (i
= 0; i
< 3; i
++)
3035 FD_SET(pipe_r
, &fds
[0]);
3037 FD_SET(nlfd
, &fds
[0]);
3041 while (select(fdmax
, &fds
[0], &fds
[1], &fds
[2], NULL
) < 0) {
3044 pr_err("select() failed\n");
3047 if (FD_ISSET(nlfd
, &fds
[0])) {
3048 err
= _mnlg_socket_recv_run(nlg_ntf
,
3049 cmd_dev_flash_status_cb
, ctx
);
3053 if (FD_ISSET(pipe_r
, &fds
[0])) {
3054 err
= read(pipe_r
, &err2
, sizeof(err2
));
3056 pr_err("Failed to read pipe\n");
3061 ctx
->flash_done
= 1;
3067 static int cmd_dev_flash(struct dl
*dl
)
3069 struct cmd_dev_flash_status_ctx ctx
= {.dl
= dl
,};
3070 struct mnlg_socket
*nlg_ntf
;
3071 struct nlmsghdr
*nlh
;
3077 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3078 cmd_dev_flash_help();
3082 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_FLASH_UPDATE
,
3083 NLM_F_REQUEST
| NLM_F_ACK
);
3085 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_FLASH_FILE_NAME
,
3086 DL_OPT_FLASH_COMPONENT
);
3090 nlg_ntf
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
3094 err
= _mnlg_socket_group_add(nlg_ntf
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
3098 err
= pipe(pipe_fds
);
3101 pipe_r
= pipe_fds
[0];
3102 pipe_w
= pipe_fds
[1];
3110 /* In child, just execute the flash and pass returned
3111 * value through pipe once it is done.
3114 err
= _mnlg_socket_send(dl
->nlg
, nlh
);
3115 write(pipe_w
, &err
, sizeof(err
));
3122 err
= cmd_dev_flash_fds_process(&ctx
, nlg_ntf
, pipe_r
);
3125 } while (!ctx
.flash_done
|| (ctx
.not_first
&& !ctx
.received_end
));
3127 err
= _mnlg_socket_recv_run(dl
->nlg
, NULL
, NULL
);
3130 mnlg_socket_close(nlg_ntf
);
3134 static int cmd_dev(struct dl
*dl
)
3136 if (dl_argv_match(dl
, "help")) {
3139 } else if (dl_argv_match(dl
, "show") ||
3140 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3142 return cmd_dev_show(dl
);
3143 } else if (dl_argv_match(dl
, "eswitch")) {
3145 return cmd_dev_eswitch(dl
);
3146 } else if (dl_argv_match(dl
, "reload")) {
3148 return cmd_dev_reload(dl
);
3149 } else if (dl_argv_match(dl
, "param")) {
3151 return cmd_dev_param(dl
);
3152 } else if (dl_argv_match(dl
, "info")) {
3154 return cmd_dev_info(dl
);
3155 } else if (dl_argv_match(dl
, "flash")) {
3157 return cmd_dev_flash(dl
);
3159 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3163 static void cmd_port_help(void)
3165 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3166 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3167 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3168 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3171 static const char *port_type_name(uint32_t type
)
3174 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
3175 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
3176 case DEVLINK_PORT_TYPE_ETH
: return "eth";
3177 case DEVLINK_PORT_TYPE_IB
: return "ib";
3178 default: return "<unknown type>";
3182 static const char *port_flavour_name(uint16_t flavour
)
3185 case DEVLINK_PORT_FLAVOUR_PHYSICAL
:
3187 case DEVLINK_PORT_FLAVOUR_CPU
:
3189 case DEVLINK_PORT_FLAVOUR_DSA
:
3191 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3193 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3196 return "<unknown flavour>";
3200 static void pr_out_port_pfvf_num(struct dl
*dl
, struct nlattr
**tb
)
3204 if (tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]) {
3205 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]);
3206 pr_out_uint(dl
, "pfnum", fn_num
);
3208 if (tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]) {
3209 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]);
3210 pr_out_uint(dl
, "vfnum", fn_num
);
3214 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
3216 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
3217 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
3219 pr_out_port_handle_start(dl
, tb
, false);
3221 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
3223 pr_out_str(dl
, "type", port_type_name(port_type
));
3225 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
3227 if (port_type
!= des_port_type
)
3228 pr_out_str(dl
, "des_type",
3229 port_type_name(des_port_type
));
3232 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
3233 pr_out_str(dl
, "netdev",
3234 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
3235 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
])
3236 pr_out_str(dl
, "ibdev",
3237 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
3238 if (tb
[DEVLINK_ATTR_PORT_FLAVOUR
]) {
3239 uint16_t port_flavour
=
3240 mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_FLAVOUR
]);
3242 pr_out_str(dl
, "flavour", port_flavour_name(port_flavour
));
3244 switch (port_flavour
) {
3245 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3246 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3247 pr_out_port_pfvf_num(dl
, tb
);
3253 if (tb
[DEVLINK_ATTR_PORT_NUMBER
]) {
3254 uint32_t port_number
;
3256 port_number
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_NUMBER
]);
3257 pr_out_uint(dl
, "port", port_number
);
3259 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
3260 pr_out_uint(dl
, "split_group",
3261 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
3262 pr_out_port_handle_end(dl
);
3265 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3267 struct dl
*dl
= data
;
3268 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3269 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3271 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3272 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3273 !tb
[DEVLINK_ATTR_PORT_INDEX
])
3274 return MNL_CB_ERROR
;
3275 pr_out_port(dl
, tb
);
3279 static int cmd_port_show(struct dl
*dl
)
3281 struct nlmsghdr
*nlh
;
3282 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3285 if (dl_argc(dl
) == 0)
3286 flags
|= NLM_F_DUMP
;
3288 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
3290 if (dl_argc(dl
) > 0) {
3291 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3296 pr_out_section_start(dl
, "port");
3297 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
3298 pr_out_section_end(dl
);
3302 static int cmd_port_set(struct dl
*dl
)
3304 struct nlmsghdr
*nlh
;
3307 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
3308 NLM_F_REQUEST
| NLM_F_ACK
);
3310 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
3314 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3317 static int cmd_port_split(struct dl
*dl
)
3319 struct nlmsghdr
*nlh
;
3322 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
3323 NLM_F_REQUEST
| NLM_F_ACK
);
3325 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
3329 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3332 static int cmd_port_unsplit(struct dl
*dl
)
3334 struct nlmsghdr
*nlh
;
3337 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
3338 NLM_F_REQUEST
| NLM_F_ACK
);
3340 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3344 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3347 static int cmd_port(struct dl
*dl
)
3349 if (dl_argv_match(dl
, "help")) {
3352 } else if (dl_argv_match(dl
, "show") ||
3353 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3355 return cmd_port_show(dl
);
3356 } else if (dl_argv_match(dl
, "set")) {
3358 return cmd_port_set(dl
);
3359 } else if (dl_argv_match(dl
, "split")) {
3361 return cmd_port_split(dl
);
3362 } else if (dl_argv_match(dl
, "unsplit")) {
3364 return cmd_port_unsplit(dl
);
3366 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3370 static void cmd_sb_help(void)
3372 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
3373 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
3374 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
3375 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
3376 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3377 pr_err(" pool POOL_INDEX ]\n");
3378 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3379 pr_err(" pool POOL_INDEX th THRESHOLD\n");
3380 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3381 pr_err(" type { ingress | egress } ]\n");
3382 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3383 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
3384 pr_err(" th THRESHOLD\n");
3385 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
3386 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
3387 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
3390 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
3392 pr_out_handle_start_arr(dl
, tb
);
3393 pr_out_uint(dl
, "sb",
3394 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3395 pr_out_uint(dl
, "size",
3396 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
3397 pr_out_uint(dl
, "ing_pools",
3398 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
3399 pr_out_uint(dl
, "eg_pools",
3400 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
3401 pr_out_uint(dl
, "ing_tcs",
3402 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
3403 pr_out_uint(dl
, "eg_tcs",
3404 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
3405 pr_out_handle_end(dl
);
3408 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3410 struct dl
*dl
= data
;
3411 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3412 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3414 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3415 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3416 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
3417 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
3418 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
3419 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
3420 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
3421 return MNL_CB_ERROR
;
3426 static int cmd_sb_show(struct dl
*dl
)
3428 struct nlmsghdr
*nlh
;
3429 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3432 if (dl_argc(dl
) == 0)
3433 flags
|= NLM_F_DUMP
;
3435 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
3437 if (dl_argc(dl
) > 0) {
3438 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3443 pr_out_section_start(dl
, "sb");
3444 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
3445 pr_out_section_end(dl
);
3449 static const char *pool_type_name(uint8_t type
)
3452 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
3453 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
3454 default: return "<unknown type>";
3458 static const char *threshold_type_name(uint8_t type
)
3461 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
3462 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
3463 default: return "<unknown type>";
3467 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
3469 pr_out_handle_start_arr(dl
, tb
);
3470 pr_out_uint(dl
, "sb",
3471 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3472 pr_out_uint(dl
, "pool",
3473 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3474 pr_out_str(dl
, "type",
3475 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3476 pr_out_uint(dl
, "size",
3477 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
3478 pr_out_str(dl
, "thtype",
3479 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
3480 if (tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
])
3481 pr_out_uint(dl
, "cell_size",
3482 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
]));
3483 pr_out_handle_end(dl
);
3486 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3488 struct dl
*dl
= data
;
3489 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3490 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3492 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3493 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3494 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3495 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
3496 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
3497 return MNL_CB_ERROR
;
3498 pr_out_sb_pool(dl
, tb
);
3502 static int cmd_sb_pool_show(struct dl
*dl
)
3504 struct nlmsghdr
*nlh
;
3505 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3508 if (dl_argc(dl
) == 0)
3509 flags
|= NLM_F_DUMP
;
3511 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
3513 if (dl_argc(dl
) > 0) {
3514 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
3520 pr_out_section_start(dl
, "pool");
3521 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
3522 pr_out_section_end(dl
);
3526 static int cmd_sb_pool_set(struct dl
*dl
)
3528 struct nlmsghdr
*nlh
;
3531 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
3532 NLM_F_REQUEST
| NLM_F_ACK
);
3534 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
3535 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
3539 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3542 static int cmd_sb_pool(struct dl
*dl
)
3544 if (dl_argv_match(dl
, "help")) {
3547 } else if (dl_argv_match(dl
, "show") ||
3548 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3550 return cmd_sb_pool_show(dl
);
3551 } else if (dl_argv_match(dl
, "set")) {
3553 return cmd_sb_pool_set(dl
);
3555 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3559 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
3561 pr_out_port_handle_start_arr(dl
, tb
, true);
3562 pr_out_uint(dl
, "sb",
3563 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3564 pr_out_uint(dl
, "pool",
3565 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3566 pr_out_uint(dl
, "threshold",
3567 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3568 pr_out_port_handle_end(dl
);
3571 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3573 struct dl
*dl
= data
;
3574 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3575 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3577 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3578 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3579 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3580 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3581 return MNL_CB_ERROR
;
3582 pr_out_sb_port_pool(dl
, tb
);
3586 static int cmd_sb_port_pool_show(struct dl
*dl
)
3588 struct nlmsghdr
*nlh
;
3589 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3592 if (dl_argc(dl
) == 0)
3593 flags
|= NLM_F_DUMP
;
3595 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3597 if (dl_argc(dl
) > 0) {
3598 err
= dl_argv_parse_put(nlh
, dl
,
3599 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
3605 pr_out_section_start(dl
, "port_pool");
3606 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
3607 pr_out_section_end(dl
);
3611 static int cmd_sb_port_pool_set(struct dl
*dl
)
3613 struct nlmsghdr
*nlh
;
3616 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
3617 NLM_F_REQUEST
| NLM_F_ACK
);
3619 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
3620 DL_OPT_SB_TH
, DL_OPT_SB
);
3624 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3627 static int cmd_sb_port_pool(struct dl
*dl
)
3629 if (dl_argv_match(dl
, "help")) {
3632 } else if (dl_argv_match(dl
, "show") ||
3633 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3635 return cmd_sb_port_pool_show(dl
);
3636 } else if (dl_argv_match(dl
, "set")) {
3638 return cmd_sb_port_pool_set(dl
);
3640 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3644 static int cmd_sb_port(struct dl
*dl
)
3646 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3649 } else if (dl_argv_match(dl
, "pool")) {
3651 return cmd_sb_port_pool(dl
);
3653 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3657 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
3659 pr_out_port_handle_start_arr(dl
, tb
, true);
3660 pr_out_uint(dl
, "sb",
3661 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3662 pr_out_uint(dl
, "tc",
3663 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
3664 pr_out_str(dl
, "type",
3665 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3666 pr_out_uint(dl
, "pool",
3667 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3668 pr_out_uint(dl
, "threshold",
3669 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3670 pr_out_port_handle_end(dl
);
3673 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3675 struct dl
*dl
= data
;
3676 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3677 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3679 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3680 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3681 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3682 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3683 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3684 return MNL_CB_ERROR
;
3685 pr_out_sb_tc_bind(dl
, tb
);
3689 static int cmd_sb_tc_bind_show(struct dl
*dl
)
3691 struct nlmsghdr
*nlh
;
3692 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3695 if (dl_argc(dl
) == 0)
3696 flags
|= NLM_F_DUMP
;
3698 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3700 if (dl_argc(dl
) > 0) {
3701 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3702 DL_OPT_SB_TYPE
, DL_OPT_SB
);
3707 pr_out_section_start(dl
, "tc_bind");
3708 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
3709 pr_out_section_end(dl
);
3713 static int cmd_sb_tc_bind_set(struct dl
*dl
)
3715 struct nlmsghdr
*nlh
;
3718 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
3719 NLM_F_REQUEST
| NLM_F_ACK
);
3721 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3722 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
3727 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3730 static int cmd_sb_tc_bind(struct dl
*dl
)
3732 if (dl_argv_match(dl
, "help")) {
3735 } else if (dl_argv_match(dl
, "show") ||
3736 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3738 return cmd_sb_tc_bind_show(dl
);
3739 } else if (dl_argv_match(dl
, "set")) {
3741 return cmd_sb_tc_bind_set(dl
);
3743 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3747 static int cmd_sb_tc(struct dl
*dl
)
3749 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3752 } else if (dl_argv_match(dl
, "bind")) {
3754 return cmd_sb_tc_bind(dl
);
3756 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3761 struct list_head list
;
3765 uint32_t bound_pool_index
;
3769 struct list_head list
;
3772 uint32_t port_index
;
3774 struct list_head pool_list
;
3775 struct list_head ing_tc_list
;
3776 struct list_head eg_tc_list
;
3782 struct list_head port_list
;
3785 static struct occ_item
*occ_item_alloc(void)
3787 return calloc(1, sizeof(struct occ_item
));
3790 static void occ_item_free(struct occ_item
*occ_item
)
3795 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
3797 struct occ_port
*occ_port
;
3799 occ_port
= calloc(1, sizeof(*occ_port
));
3802 occ_port
->port_index
= port_index
;
3803 INIT_LIST_HEAD(&occ_port
->pool_list
);
3804 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
3805 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
3809 static void occ_port_free(struct occ_port
*occ_port
)
3811 struct occ_item
*occ_item
, *tmp
;
3813 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
3814 occ_item_free(occ_item
);
3815 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
3816 occ_item_free(occ_item
);
3817 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
3818 occ_item_free(occ_item
);
3821 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
3823 struct occ_show
*occ_show
;
3825 occ_show
= calloc(1, sizeof(*occ_show
));
3829 INIT_LIST_HEAD(&occ_show
->port_list
);
3833 static void occ_show_free(struct occ_show
*occ_show
)
3835 struct occ_port
*occ_port
, *tmp
;
3837 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
3838 occ_port_free(occ_port
);
3841 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
3844 struct occ_port
*occ_port
;
3845 uint32_t port_index
;
3847 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
3849 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
3850 if (occ_port
->port_index
== port_index
)
3853 occ_port
= occ_port_alloc(port_index
);
3856 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
3860 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
3863 struct occ_item
*occ_item
;
3866 pr_out_sp(7, " %s:", label
);
3867 list_for_each_entry(occ_item
, list
, list
) {
3868 if ((i
- 1) % 4 == 0 && i
!= 1)
3871 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
3872 occ_item
->bound_pool_index
);
3874 pr_out_sp(7, "%2u:", occ_item
->index
);
3875 pr_out_sp(21, "%10u/%u", occ_item
->cur
, occ_item
->max
);
3879 if ((i
- 1) % 4 != 0)
3883 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
3884 struct list_head
*list
,
3887 struct occ_item
*occ_item
;
3890 jsonw_name(dl
->jw
, label
);
3891 jsonw_start_object(dl
->jw
);
3892 list_for_each_entry(occ_item
, list
, list
) {
3893 sprintf(buf
, "%u", occ_item
->index
);
3894 jsonw_name(dl
->jw
, buf
);
3895 jsonw_start_object(dl
->jw
);
3897 jsonw_uint_field(dl
->jw
, "bound_pool",
3898 occ_item
->bound_pool_index
);
3899 jsonw_uint_field(dl
->jw
, "current", occ_item
->cur
);
3900 jsonw_uint_field(dl
->jw
, "max", occ_item
->max
);
3901 jsonw_end_object(dl
->jw
);
3903 jsonw_end_object(dl
->jw
);
3906 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
3908 if (dl
->json_output
) {
3909 pr_out_json_occ_show_item_list(dl
, "pool",
3910 &occ_port
->pool_list
, false);
3911 pr_out_json_occ_show_item_list(dl
, "itc",
3912 &occ_port
->ing_tc_list
, true);
3913 pr_out_json_occ_show_item_list(dl
, "etc",
3914 &occ_port
->eg_tc_list
, true);
3917 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
3918 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
3919 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
3923 static void pr_out_occ_show(struct occ_show
*occ_show
)
3925 struct dl
*dl
= occ_show
->dl
;
3926 struct dl_opts
*opts
= &dl
->opts
;
3927 struct occ_port
*occ_port
;
3929 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
3930 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
3931 occ_port
->port_index
, true, false);
3932 pr_out_occ_show_port(dl
, occ_port
);
3933 pr_out_port_handle_end(dl
);
3937 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
3940 struct occ_port
*occ_port
;
3941 struct occ_item
*occ_item
;
3943 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
3946 occ_port
= occ_port_get(occ_show
, tb
);
3948 occ_show
->err
= -ENOMEM
;
3952 occ_item
= occ_item_alloc();
3954 occ_show
->err
= -ENOMEM
;
3957 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
3958 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
3959 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
3960 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
3963 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
3965 struct occ_show
*occ_show
= data
;
3966 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3967 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3969 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3970 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3971 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3972 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3973 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
3974 return MNL_CB_ERROR
;
3975 cmd_sb_occ_port_pool_process(occ_show
, tb
);
3979 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
3982 struct occ_port
*occ_port
;
3983 struct occ_item
*occ_item
;
3986 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
3989 occ_port
= occ_port_get(occ_show
, tb
);
3991 occ_show
->err
= -ENOMEM
;
3995 occ_item
= occ_item_alloc();
3997 occ_show
->err
= -ENOMEM
;
4000 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
4001 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4002 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4003 occ_item
->bound_pool_index
=
4004 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4005 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
4006 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
4007 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
4008 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
4009 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
4011 occ_item_free(occ_item
);
4014 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4016 struct occ_show
*occ_show
= data
;
4017 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4018 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4020 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4021 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4022 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4023 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
4024 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4025 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4026 return MNL_CB_ERROR
;
4027 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
4031 static int cmd_sb_occ_show(struct dl
*dl
)
4033 struct nlmsghdr
*nlh
;
4034 struct occ_show
*occ_show
;
4035 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
4038 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
4042 occ_show
= occ_show_alloc(dl
);
4046 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
4048 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4049 cmd_sb_occ_port_pool_process_cb
, occ_show
);
4053 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
4055 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4056 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
4060 pr_out_section_start(dl
, "occupancy");
4061 pr_out_occ_show(occ_show
);
4062 pr_out_section_end(dl
);
4065 occ_show_free(occ_show
);
4069 static int cmd_sb_occ_snapshot(struct dl
*dl
)
4071 struct nlmsghdr
*nlh
;
4074 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
4075 NLM_F_REQUEST
| NLM_F_ACK
);
4077 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4081 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4084 static int cmd_sb_occ_clearmax(struct dl
*dl
)
4086 struct nlmsghdr
*nlh
;
4089 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
4090 NLM_F_REQUEST
| NLM_F_ACK
);
4092 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4096 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4099 static int cmd_sb_occ(struct dl
*dl
)
4101 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4104 } else if (dl_argv_match(dl
, "show") ||
4105 dl_argv_match(dl
, "list")) {
4107 return cmd_sb_occ_show(dl
);
4108 } else if (dl_argv_match(dl
, "snapshot")) {
4110 return cmd_sb_occ_snapshot(dl
);
4111 } else if (dl_argv_match(dl
, "clearmax")) {
4113 return cmd_sb_occ_clearmax(dl
);
4115 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4119 static int cmd_sb(struct dl
*dl
)
4121 if (dl_argv_match(dl
, "help")) {
4124 } else if (dl_argv_match(dl
, "show") ||
4125 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
4127 return cmd_sb_show(dl
);
4128 } else if (dl_argv_match(dl
, "pool")) {
4130 return cmd_sb_pool(dl
);
4131 } else if (dl_argv_match(dl
, "port")) {
4133 return cmd_sb_port(dl
);
4134 } else if (dl_argv_match(dl
, "tc")) {
4136 return cmd_sb_tc(dl
);
4137 } else if (dl_argv_match(dl
, "occupancy")) {
4139 return cmd_sb_occ(dl
);
4141 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4145 static const char *cmd_name(uint8_t cmd
)
4148 case DEVLINK_CMD_UNSPEC
: return "unspec";
4149 case DEVLINK_CMD_GET
: return "get";
4150 case DEVLINK_CMD_SET
: return "set";
4151 case DEVLINK_CMD_NEW
: return "new";
4152 case DEVLINK_CMD_DEL
: return "del";
4153 case DEVLINK_CMD_PORT_GET
: return "get";
4154 case DEVLINK_CMD_PORT_SET
: return "set";
4155 case DEVLINK_CMD_PORT_NEW
: return "new";
4156 case DEVLINK_CMD_PORT_DEL
: return "del";
4157 case DEVLINK_CMD_PARAM_GET
: return "get";
4158 case DEVLINK_CMD_PARAM_SET
: return "set";
4159 case DEVLINK_CMD_PARAM_NEW
: return "new";
4160 case DEVLINK_CMD_PARAM_DEL
: return "del";
4161 case DEVLINK_CMD_REGION_GET
: return "get";
4162 case DEVLINK_CMD_REGION_SET
: return "set";
4163 case DEVLINK_CMD_REGION_NEW
: return "new";
4164 case DEVLINK_CMD_REGION_DEL
: return "del";
4165 case DEVLINK_CMD_FLASH_UPDATE
: return "begin";
4166 case DEVLINK_CMD_FLASH_UPDATE_END
: return "end";
4167 case DEVLINK_CMD_FLASH_UPDATE_STATUS
: return "status";
4168 case DEVLINK_CMD_TRAP_GET
: return "get";
4169 case DEVLINK_CMD_TRAP_SET
: return "set";
4170 case DEVLINK_CMD_TRAP_NEW
: return "new";
4171 case DEVLINK_CMD_TRAP_DEL
: return "del";
4172 case DEVLINK_CMD_TRAP_GROUP_GET
: return "get";
4173 case DEVLINK_CMD_TRAP_GROUP_SET
: return "set";
4174 case DEVLINK_CMD_TRAP_GROUP_NEW
: return "new";
4175 case DEVLINK_CMD_TRAP_GROUP_DEL
: return "del";
4176 default: return "<unknown cmd>";
4180 static const char *cmd_obj(uint8_t cmd
)
4183 case DEVLINK_CMD_UNSPEC
: return "unspec";
4184 case DEVLINK_CMD_GET
:
4185 case DEVLINK_CMD_SET
:
4186 case DEVLINK_CMD_NEW
:
4187 case DEVLINK_CMD_DEL
:
4189 case DEVLINK_CMD_PORT_GET
:
4190 case DEVLINK_CMD_PORT_SET
:
4191 case DEVLINK_CMD_PORT_NEW
:
4192 case DEVLINK_CMD_PORT_DEL
:
4194 case DEVLINK_CMD_PARAM_GET
:
4195 case DEVLINK_CMD_PARAM_SET
:
4196 case DEVLINK_CMD_PARAM_NEW
:
4197 case DEVLINK_CMD_PARAM_DEL
:
4199 case DEVLINK_CMD_REGION_GET
:
4200 case DEVLINK_CMD_REGION_SET
:
4201 case DEVLINK_CMD_REGION_NEW
:
4202 case DEVLINK_CMD_REGION_DEL
:
4204 case DEVLINK_CMD_FLASH_UPDATE
:
4205 case DEVLINK_CMD_FLASH_UPDATE_END
:
4206 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4208 case DEVLINK_CMD_TRAP_GET
:
4209 case DEVLINK_CMD_TRAP_SET
:
4210 case DEVLINK_CMD_TRAP_NEW
:
4211 case DEVLINK_CMD_TRAP_DEL
:
4213 case DEVLINK_CMD_TRAP_GROUP_GET
:
4214 case DEVLINK_CMD_TRAP_GROUP_SET
:
4215 case DEVLINK_CMD_TRAP_GROUP_NEW
:
4216 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4217 return "trap-group";
4218 default: return "<unknown obj>";
4222 static void pr_out_mon_header(uint8_t cmd
)
4224 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
4227 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
4229 const char *obj
= cmd_obj(cmd
);
4230 unsigned int index
= 0;
4231 const char *cur_obj
;
4235 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4236 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
4242 static void pr_out_flash_update(struct dl
*dl
, struct nlattr
**tb
)
4244 __pr_out_handle_start(dl
, tb
, true, false);
4246 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
])
4247 pr_out_str(dl
, "msg",
4248 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]));
4250 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
])
4251 pr_out_str(dl
, "component",
4252 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]));
4254 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
4255 pr_out_u64(dl
, "done",
4256 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]));
4258 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
4259 pr_out_u64(dl
, "total",
4260 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]));
4262 pr_out_handle_end(dl
);
4265 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
);
4266 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4267 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4269 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
4271 struct dl
*dl
= data
;
4272 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4273 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4274 uint8_t cmd
= genl
->cmd
;
4276 if (!cmd_filter_check(dl
, cmd
))
4280 case DEVLINK_CMD_GET
: /* fall through */
4281 case DEVLINK_CMD_SET
: /* fall through */
4282 case DEVLINK_CMD_NEW
: /* fall through */
4283 case DEVLINK_CMD_DEL
:
4284 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4285 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4286 return MNL_CB_ERROR
;
4287 pr_out_mon_header(genl
->cmd
);
4288 pr_out_handle(dl
, tb
);
4290 case DEVLINK_CMD_PORT_GET
: /* fall through */
4291 case DEVLINK_CMD_PORT_SET
: /* fall through */
4292 case DEVLINK_CMD_PORT_NEW
: /* fall through */
4293 case DEVLINK_CMD_PORT_DEL
:
4294 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4295 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4296 !tb
[DEVLINK_ATTR_PORT_INDEX
])
4297 return MNL_CB_ERROR
;
4298 pr_out_mon_header(genl
->cmd
);
4299 pr_out_port(dl
, tb
);
4301 case DEVLINK_CMD_PARAM_GET
: /* fall through */
4302 case DEVLINK_CMD_PARAM_SET
: /* fall through */
4303 case DEVLINK_CMD_PARAM_NEW
: /* fall through */
4304 case DEVLINK_CMD_PARAM_DEL
:
4305 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4306 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4307 !tb
[DEVLINK_ATTR_PARAM
])
4308 return MNL_CB_ERROR
;
4309 pr_out_mon_header(genl
->cmd
);
4310 pr_out_param(dl
, tb
, false);
4312 case DEVLINK_CMD_REGION_GET
: /* fall through */
4313 case DEVLINK_CMD_REGION_SET
: /* fall through */
4314 case DEVLINK_CMD_REGION_NEW
: /* fall through */
4315 case DEVLINK_CMD_REGION_DEL
:
4316 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4317 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4318 !tb
[DEVLINK_ATTR_REGION_NAME
])
4319 return MNL_CB_ERROR
;
4320 pr_out_mon_header(genl
->cmd
);
4321 pr_out_region(dl
, tb
);
4323 case DEVLINK_CMD_FLASH_UPDATE
: /* fall through */
4324 case DEVLINK_CMD_FLASH_UPDATE_END
: /* fall through */
4325 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4326 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4327 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4328 return MNL_CB_ERROR
;
4329 pr_out_mon_header(genl
->cmd
);
4330 pr_out_flash_update(dl
, tb
);
4332 case DEVLINK_CMD_TRAP_GET
: /* fall through */
4333 case DEVLINK_CMD_TRAP_SET
: /* fall through */
4334 case DEVLINK_CMD_TRAP_NEW
: /* fall through */
4335 case DEVLINK_CMD_TRAP_DEL
:
4336 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4337 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4338 !tb
[DEVLINK_ATTR_TRAP_NAME
] ||
4339 !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
4340 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
4341 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4342 !tb
[DEVLINK_ATTR_TRAP_METADATA
] ||
4343 !tb
[DEVLINK_ATTR_STATS
])
4344 return MNL_CB_ERROR
;
4345 pr_out_mon_header(genl
->cmd
);
4346 pr_out_trap(dl
, tb
, false);
4348 case DEVLINK_CMD_TRAP_GROUP_GET
: /* fall through */
4349 case DEVLINK_CMD_TRAP_GROUP_SET
: /* fall through */
4350 case DEVLINK_CMD_TRAP_GROUP_NEW
: /* fall through */
4351 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4352 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4353 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4354 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4355 !tb
[DEVLINK_ATTR_STATS
])
4356 return MNL_CB_ERROR
;
4357 pr_out_mon_header(genl
->cmd
);
4358 pr_out_trap_group(dl
, tb
, false);
4364 static int cmd_mon_show(struct dl
*dl
)
4367 unsigned int index
= 0;
4368 const char *cur_obj
;
4370 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4371 if (strcmp(cur_obj
, "all") != 0 &&
4372 strcmp(cur_obj
, "dev") != 0 &&
4373 strcmp(cur_obj
, "port") != 0 &&
4374 strcmp(cur_obj
, "trap") != 0 &&
4375 strcmp(cur_obj
, "trap-group") != 0) {
4376 pr_err("Unknown object \"%s\"\n", cur_obj
);
4380 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
4383 err
= _mnlg_socket_recv_run(dl
->nlg
, cmd_mon_show_cb
, dl
);
4389 static void cmd_mon_help(void)
4391 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
4392 "where OBJECT-LIST := { dev | port | trap | trap-group }\n");
4395 static int cmd_mon(struct dl
*dl
)
4397 if (dl_argv_match(dl
, "help")) {
4401 return cmd_mon_show(dl
);
4404 struct dpipe_field
{
4407 unsigned int bitwidth
;
4408 enum devlink_dpipe_field_mapping_type mapping_type
;
4411 struct dpipe_header
{
4412 struct list_head list
;
4415 struct dpipe_field
*fields
;
4416 unsigned int fields_count
;
4419 struct dpipe_table
{
4420 struct list_head list
;
4422 unsigned int resource_id
;
4423 bool resource_valid
;
4426 struct dpipe_tables
{
4427 struct list_head table_list
;
4437 enum devlink_resource_unit unit
;
4442 struct list_head list
;
4443 struct list_head resource_list
;
4444 struct resource
*parent
;
4448 struct list_head resource_list
;
4451 struct resource_ctx
{
4454 struct resources
*resources
;
4455 struct dpipe_tables
*tables
;
4456 bool print_resources
;
4457 bool pending_change
;
4460 static struct resource
*resource_alloc(void)
4462 struct resource
*resource
;
4464 resource
= calloc(1, sizeof(struct resource
));
4467 INIT_LIST_HEAD(&resource
->resource_list
);
4471 static void resource_free(struct resource
*resource
)
4473 struct resource
*child_resource
, *tmp
;
4475 list_for_each_entry_safe(child_resource
, tmp
, &resource
->resource_list
,
4477 free(child_resource
->name
);
4478 resource_free(child_resource
);
4483 static struct resources
*resources_alloc(void)
4485 struct resources
*resources
;
4487 resources
= calloc(1, sizeof(struct resources
));
4490 INIT_LIST_HEAD(&resources
->resource_list
);
4494 static void resources_free(struct resources
*resources
)
4496 struct resource
*resource
, *tmp
;
4498 list_for_each_entry_safe(resource
, tmp
, &resources
->resource_list
, list
)
4499 resource_free(resource
);
4502 static int resource_ctx_init(struct resource_ctx
*ctx
, struct dl
*dl
)
4504 ctx
->resources
= resources_alloc();
4505 if (!ctx
->resources
)
4511 static void resource_ctx_fini(struct resource_ctx
*ctx
)
4513 resources_free(ctx
->resources
);
4519 struct list_head global_headers
;
4520 struct list_head local_headers
;
4521 struct dpipe_tables
*tables
;
4522 struct resources
*resources
;
4527 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
4529 struct dpipe_header
*header
;
4531 header
= calloc(1, sizeof(struct dpipe_header
));
4534 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
4535 if (!header
->fields
)
4536 goto err_fields_alloc
;
4537 header
->fields_count
= fields_count
;
4545 static void dpipe_header_free(struct dpipe_header
*header
)
4547 free(header
->fields
);
4551 static void dpipe_header_clear(struct dpipe_header
*header
)
4553 struct dpipe_field
*field
;
4556 for (i
= 0; i
< header
->fields_count
; i
++) {
4557 field
= &header
->fields
[i
];
4563 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
4564 struct dpipe_header
*header
, bool global
)
4567 list_add(&header
->list
, &ctx
->global_headers
);
4569 list_add(&header
->list
, &ctx
->local_headers
);
4572 static void dpipe_header_del(struct dpipe_header
*header
)
4574 list_del(&header
->list
);
4577 static struct dpipe_table
*dpipe_table_alloc(void)
4579 return calloc(1, sizeof(struct dpipe_table
));
4582 static void dpipe_table_free(struct dpipe_table
*table
)
4587 static struct dpipe_tables
*dpipe_tables_alloc(void)
4589 struct dpipe_tables
*tables
;
4591 tables
= calloc(1, sizeof(struct dpipe_tables
));
4594 INIT_LIST_HEAD(&tables
->table_list
);
4598 static void dpipe_tables_free(struct dpipe_tables
*tables
)
4600 struct dpipe_table
*table
, *tmp
;
4602 list_for_each_entry_safe(table
, tmp
, &tables
->table_list
, list
)
4603 dpipe_table_free(table
);
4607 static int dpipe_ctx_init(struct dpipe_ctx
*ctx
, struct dl
*dl
)
4609 ctx
->tables
= dpipe_tables_alloc();
4614 INIT_LIST_HEAD(&ctx
->global_headers
);
4615 INIT_LIST_HEAD(&ctx
->local_headers
);
4619 static void dpipe_ctx_fini(struct dpipe_ctx
*ctx
)
4621 struct dpipe_header
*header
, *tmp
;
4623 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
4625 dpipe_header_del(header
);
4626 dpipe_header_clear(header
);
4627 dpipe_header_free(header
);
4629 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
4631 dpipe_header_del(header
);
4632 dpipe_header_clear(header
);
4633 dpipe_header_free(header
);
4635 dpipe_tables_free(ctx
->tables
);
4638 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
4639 uint32_t header_id
, bool global
)
4641 struct list_head
*header_list
;
4642 struct dpipe_header
*header
;
4645 header_list
= &ctx
->global_headers
;
4647 header_list
= &ctx
->local_headers
;
4648 list_for_each_entry(header
, header_list
, list
) {
4649 if (header
->id
!= header_id
)
4651 return header
->name
;
4656 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
4658 uint32_t field_id
, bool global
)
4660 struct list_head
*header_list
;
4661 struct dpipe_header
*header
;
4664 header_list
= &ctx
->global_headers
;
4666 header_list
= &ctx
->local_headers
;
4667 list_for_each_entry(header
, header_list
, list
) {
4668 if (header
->id
!= header_id
)
4670 return header
->fields
[field_id
].name
;
4676 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
4678 switch (mapping_type
) {
4679 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
4681 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
4689 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
4690 uint32_t field_id
, bool global
)
4692 enum devlink_dpipe_field_mapping_type mapping_type
;
4693 struct list_head
*header_list
;
4694 struct dpipe_header
*header
;
4697 header_list
= &ctx
->global_headers
;
4699 header_list
= &ctx
->local_headers
;
4700 list_for_each_entry(header
, header_list
, list
) {
4701 if (header
->id
!= header_id
)
4703 mapping_type
= header
->fields
[field_id
].mapping_type
;
4704 return dpipe_field_mapping_e2s(mapping_type
);
4709 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
4710 struct dpipe_field
*fields
,
4711 unsigned int field_count
)
4713 struct dpipe_field
*field
;
4716 for (i
= 0; i
< field_count
; i
++) {
4718 pr_out_entry_start(ctx
->dl
);
4719 pr_out_str(ctx
->dl
, "name", field
->name
);
4720 if (ctx
->dl
->verbose
)
4721 pr_out_uint(ctx
->dl
, "id", field
->id
);
4722 pr_out_uint(ctx
->dl
, "bitwidth", field
->bitwidth
);
4723 if (field
->mapping_type
)
4724 pr_out_str(ctx
->dl
, "mapping_type",
4725 dpipe_field_mapping_e2s(field
->mapping_type
));
4726 pr_out_entry_end(ctx
->dl
);
4731 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
4732 struct dpipe_header
*header
, bool global
)
4734 pr_out_handle_start_arr(ctx
->dl
, tb
);
4735 pr_out_str(ctx
->dl
, "name", header
->name
);
4736 if (ctx
->dl
->verbose
) {
4737 pr_out_uint(ctx
->dl
, "id", header
->id
);
4738 pr_out_str(ctx
->dl
, "global",
4739 global
? "true" : "false");
4741 pr_out_array_start(ctx
->dl
, "field");
4742 pr_out_dpipe_fields(ctx
, header
->fields
,
4743 header
->fields_count
);
4744 pr_out_array_end(ctx
->dl
);
4745 pr_out_handle_end(ctx
->dl
);
4748 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
4751 struct dpipe_header
*header
;
4753 list_for_each_entry(header
, &ctx
->local_headers
, list
)
4754 pr_out_dpipe_header(ctx
, tb
, header
, false);
4756 list_for_each_entry(header
, &ctx
->global_headers
, list
)
4757 pr_out_dpipe_header(ctx
, tb
, header
, true);
4760 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
4762 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
4766 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
4767 if (err
!= MNL_CB_OK
)
4769 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
4770 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
4771 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
4772 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
4775 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
4776 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4777 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
4778 field
->name
= strdup(name
);
4781 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
4785 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
4786 struct dpipe_field
*fields
)
4788 struct nlattr
*nla_field
;
4792 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
4793 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
4801 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
4803 struct nlattr
*nla_field
;
4804 unsigned int count
= 0;
4806 mnl_attr_for_each_nested(nla_field
, nla_fields
)
4811 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
4813 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
4814 struct dpipe_header
*header
;
4815 unsigned int fields_count
;
4816 const char *header_name
;
4820 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
4821 if (err
!= MNL_CB_OK
)
4824 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
4825 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4826 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
4829 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
4830 header
= dpipe_header_alloc(fields_count
);
4834 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
4835 header
->name
= strdup(header_name
);
4836 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4837 header
->fields_count
= fields_count
;
4838 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4840 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
4844 dpipe_header_add(ctx
, header
, global
);
4848 dpipe_header_free(header
);
4852 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
4854 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
4855 struct nlattr
*nla_header
;
4858 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
4859 err
= dpipe_header_get(ctx
, nla_header
);
4866 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
4868 struct dpipe_ctx
*ctx
= data
;
4869 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4870 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4873 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4874 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4875 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
4876 return MNL_CB_ERROR
;
4877 err
= dpipe_headers_get(ctx
, tb
);
4880 return MNL_CB_ERROR
;
4883 if (ctx
->print_headers
)
4884 pr_out_dpipe_headers(ctx
, tb
);
4888 static int cmd_dpipe_headers_show(struct dl
*dl
)
4890 struct nlmsghdr
*nlh
;
4891 struct dpipe_ctx ctx
= {};
4892 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
4895 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
4897 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
4901 err
= dpipe_ctx_init(&ctx
, dl
);
4905 ctx
.print_headers
= true;
4907 pr_out_section_start(dl
, "header");
4908 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
4910 pr_err("error get headers %s\n", strerror(ctx
.err
));
4911 pr_out_section_end(dl
);
4913 dpipe_ctx_fini(&ctx
);
4917 static void cmd_dpipe_header_help(void)
4919 pr_err("Usage: devlink dpipe headers show DEV\n");
4922 static int cmd_dpipe_header(struct dl
*dl
)
4924 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4925 cmd_dpipe_header_help();
4927 } else if (dl_argv_match(dl
, "show")) {
4929 return cmd_dpipe_headers_show(dl
);
4931 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4936 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
4938 switch (action_type
) {
4939 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
4940 return "field_modify";
4946 struct dpipe_op_info
{
4952 struct dpipe_action
{
4953 struct dpipe_op_info info
;
4957 static void pr_out_dpipe_action(struct dpipe_action
*action
,
4958 struct dpipe_ctx
*ctx
)
4960 struct dpipe_op_info
*op_info
= &action
->info
;
4961 const char *mapping
;
4963 pr_out_str(ctx
->dl
, "type",
4964 dpipe_action_type_e2s(action
->type
));
4965 pr_out_str(ctx
->dl
, "header",
4966 dpipe_header_id2s(ctx
, op_info
->header_id
,
4967 op_info
->header_global
));
4968 pr_out_str(ctx
->dl
, "field",
4969 dpipe_field_id2s(ctx
, op_info
->header_id
,
4971 op_info
->header_global
));
4972 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
4974 op_info
->header_global
);
4976 pr_out_str(ctx
->dl
, "mapping", mapping
);
4979 static int dpipe_action_parse(struct dpipe_action
*action
, struct nlattr
*nl
)
4981 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
4984 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
4985 if (err
!= MNL_CB_OK
)
4988 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
4989 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
4990 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4991 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
4995 action
->type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
4996 action
->info
.header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4997 action
->info
.field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4998 action
->info
.header_global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5003 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
5004 struct nlattr
*nla_actions
)
5006 struct nlattr
*nla_action
;
5007 struct dpipe_action action
;
5009 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
5010 pr_out_entry_start(ctx
->dl
);
5011 if (dpipe_action_parse(&action
, nla_action
))
5012 goto err_action_parse
;
5013 pr_out_dpipe_action(&action
, ctx
);
5014 pr_out_entry_end(ctx
->dl
);
5019 pr_out_entry_end(ctx
->dl
);
5024 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
5026 switch (match_type
) {
5027 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
5028 return "field_exact";
5034 struct dpipe_match
{
5035 struct dpipe_op_info info
;
5039 static void pr_out_dpipe_match(struct dpipe_match
*match
,
5040 struct dpipe_ctx
*ctx
)
5042 struct dpipe_op_info
*op_info
= &match
->info
;
5043 const char *mapping
;
5045 pr_out_str(ctx
->dl
, "type",
5046 dpipe_match_type_e2s(match
->type
));
5047 pr_out_str(ctx
->dl
, "header",
5048 dpipe_header_id2s(ctx
, op_info
->header_id
,
5049 op_info
->header_global
));
5050 pr_out_str(ctx
->dl
, "field",
5051 dpipe_field_id2s(ctx
, op_info
->header_id
,
5053 op_info
->header_global
));
5054 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5056 op_info
->header_global
);
5058 pr_out_str(ctx
->dl
, "mapping", mapping
);
5061 static int dpipe_match_parse(struct dpipe_match
*match
,
5065 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
5068 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
5069 if (err
!= MNL_CB_OK
)
5072 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
5073 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5074 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5075 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5079 match
->type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
5080 match
->info
.header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5081 match
->info
.field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5082 match
->info
.header_global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5087 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
5088 struct nlattr
*nla_matches
)
5090 struct nlattr
*nla_match
;
5091 struct dpipe_match match
;
5093 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
5094 pr_out_entry_start(ctx
->dl
);
5095 if (dpipe_match_parse(&match
, nla_match
))
5096 goto err_match_parse
;
5097 pr_out_dpipe_match(&match
, ctx
);
5098 pr_out_entry_end(ctx
->dl
);
5103 pr_out_entry_end(ctx
->dl
);
5107 static struct resource
*
5108 resource_find(struct resources
*resources
, struct resource
*resource
,
5109 uint64_t resource_id
)
5111 struct list_head
*list_head
;
5114 list_head
= &resources
->resource_list
;
5116 list_head
= &resource
->resource_list
;
5118 list_for_each_entry(resource
, list_head
, list
) {
5119 struct resource
*child_resource
;
5121 if (resource
->id
== resource_id
)
5124 child_resource
= resource_find(resources
, resource
,
5127 return child_resource
;
5133 resource_path_print(struct dl
*dl
, struct resources
*resources
,
5134 uint64_t resource_id
)
5136 struct resource
*resource
, *parent_resource
;
5137 const char del
[] = "/";
5141 resource
= resource_find(resources
, NULL
, resource_id
);
5145 for (parent_resource
= resource
; parent_resource
;
5146 parent_resource
= parent_resource
->parent
)
5147 path_len
+= strlen(parent_resource
->name
) + 1;
5150 path
= calloc(1, path_len
);
5154 path
+= path_len
- 1;
5155 for (parent_resource
= resource
; parent_resource
;
5156 parent_resource
= parent_resource
->parent
) {
5157 path
-= strlen(parent_resource
->name
);
5158 memcpy(path
, parent_resource
->name
,
5159 strlen(parent_resource
->name
));
5160 path
-= strlen(del
);
5161 memcpy(path
, del
, strlen(del
));
5163 pr_out_str(dl
, "resource_path", path
);
5167 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5169 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
5170 struct dpipe_table
*table
;
5171 uint32_t resource_units
;
5172 bool counters_enabled
;
5173 bool resource_valid
;
5177 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
5178 if (err
!= MNL_CB_OK
)
5181 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
5182 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
5183 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
5184 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
5185 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
5189 table
= dpipe_table_alloc();
5193 table
->name
= strdup(mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]));
5194 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
5195 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
5197 resource_valid
= nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
] &&
5199 if (resource_valid
) {
5200 table
->resource_id
= mnl_attr_get_u64(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
]);
5201 table
->resource_valid
= true;
5204 list_add_tail(&table
->list
, &ctx
->tables
->table_list
);
5205 if (!ctx
->print_tables
)
5208 pr_out_str(ctx
->dl
, "name", table
->name
);
5209 pr_out_uint(ctx
->dl
, "size", size
);
5210 pr_out_str(ctx
->dl
, "counters_enabled",
5211 counters_enabled
? "true" : "false");
5213 if (resource_valid
) {
5214 resource_units
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS
]);
5215 resource_path_print(ctx
->dl
, ctx
->resources
,
5216 table
->resource_id
);
5217 pr_out_uint(ctx
->dl
, "resource_units", resource_units
);
5220 pr_out_array_start(ctx
->dl
, "match");
5221 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
5222 goto err_matches_show
;
5223 pr_out_array_end(ctx
->dl
);
5225 pr_out_array_start(ctx
->dl
, "action");
5226 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
5227 goto err_actions_show
;
5228 pr_out_array_end(ctx
->dl
);
5234 pr_out_array_end(ctx
->dl
);
5238 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5240 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
5241 struct nlattr
*nla_table
;
5243 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
5244 if (ctx
->print_tables
)
5245 pr_out_handle_start_arr(ctx
->dl
, tb
);
5246 if (dpipe_table_show(ctx
, nla_table
))
5247 goto err_table_show
;
5248 if (ctx
->print_tables
)
5249 pr_out_handle_end(ctx
->dl
);
5254 if (ctx
->print_tables
)
5255 pr_out_handle_end(ctx
->dl
);
5259 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5261 struct dpipe_ctx
*ctx
= data
;
5262 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5263 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5265 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5266 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5267 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
5268 return MNL_CB_ERROR
;
5270 if (dpipe_tables_show(ctx
, tb
))
5271 return MNL_CB_ERROR
;
5275 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
);
5277 static int cmd_dpipe_table_show(struct dl
*dl
)
5279 struct nlmsghdr
*nlh
;
5280 struct dpipe_ctx dpipe_ctx
= {};
5281 struct resource_ctx resource_ctx
= {};
5282 uint16_t flags
= NLM_F_REQUEST
;
5285 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
5289 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5291 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5295 dpipe_ctx
.print_tables
= true;
5297 dl_opts_put(nlh
, dl
);
5298 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
,
5301 pr_err("error get headers %s\n", strerror(dpipe_ctx
.err
));
5302 goto err_headers_get
;
5305 err
= resource_ctx_init(&resource_ctx
, dl
);
5307 goto err_resource_ctx_init
;
5309 resource_ctx
.print_resources
= false;
5310 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
, flags
);
5311 dl_opts_put(nlh
, dl
);
5312 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
5315 dpipe_ctx
.resources
= resource_ctx
.resources
;
5317 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5318 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
5319 dl_opts_put(nlh
, dl
);
5321 pr_out_section_start(dl
, "table");
5322 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, &dpipe_ctx
);
5323 pr_out_section_end(dl
);
5325 resource_ctx_fini(&resource_ctx
);
5326 dpipe_ctx_fini(&dpipe_ctx
);
5329 err_resource_ctx_init
:
5331 dpipe_ctx_fini(&dpipe_ctx
);
5335 static int cmd_dpipe_table_set(struct dl
*dl
)
5337 struct nlmsghdr
*nlh
;
5340 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
5341 NLM_F_REQUEST
| NLM_F_ACK
);
5343 err
= dl_argv_parse_put(nlh
, dl
,
5344 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
5345 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
5349 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5352 enum dpipe_value_type
{
5353 DPIPE_VALUE_TYPE_VALUE
,
5354 DPIPE_VALUE_TYPE_MASK
,
5358 dpipe_value_type_e2s(enum dpipe_value_type type
)
5361 case DPIPE_VALUE_TYPE_VALUE
:
5363 case DPIPE_VALUE_TYPE_MASK
:
5364 return "value_mask";
5370 struct dpipe_field_printer
{
5371 unsigned int field_id
;
5372 void (*printer
)(struct dpipe_ctx
*, enum dpipe_value_type
, void *);
5375 struct dpipe_header_printer
{
5376 struct dpipe_field_printer
*printers
;
5377 unsigned int printers_count
;
5378 unsigned int header_id
;
5381 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx
*ctx
,
5382 enum dpipe_value_type type
,
5385 struct in_addr ip_addr
;
5387 ip_addr
.s_addr
= htonl(*(uint32_t *)value
);
5388 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
), inet_ntoa(ip_addr
));
5392 dpipe_field_printer_ethernet_addr(struct dpipe_ctx
*ctx
,
5393 enum dpipe_value_type type
,
5396 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
),
5397 ether_ntoa((struct ether_addr
*)value
));
5400 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx
*ctx
,
5401 enum dpipe_value_type type
,
5404 char str
[INET6_ADDRSTRLEN
];
5406 inet_ntop(AF_INET6
, value
, str
, INET6_ADDRSTRLEN
);
5407 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
), str
);
5410 static struct dpipe_field_printer dpipe_field_printers_ipv4
[] = {
5412 .printer
= dpipe_field_printer_ipv4_addr
,
5413 .field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
,
5417 static struct dpipe_header_printer dpipe_header_printer_ipv4
= {
5418 .printers
= dpipe_field_printers_ipv4
,
5419 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv4
),
5420 .header_id
= DEVLINK_DPIPE_HEADER_IPV4
,
5423 static struct dpipe_field_printer dpipe_field_printers_ethernet
[] = {
5425 .printer
= dpipe_field_printer_ethernet_addr
,
5426 .field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
,
5430 static struct dpipe_header_printer dpipe_header_printer_ethernet
= {
5431 .printers
= dpipe_field_printers_ethernet
,
5432 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ethernet
),
5433 .header_id
= DEVLINK_DPIPE_HEADER_ETHERNET
,
5436 static struct dpipe_field_printer dpipe_field_printers_ipv6
[] = {
5438 .printer
= dpipe_field_printer_ipv6_addr
,
5439 .field_id
= DEVLINK_DPIPE_FIELD_IPV6_DST_IP
,
5443 static struct dpipe_header_printer dpipe_header_printer_ipv6
= {
5444 .printers
= dpipe_field_printers_ipv6
,
5445 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv6
),
5446 .header_id
= DEVLINK_DPIPE_HEADER_IPV6
,
5449 static struct dpipe_header_printer
*dpipe_header_printers
[] = {
5450 &dpipe_header_printer_ipv4
,
5451 &dpipe_header_printer_ethernet
,
5452 &dpipe_header_printer_ipv6
,
5455 static int dpipe_print_prot_header(struct dpipe_ctx
*ctx
,
5456 struct dpipe_op_info
*info
,
5457 enum dpipe_value_type type
,
5460 unsigned int header_printers_count
= ARRAY_SIZE(dpipe_header_printers
);
5461 struct dpipe_header_printer
*header_printer
;
5462 struct dpipe_field_printer
*field_printer
;
5463 unsigned int field_printers_count
;
5467 for (i
= 0; i
< header_printers_count
; i
++) {
5468 header_printer
= dpipe_header_printers
[i
];
5469 if (header_printer
->header_id
!= info
->header_id
)
5471 field_printers_count
= header_printer
->printers_count
;
5472 for (j
= 0; j
< field_printers_count
; j
++) {
5473 field_printer
= &header_printer
->printers
[j
];
5474 if (field_printer
->field_id
!= info
->field_id
)
5476 field_printer
->printer(ctx
, type
, value
);
5484 static void __pr_out_entry_value(struct dpipe_ctx
*ctx
,
5486 unsigned int value_len
,
5487 struct dpipe_op_info
*info
,
5488 enum dpipe_value_type type
)
5490 if (info
->header_global
&&
5491 !dpipe_print_prot_header(ctx
, info
, type
, value
))
5494 if (value_len
== sizeof(uint32_t)) {
5495 uint32_t *value_32
= value
;
5497 pr_out_uint(ctx
->dl
, dpipe_value_type_e2s(type
), *value_32
);
5501 static void pr_out_dpipe_entry_value(struct dpipe_ctx
*ctx
,
5502 struct nlattr
**nla_match_value
,
5503 struct dpipe_op_info
*info
)
5505 void *value
, *value_mask
;
5506 uint32_t value_mapping
;
5510 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
5511 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
5513 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5514 value
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5517 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
5518 pr_out_uint(ctx
->dl
, "mapping_value", value_mapping
);
5522 value_mask
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5523 __pr_out_entry_value(ctx
, value_mask
, value_len
, info
,
5524 DPIPE_VALUE_TYPE_MASK
);
5527 __pr_out_entry_value(ctx
, value
, value_len
, info
, DPIPE_VALUE_TYPE_VALUE
);
5530 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
5533 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5534 struct dpipe_match match
;
5537 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
5538 if (err
!= MNL_CB_OK
)
5541 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
5542 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5546 pr_out_entry_start(ctx
->dl
);
5547 if (dpipe_match_parse(&match
,
5548 nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
5549 goto err_match_parse
;
5550 pr_out_dpipe_match(&match
, ctx
);
5551 pr_out_dpipe_entry_value(ctx
, nla_match_value
, &match
.info
);
5552 pr_out_entry_end(ctx
->dl
);
5557 pr_out_entry_end(ctx
->dl
);
5561 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
5564 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5565 struct dpipe_action action
;
5568 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
5569 if (err
!= MNL_CB_OK
)
5572 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
5573 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5577 pr_out_entry_start(ctx
->dl
);
5578 if (dpipe_action_parse(&action
,
5579 nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
5580 goto err_action_parse
;
5581 pr_out_dpipe_action(&action
, ctx
);
5582 pr_out_dpipe_entry_value(ctx
, nla_action_value
, &action
.info
);
5583 pr_out_entry_end(ctx
->dl
);
5588 pr_out_entry_end(ctx
->dl
);
5593 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
5594 struct nlattr
*nla_action_values
)
5596 struct nlattr
*nla_action_value
;
5598 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
5599 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
5606 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
5607 struct nlattr
*nla_match_values
)
5609 struct nlattr
*nla_match_value
;
5611 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
5612 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
5618 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5620 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
5621 uint32_t entry_index
;
5625 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
5626 if (err
!= MNL_CB_OK
)
5629 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
5630 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
5631 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
5635 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
5636 pr_out_uint(ctx
->dl
, "index", entry_index
);
5638 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
5639 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
5640 pr_out_uint(ctx
->dl
, "counter", counter
);
5643 pr_out_array_start(ctx
->dl
, "match_value");
5644 if (dpipe_tables_match_values_show(ctx
,
5645 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
5646 goto err_match_values_show
;
5647 pr_out_array_end(ctx
->dl
);
5649 pr_out_array_start(ctx
->dl
, "action_value");
5650 if (dpipe_tables_action_values_show(ctx
,
5651 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
5652 goto err_action_values_show
;
5653 pr_out_array_end(ctx
->dl
);
5656 err_action_values_show
:
5657 err_match_values_show
:
5658 pr_out_array_end(ctx
->dl
);
5662 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5664 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
5665 struct nlattr
*nla_entry
;
5667 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
5668 pr_out_handle_start_arr(ctx
->dl
, tb
);
5669 if (dpipe_entry_show(ctx
, nla_entry
))
5670 goto err_entry_show
;
5671 pr_out_handle_end(ctx
->dl
);
5676 pr_out_handle_end(ctx
->dl
);
5680 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5682 struct dpipe_ctx
*ctx
= data
;
5683 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5684 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5686 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5687 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5688 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
5689 return MNL_CB_ERROR
;
5691 if (dpipe_table_entries_show(ctx
, tb
))
5692 return MNL_CB_ERROR
;
5696 static int cmd_dpipe_table_dump(struct dl
*dl
)
5698 struct nlmsghdr
*nlh
;
5699 struct dpipe_ctx ctx
= {};
5700 uint16_t flags
= NLM_F_REQUEST
;
5703 err
= dpipe_ctx_init(&ctx
, dl
);
5707 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
5711 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5712 dl_opts_put(nlh
, dl
);
5713 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5715 pr_err("error get headers %s\n", strerror(ctx
.err
));
5719 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5720 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
5721 dl_opts_put(nlh
, dl
);
5723 pr_out_section_start(dl
, "table_entry");
5724 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, &ctx
);
5725 pr_out_section_end(dl
);
5727 dpipe_ctx_fini(&ctx
);
5731 static void cmd_dpipe_table_help(void)
5733 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
5734 "where OBJECT-LIST := { show | set | dump }\n");
5737 static int cmd_dpipe_table(struct dl
*dl
)
5739 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5740 cmd_dpipe_table_help();
5742 } else if (dl_argv_match(dl
, "show")) {
5744 return cmd_dpipe_table_show(dl
);
5745 } else if (dl_argv_match(dl
, "set")) {
5747 return cmd_dpipe_table_set(dl
);
5748 } else if (dl_argv_match(dl
, "dump")) {
5750 return cmd_dpipe_table_dump(dl
);
5752 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5756 static void cmd_dpipe_help(void)
5758 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
5759 "where OBJECT-LIST := { header | table }\n");
5762 static int cmd_dpipe(struct dl
*dl
)
5764 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5767 } else if (dl_argv_match(dl
, "header")) {
5769 return cmd_dpipe_header(dl
);
5770 } else if (dl_argv_match(dl
, "table")) {
5772 return cmd_dpipe_table(dl
);
5774 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5779 resource_parse(struct resource_ctx
*ctx
, struct resource
*resource
,
5780 struct nlattr
**nla_resource
)
5782 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
] ||
5783 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
] ||
5784 !nla_resource
[DEVLINK_ATTR_RESOURCE_ID
] ||
5785 !nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
] ||
5786 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
] ||
5787 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
] ||
5788 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]) {
5792 resource
->name
= strdup(mnl_attr_get_str(nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
]));
5793 resource
->size
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
]);
5794 resource
->id
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_ID
]);
5795 resource
->unit
= mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
]);
5796 resource
->size_min
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
]);
5797 resource
->size_max
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
]);
5798 resource
->size_gran
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]);
5800 if (nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
])
5801 resource
->size_new
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
]);
5803 resource
->size_new
= resource
->size
;
5805 if (nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]) {
5806 resource
->size_occ
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]);
5807 resource
->occ_valid
= true;
5810 if (resource
->size_new
!= resource
->size
)
5811 ctx
->pending_change
= true;
5817 resource_get(struct resource_ctx
*ctx
, struct resource
*resource
,
5818 struct resource
*parent_resource
, struct nlattr
*nl
)
5820 struct nlattr
*nla_resource
[DEVLINK_ATTR_MAX
+ 1] = {};
5821 struct nlattr
*nla_child_resource
;
5822 struct nlattr
*nla_resources
;
5832 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_resource
);
5833 if (err
!= MNL_CB_OK
)
5836 err
= resource_parse(ctx
, resource
, nla_resource
);
5840 resource
->parent
= parent_resource
;
5841 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
])
5844 resource
->size_valid
= !!mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_VALID
]);
5845 nla_resources
= nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
];
5847 mnl_attr_for_each_nested(nla_child_resource
, nla_resources
) {
5848 struct resource
*child_resource
;
5849 struct list_head
*list
;
5851 child_resource
= resource_alloc();
5852 if (!child_resource
)
5856 list
= &ctx
->resources
->resource_list
;
5858 list
= &resource
->resource_list
;
5860 list_add_tail(&child_resource
->list
, list
);
5861 err
= resource_get(ctx
, child_resource
, resource
,
5862 nla_child_resource
);
5870 static const char *resource_unit_str_get(enum devlink_resource_unit unit
)
5873 case DEVLINK_RESOURCE_UNIT_ENTRY
: return "entry";
5874 default: return "<unknown unit>";
5878 static void resource_show(struct resource
*resource
,
5879 struct resource_ctx
*ctx
)
5881 struct resource
*child_resource
;
5882 struct dpipe_table
*table
;
5883 struct dl
*dl
= ctx
->dl
;
5886 pr_out_str(dl
, "name", resource
->name
);
5888 resource_path_print(dl
, ctx
->resources
, resource
->id
);
5889 pr_out_u64(dl
, "size", resource
->size
);
5890 if (resource
->size
!= resource
->size_new
)
5891 pr_out_u64(dl
, "size_new", resource
->size_new
);
5892 if (resource
->occ_valid
)
5893 pr_out_uint(dl
, "occ", resource
->size_occ
);
5894 pr_out_str(dl
, "unit", resource_unit_str_get(resource
->unit
));
5896 if (resource
->size_min
!= resource
->size_max
) {
5897 pr_out_uint(dl
, "size_min", resource
->size_min
);
5898 pr_out_u64(dl
, "size_max", resource
->size_max
);
5899 pr_out_uint(dl
, "size_gran", resource
->size_gran
);
5902 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
)
5903 if (table
->resource_id
== resource
->id
&&
5904 table
->resource_valid
)
5908 pr_out_array_start(dl
, "dpipe_tables");
5910 pr_out_str(dl
, "dpipe_tables", "none");
5912 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
) {
5913 if (table
->resource_id
!= resource
->id
||
5914 !table
->resource_valid
)
5916 pr_out_entry_start(dl
);
5917 pr_out_str(dl
, "table_name", table
->name
);
5918 pr_out_entry_end(dl
);
5921 pr_out_array_end(dl
);
5923 if (list_empty(&resource
->resource_list
))
5926 if (ctx
->pending_change
)
5927 pr_out_str(dl
, "size_valid", resource
->size_valid
?
5929 pr_out_array_start(dl
, "resources");
5930 list_for_each_entry(child_resource
, &resource
->resource_list
, list
) {
5931 pr_out_entry_start(dl
);
5932 resource_show(child_resource
, ctx
);
5933 pr_out_entry_end(dl
);
5935 pr_out_array_end(dl
);
5939 resources_show(struct resource_ctx
*ctx
, struct nlattr
**tb
)
5941 struct resources
*resources
= ctx
->resources
;
5942 struct resource
*resource
;
5944 list_for_each_entry(resource
, &resources
->resource_list
, list
) {
5945 pr_out_handle_start_arr(ctx
->dl
, tb
);
5946 resource_show(resource
, ctx
);
5947 pr_out_handle_end(ctx
->dl
);
5951 static int resources_get(struct resource_ctx
*ctx
, struct nlattr
**tb
)
5953 return resource_get(ctx
, NULL
, NULL
, tb
[DEVLINK_ATTR_RESOURCE_LIST
]);
5956 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5958 struct resource_ctx
*ctx
= data
;
5959 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5960 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5963 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5964 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5965 !tb
[DEVLINK_ATTR_RESOURCE_LIST
])
5966 return MNL_CB_ERROR
;
5968 err
= resources_get(ctx
, tb
);
5971 return MNL_CB_ERROR
;
5974 if (ctx
->print_resources
)
5975 resources_show(ctx
, tb
);
5980 static int cmd_resource_show(struct dl
*dl
)
5982 struct nlmsghdr
*nlh
;
5983 struct dpipe_ctx dpipe_ctx
= {};
5984 struct resource_ctx resource_ctx
= {};
5987 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, 0);
5991 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
,
5993 dl_opts_put(nlh
, dl
);
5995 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5999 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
,
6002 pr_err("error get tables %s\n", strerror(dpipe_ctx
.err
));
6006 err
= resource_ctx_init(&resource_ctx
, dl
);
6010 resource_ctx
.print_resources
= true;
6011 resource_ctx
.tables
= dpipe_ctx
.tables
;
6012 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6013 NLM_F_REQUEST
| NLM_F_ACK
);
6014 dl_opts_put(nlh
, dl
);
6015 pr_out_section_start(dl
, "resources");
6016 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
6018 pr_out_section_end(dl
);
6019 resource_ctx_fini(&resource_ctx
);
6021 dpipe_ctx_fini(&dpipe_ctx
);
6025 static void cmd_resource_help(void)
6027 pr_err("Usage: devlink resource show DEV\n"
6028 " devlink resource set DEV path PATH size SIZE\n");
6031 static struct resource
*
6032 resource_find_by_name(struct list_head
*list
, char *name
)
6034 struct resource
*resource
;
6036 list_for_each_entry(resource
, list
, list
) {
6037 if (!strcmp(resource
->name
, name
))
6044 resource_path_parse(struct resource_ctx
*ctx
, const char *resource_path
,
6045 uint32_t *p_resource_id
, bool *p_resource_valid
)
6047 struct resource
*resource
;
6048 uint32_t resource_id
= 0;
6049 char *resource_path_dup
;
6050 struct list_head
*list
;
6051 const char del
[] = "/";
6052 char *resource_name
;
6054 resource_path_dup
= strdup(resource_path
);
6055 list
= &ctx
->resources
->resource_list
;
6056 resource_name
= strtok(resource_path_dup
, del
);
6057 while (resource_name
!= NULL
) {
6058 resource
= resource_find_by_name(list
, resource_name
);
6060 goto err_resource_lookup
;
6062 list
= &resource
->resource_list
;
6063 resource_name
= strtok(NULL
, del
);
6064 resource_id
= resource
->id
;
6066 free(resource_path_dup
);
6067 *p_resource_valid
= true;
6068 *p_resource_id
= resource_id
;
6071 err_resource_lookup
:
6072 free(resource_path_dup
);
6076 static int cmd_resource_set(struct dl
*dl
)
6078 struct nlmsghdr
*nlh
;
6079 struct resource_ctx ctx
= {};
6082 err
= resource_ctx_init(&ctx
, dl
);
6086 ctx
.print_resources
= false;
6087 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_RESOURCE_PATH
|
6088 DL_OPT_RESOURCE_SIZE
, 0);
6092 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6094 dl_opts_put(nlh
, dl
);
6095 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
, &ctx
);
6097 pr_err("error getting resources %s\n", strerror(ctx
.err
));
6101 err
= resource_path_parse(&ctx
, dl
->opts
.resource_path
,
6102 &dl
->opts
.resource_id
,
6103 &dl
->opts
.resource_id_valid
);
6105 pr_err("error parsing resource path %s\n", strerror(-err
));
6109 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_SET
,
6110 NLM_F_REQUEST
| NLM_F_ACK
);
6112 dl_opts_put(nlh
, dl
);
6113 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6115 resource_ctx_fini(&ctx
);
6119 static int cmd_resource(struct dl
*dl
)
6121 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6122 cmd_resource_help();
6124 } else if (dl_argv_match(dl
, "show")) {
6126 return cmd_resource_show(dl
);
6127 } else if (dl_argv_match(dl
, "set")) {
6129 return cmd_resource_set(dl
);
6131 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6135 static void pr_out_region_handle_start(struct dl
*dl
, struct nlattr
**tb
)
6137 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
6138 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
6139 const char *region_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_REGION_NAME
]);
6142 sprintf(buf
, "%s/%s/%s", bus_name
, dev_name
, region_name
);
6143 if (dl
->json_output
) {
6144 jsonw_name(dl
->jw
, buf
);
6145 jsonw_start_object(dl
->jw
);
6151 static void pr_out_region_handle_end(struct dl
*dl
)
6153 if (dl
->json_output
)
6154 jsonw_end_object(dl
->jw
);
6159 static void pr_out_region_snapshots_start(struct dl
*dl
, bool array
)
6161 __pr_out_indent_newline(dl
);
6162 if (dl
->json_output
) {
6163 jsonw_name(dl
->jw
, "snapshot");
6164 jsonw_start_array(dl
->jw
);
6166 pr_out("snapshot %s", array
? "[" : "");
6170 static void pr_out_region_snapshots_end(struct dl
*dl
, bool array
)
6172 if (dl
->json_output
)
6173 jsonw_end_array(dl
->jw
);
6178 static void pr_out_region_snapshots_id(struct dl
*dl
, struct nlattr
**tb
, int index
)
6180 uint32_t snapshot_id
;
6182 if (!tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6185 snapshot_id
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
]);
6187 if (dl
->json_output
)
6188 jsonw_uint(dl
->jw
, snapshot_id
);
6190 pr_out("%s%u", index
? " " : "", snapshot_id
);
6193 static void pr_out_snapshots(struct dl
*dl
, struct nlattr
**tb
)
6195 struct nlattr
*tb_snapshot
[DEVLINK_ATTR_MAX
+ 1] = {};
6196 struct nlattr
*nla_sanpshot
;
6199 pr_out_region_snapshots_start(dl
, true);
6200 mnl_attr_for_each_nested(nla_sanpshot
, tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
]) {
6201 err
= mnl_attr_parse_nested(nla_sanpshot
, attr_cb
, tb_snapshot
);
6202 if (err
!= MNL_CB_OK
)
6204 pr_out_region_snapshots_id(dl
, tb_snapshot
, index
++);
6206 pr_out_region_snapshots_end(dl
, true);
6209 static void pr_out_snapshot(struct dl
*dl
, struct nlattr
**tb
)
6211 pr_out_region_snapshots_start(dl
, false);
6212 pr_out_region_snapshots_id(dl
, tb
, 0);
6213 pr_out_region_snapshots_end(dl
, false);
6216 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
)
6218 pr_out_region_handle_start(dl
, tb
);
6220 if (tb
[DEVLINK_ATTR_REGION_SIZE
])
6221 pr_out_u64(dl
, "size",
6222 mnl_attr_get_u64(tb
[DEVLINK_ATTR_REGION_SIZE
]));
6224 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
])
6225 pr_out_snapshots(dl
, tb
);
6227 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6228 pr_out_snapshot(dl
, tb
);
6230 pr_out_region_handle_end(dl
);
6233 static int cmd_region_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6235 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6236 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6237 struct dl
*dl
= data
;
6239 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6240 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6241 !tb
[DEVLINK_ATTR_REGION_NAME
] || !tb
[DEVLINK_ATTR_REGION_SIZE
])
6242 return MNL_CB_ERROR
;
6244 pr_out_region(dl
, tb
);
6249 static int cmd_region_show(struct dl
*dl
)
6251 struct nlmsghdr
*nlh
;
6252 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6255 if (dl_argc(dl
) == 0)
6256 flags
|= NLM_F_DUMP
;
6258 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_GET
, flags
);
6260 if (dl_argc(dl
) > 0) {
6261 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
, 0);
6266 pr_out_section_start(dl
, "regions");
6267 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_show_cb
, dl
);
6268 pr_out_section_end(dl
);
6272 static int cmd_region_snapshot_del(struct dl
*dl
)
6274 struct nlmsghdr
*nlh
;
6277 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_DEL
,
6278 NLM_F_REQUEST
| NLM_F_ACK
);
6280 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6281 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6285 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6288 static int cmd_region_read_cb(const struct nlmsghdr
*nlh
, void *data
)
6290 struct nlattr
*nla_entry
, *nla_chunk_data
, *nla_chunk_addr
;
6291 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6292 struct nlattr
*tb_field
[DEVLINK_ATTR_MAX
+ 1] = {};
6293 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6294 struct dl
*dl
= data
;
6297 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6298 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6299 !tb
[DEVLINK_ATTR_REGION_CHUNKS
])
6300 return MNL_CB_ERROR
;
6302 mnl_attr_for_each_nested(nla_entry
, tb
[DEVLINK_ATTR_REGION_CHUNKS
]) {
6303 err
= mnl_attr_parse_nested(nla_entry
, attr_cb
, tb_field
);
6304 if (err
!= MNL_CB_OK
)
6305 return MNL_CB_ERROR
;
6307 nla_chunk_data
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_DATA
];
6308 if (!nla_chunk_data
)
6311 nla_chunk_addr
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_ADDR
];
6312 if (!nla_chunk_addr
)
6315 pr_out_region_chunk(dl
, mnl_attr_get_payload(nla_chunk_data
),
6316 mnl_attr_get_payload_len(nla_chunk_data
),
6317 mnl_attr_get_u64(nla_chunk_addr
));
6322 static int cmd_region_dump(struct dl
*dl
)
6324 struct nlmsghdr
*nlh
;
6327 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6328 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6330 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6331 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6335 pr_out_section_start(dl
, "dump");
6336 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6337 pr_out_section_end(dl
);
6338 if (!dl
->json_output
)
6343 static int cmd_region_read(struct dl
*dl
)
6345 struct nlmsghdr
*nlh
;
6348 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6349 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6351 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6352 DL_OPT_REGION_ADDRESS
| DL_OPT_REGION_LENGTH
|
6353 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6357 pr_out_section_start(dl
, "read");
6358 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6359 pr_out_section_end(dl
);
6360 if (!dl
->json_output
)
6365 static void cmd_region_help(void)
6367 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
6368 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
6369 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
6370 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
6373 static int cmd_region(struct dl
*dl
)
6375 if (dl_no_arg(dl
)) {
6376 return cmd_region_show(dl
);
6377 } else if (dl_argv_match(dl
, "help")) {
6380 } else if (dl_argv_match(dl
, "show")) {
6382 return cmd_region_show(dl
);
6383 } else if (dl_argv_match(dl
, "del")) {
6385 return cmd_region_snapshot_del(dl
);
6386 } else if (dl_argv_match(dl
, "dump")) {
6388 return cmd_region_dump(dl
);
6389 } else if (dl_argv_match(dl
, "read")) {
6391 return cmd_region_read(dl
);
6393 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6397 static int cmd_health_set_params(struct dl
*dl
)
6399 struct nlmsghdr
*nlh
;
6402 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_SET
,
6403 NLM_F_REQUEST
| NLM_F_ACK
);
6404 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
,
6405 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
|
6406 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
);
6410 dl_opts_put(nlh
, dl
);
6411 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6414 static int cmd_health_dump_clear(struct dl
*dl
)
6416 struct nlmsghdr
*nlh
;
6419 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR
,
6420 NLM_F_REQUEST
| NLM_F_ACK
);
6422 err
= dl_argv_parse_put(nlh
, dl
,
6423 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6427 dl_opts_put(nlh
, dl
);
6428 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6431 static int fmsg_value_show(struct dl
*dl
, int type
, struct nlattr
*nl_data
)
6438 pr_out_bool_value(dl
, mnl_attr_get_u8(nl_data
));
6441 pr_out_uint_value(dl
, mnl_attr_get_u8(nl_data
));
6444 pr_out_uint_value(dl
, mnl_attr_get_u16(nl_data
));
6447 pr_out_uint_value(dl
, mnl_attr_get_u32(nl_data
));
6450 pr_out_uint64_value(dl
, mnl_attr_get_u64(nl_data
));
6452 case MNL_TYPE_NUL_STRING
:
6453 pr_out_str_value(dl
, mnl_attr_get_str(nl_data
));
6455 case MNL_TYPE_BINARY
:
6456 len
= mnl_attr_get_payload_len(nl_data
);
6457 data
= mnl_attr_get_payload(nl_data
);
6458 pr_out_binary_value(dl
, data
, len
);
6468 struct list_head list
;
6471 struct fmsg_cb_data
{
6474 struct list_head entry_list
;
6477 static int cmd_fmsg_nest_queue(struct fmsg_cb_data
*fmsg_data
,
6478 uint8_t *attr_value
, bool insert
)
6480 struct nest_entry
*entry
;
6483 entry
= malloc(sizeof(struct nest_entry
));
6487 entry
->attr_type
= *attr_value
;
6488 list_add(&entry
->list
, &fmsg_data
->entry_list
);
6490 if (list_empty(&fmsg_data
->entry_list
))
6491 return MNL_CB_ERROR
;
6492 entry
= list_first_entry(&fmsg_data
->entry_list
,
6493 struct nest_entry
, list
);
6494 *attr_value
= entry
->attr_type
;
6495 list_del(&entry
->list
);
6501 static int cmd_fmsg_nest(struct fmsg_cb_data
*fmsg_data
, uint8_t nest_value
,
6504 struct dl
*dl
= fmsg_data
->dl
;
6505 uint8_t value
= nest_value
;
6508 err
= cmd_fmsg_nest_queue(fmsg_data
, &value
, start
);
6509 if (err
!= MNL_CB_OK
)
6513 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6515 pr_out_entry_start(dl
);
6517 pr_out_entry_end(dl
);
6519 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6521 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6522 if (dl
->json_output
) {
6524 jsonw_start_array(dl
->jw
);
6526 jsonw_end_array(dl
->jw
);
6530 __pr_out_indent_inc();
6532 __pr_out_indent_dec();
6542 static int cmd_fmsg_object_cb(const struct nlmsghdr
*nlh
, void *data
)
6544 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6545 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6546 struct fmsg_cb_data
*fmsg_data
= data
;
6547 struct dl
*dl
= fmsg_data
->dl
;
6548 struct nlattr
*nla_object
;
6552 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6553 if (!tb
[DEVLINK_ATTR_FMSG
])
6554 return MNL_CB_ERROR
;
6556 mnl_attr_for_each_nested(nla_object
, tb
[DEVLINK_ATTR_FMSG
]) {
6557 attr_type
= mnl_attr_get_type(nla_object
);
6558 switch (attr_type
) {
6559 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6560 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6561 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6562 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, true);
6563 if (err
!= MNL_CB_OK
)
6566 case DEVLINK_ATTR_FMSG_NEST_END
:
6567 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, false);
6568 if (err
!= MNL_CB_OK
)
6571 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
6572 pr_out_name(dl
, mnl_attr_get_str(nla_object
));
6574 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
:
6575 fmsg_data
->value_type
= mnl_attr_get_u8(nla_object
);
6577 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
6578 err
= fmsg_value_show(dl
, fmsg_data
->value_type
,
6580 if (err
!= MNL_CB_OK
)
6590 static int cmd_health_object_common(struct dl
*dl
, uint8_t cmd
, uint16_t flags
)
6592 struct fmsg_cb_data data
;
6593 struct nlmsghdr
*nlh
;
6596 nlh
= mnlg_msg_prepare(dl
->nlg
, cmd
, flags
| NLM_F_REQUEST
| NLM_F_ACK
);
6598 err
= dl_argv_parse_put(nlh
, dl
,
6599 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6604 INIT_LIST_HEAD(&data
.entry_list
);
6605 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_fmsg_object_cb
, &data
);
6609 static int cmd_health_dump_show(struct dl
*dl
)
6611 return cmd_health_object_common(dl
,
6612 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
,
6616 static int cmd_health_diagnose(struct dl
*dl
)
6618 return cmd_health_object_common(dl
,
6619 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
,
6623 static int cmd_health_recover(struct dl
*dl
)
6625 struct nlmsghdr
*nlh
;
6628 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
,
6629 NLM_F_REQUEST
| NLM_F_ACK
);
6631 err
= dl_argv_parse_put(nlh
, dl
,
6632 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6636 dl_opts_put(nlh
, dl
);
6637 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6640 enum devlink_health_reporter_state
{
6641 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
,
6642 DEVLINK_HEALTH_REPORTER_STATE_ERROR
,
6645 static const char *health_state_name(uint8_t state
)
6648 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
:
6649 return HEALTH_REPORTER_STATE_HEALTHY_STR
;
6650 case DEVLINK_HEALTH_REPORTER_STATE_ERROR
:
6651 return HEALTH_REPORTER_STATE_ERROR_STR
;
6653 return "<unknown state>";
6657 static void pr_out_dump_reporter_format_logtime(struct dl
*dl
, const struct nlattr
*attr
)
6659 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6660 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6661 uint64_t time_ms
= mnl_attr_get_u64(attr
);
6662 struct sysinfo s_info
;
6668 info
= localtime(&now
);
6669 err
= sysinfo(&s_info
);
6672 /* Subtract uptime in sec from now yields the time of system
6673 * uptime. To this, add time_ms which is the amount of
6674 * milliseconds elapsed between uptime and the dump taken.
6676 sec
= now
- s_info
.uptime
+ time_ms
/ 1000;
6677 info
= localtime(&sec
);
6679 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", info
);
6680 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", info
);
6681 pr_out_str(dl
, "last_dump_date", dump_date
);
6682 pr_out_str(dl
, "last_dump_time", dump_time
);
6685 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
)
6687 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6688 enum devlink_health_reporter_state state
;
6691 err
= mnl_attr_parse_nested(tb_health
[DEVLINK_ATTR_HEALTH_REPORTER
],
6693 if (err
!= MNL_CB_OK
)
6696 if (!tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
] ||
6697 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] ||
6698 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] ||
6699 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
])
6702 pr_out_handle_start_arr(dl
, tb_health
);
6704 pr_out_str(dl
, "reporter",
6705 mnl_attr_get_str(tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]));
6706 if (!dl
->json_output
) {
6708 __pr_out_indent_inc();
6710 state
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
]);
6711 pr_out_str(dl
, "state", health_state_name(state
));
6712 pr_out_u64(dl
, "error",
6713 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
]));
6714 pr_out_u64(dl
, "recover",
6715 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
]));
6716 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
])
6717 pr_out_dump_reporter_format_logtime(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
]);
6718 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
6719 pr_out_u64(dl
, "grace_period",
6720 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]));
6721 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
6722 pr_out_bool(dl
, "auto_recover",
6723 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]));
6725 __pr_out_indent_dec();
6726 pr_out_handle_end(dl
);
6729 static int cmd_health_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6731 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6732 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6733 struct dl
*dl
= data
;
6735 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6736 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6737 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
6738 return MNL_CB_ERROR
;
6740 pr_out_health(dl
, tb
);
6745 static int cmd_health_show(struct dl
*dl
)
6747 struct nlmsghdr
*nlh
;
6748 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6751 if (dl_argc(dl
) == 0)
6752 flags
|= NLM_F_DUMP
;
6753 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_GET
,
6756 if (dl_argc(dl
) > 0) {
6757 err
= dl_argv_parse_put(nlh
, dl
,
6759 DL_OPT_HEALTH_REPORTER_NAME
, 0);
6763 pr_out_section_start(dl
, "health");
6765 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_health_show_cb
, dl
);
6766 pr_out_section_end(dl
);
6770 static void cmd_health_help(void)
6772 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
6773 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
6774 pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n");
6775 pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n");
6776 pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n");
6777 pr_err(" devlink health set DEV reporter REPORTER_NAME { grace_period | auto_recover } { msec | boolean }\n");
6780 static int cmd_health(struct dl
*dl
)
6782 if (dl_argv_match(dl
, "help")) {
6785 } else if (dl_argv_match(dl
, "show") ||
6786 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
6788 return cmd_health_show(dl
);
6789 } else if (dl_argv_match(dl
, "recover")) {
6791 return cmd_health_recover(dl
);
6792 } else if (dl_argv_match(dl
, "diagnose")) {
6794 return cmd_health_diagnose(dl
);
6795 } else if (dl_argv_match(dl
, "dump")) {
6797 if (dl_argv_match(dl
, "show")) {
6799 return cmd_health_dump_show(dl
);
6800 } else if (dl_argv_match(dl
, "clear")) {
6802 return cmd_health_dump_clear(dl
);
6804 } else if (dl_argv_match(dl
, "set")) {
6806 return cmd_health_set_params(dl
);
6808 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6812 static const char *trap_type_name(uint8_t type
)
6815 case DEVLINK_TRAP_TYPE_DROP
:
6817 case DEVLINK_TRAP_TYPE_EXCEPTION
:
6820 return "<unknown type>";
6824 static const char *trap_action_name(uint8_t action
)
6827 case DEVLINK_TRAP_ACTION_DROP
:
6829 case DEVLINK_TRAP_ACTION_TRAP
:
6832 return "<unknown action>";
6836 static const char *trap_metadata_name(const struct nlattr
*attr
)
6838 switch (attr
->nla_type
) {
6839 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT
:
6840 return "input_port";
6842 return "<unknown metadata type>";
6845 static void pr_out_trap_metadata(struct dl
*dl
, struct nlattr
*attr
)
6847 struct nlattr
*attr_metadata
;
6849 pr_out_array_start(dl
, "metadata");
6850 mnl_attr_for_each_nested(attr_metadata
, attr
)
6851 pr_out_str_value(dl
, trap_metadata_name(attr_metadata
));
6852 pr_out_array_end(dl
);
6855 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
)
6857 uint8_t action
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_ACTION
]);
6858 uint8_t type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_TYPE
]);
6861 pr_out_handle_start_arr(dl
, tb
);
6863 __pr_out_handle_start(dl
, tb
, true, false);
6865 pr_out_str(dl
, "name", mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_NAME
]));
6866 pr_out_str(dl
, "type", trap_type_name(type
));
6867 pr_out_bool(dl
, "generic", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
6868 pr_out_str(dl
, "action", trap_action_name(action
));
6869 pr_out_str(dl
, "group",
6870 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
6872 pr_out_trap_metadata(dl
, tb
[DEVLINK_ATTR_TRAP_METADATA
]);
6873 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
6874 pr_out_handle_end(dl
);
6877 static int cmd_trap_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6879 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6880 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6881 struct dl
*dl
= data
;
6883 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6884 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6885 !tb
[DEVLINK_ATTR_TRAP_NAME
] || !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
6886 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
6887 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
6888 !tb
[DEVLINK_ATTR_TRAP_METADATA
] || !tb
[DEVLINK_ATTR_STATS
])
6889 return MNL_CB_ERROR
;
6891 pr_out_trap(dl
, tb
, true);
6896 static void cmd_trap_help(void)
6898 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop } ]\n");
6899 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
6900 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop } ]\n");
6901 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
6904 static int cmd_trap_show(struct dl
*dl
)
6906 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6907 struct nlmsghdr
*nlh
;
6910 if (dl_argc(dl
) == 0)
6911 flags
|= NLM_F_DUMP
;
6913 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GET
, flags
);
6915 if (dl_argc(dl
) > 0) {
6916 err
= dl_argv_parse_put(nlh
, dl
,
6917 DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
, 0);
6922 pr_out_section_start(dl
, "trap");
6923 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_show_cb
, dl
);
6924 pr_out_section_end(dl
);
6929 static int cmd_trap_set(struct dl
*dl
)
6931 struct nlmsghdr
*nlh
;
6934 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_SET
,
6935 NLM_F_REQUEST
| NLM_F_ACK
);
6937 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
,
6938 DL_OPT_TRAP_ACTION
);
6942 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6945 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
)
6948 pr_out_handle_start_arr(dl
, tb
);
6950 __pr_out_handle_start(dl
, tb
, true, false);
6952 pr_out_str(dl
, "name",
6953 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
6954 pr_out_bool(dl
, "generic", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
6955 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
6956 pr_out_handle_end(dl
);
6959 static int cmd_trap_group_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6961 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6962 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6963 struct dl
*dl
= data
;
6965 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6966 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6967 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] || !tb
[DEVLINK_ATTR_STATS
])
6968 return MNL_CB_ERROR
;
6970 pr_out_trap_group(dl
, tb
, true);
6975 static int cmd_trap_group_show(struct dl
*dl
)
6977 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6978 struct nlmsghdr
*nlh
;
6981 if (dl_argc(dl
) == 0)
6982 flags
|= NLM_F_DUMP
;
6984 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_GET
, flags
);
6986 if (dl_argc(dl
) > 0) {
6987 err
= dl_argv_parse_put(nlh
, dl
,
6988 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
6994 pr_out_section_start(dl
, "trap_group");
6995 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_group_show_cb
, dl
);
6996 pr_out_section_end(dl
);
7001 static int cmd_trap_group_set(struct dl
*dl
)
7003 struct nlmsghdr
*nlh
;
7006 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_SET
,
7007 NLM_F_REQUEST
| NLM_F_ACK
);
7009 err
= dl_argv_parse_put(nlh
, dl
,
7010 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7011 DL_OPT_TRAP_ACTION
);
7015 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7018 static int cmd_trap_group(struct dl
*dl
)
7020 if (dl_argv_match(dl
, "help")) {
7023 } else if (dl_argv_match(dl
, "show") ||
7024 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7026 return cmd_trap_group_show(dl
);
7027 } else if (dl_argv_match(dl
, "set")) {
7029 return cmd_trap_group_set(dl
);
7031 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7035 static int cmd_trap(struct dl
*dl
)
7037 if (dl_argv_match(dl
, "help")) {
7040 } else if (dl_argv_match(dl
, "show") ||
7041 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7043 return cmd_trap_show(dl
);
7044 } else if (dl_argv_match(dl
, "set")) {
7046 return cmd_trap_set(dl
);
7047 } else if (dl_argv_match(dl
, "group")) {
7049 return cmd_trap_group(dl
);
7051 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7055 static void help(void)
7057 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
7058 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
7059 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
7060 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
7063 static int dl_cmd(struct dl
*dl
, int argc
, char **argv
)
7068 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
7071 } else if (dl_argv_match(dl
, "dev")) {
7074 } else if (dl_argv_match(dl
, "port")) {
7076 return cmd_port(dl
);
7077 } else if (dl_argv_match(dl
, "sb")) {
7080 } else if (dl_argv_match(dl
, "monitor")) {
7083 } else if (dl_argv_match(dl
, "dpipe")) {
7085 return cmd_dpipe(dl
);
7086 } else if (dl_argv_match(dl
, "resource")) {
7088 return cmd_resource(dl
);
7089 } else if (dl_argv_match(dl
, "region")) {
7091 return cmd_region(dl
);
7092 } else if (dl_argv_match(dl
, "health")) {
7094 return cmd_health(dl
);
7095 } else if (dl_argv_match(dl
, "trap")) {
7097 return cmd_trap(dl
);
7099 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
7103 static int dl_init(struct dl
*dl
)
7107 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
7109 pr_err("Failed to connect to devlink Netlink\n");
7113 err
= ifname_map_init(dl
);
7115 pr_err("Failed to create index map\n");
7116 goto err_ifname_map_create
;
7118 if (dl
->json_output
) {
7119 dl
->jw
= jsonw_new(stdout
);
7121 pr_err("Failed to create JSON writer\n");
7124 jsonw_pretty(dl
->jw
, dl
->pretty_output
);
7129 ifname_map_fini(dl
);
7130 err_ifname_map_create
:
7131 mnlg_socket_close(dl
->nlg
);
7135 static void dl_fini(struct dl
*dl
)
7137 if (dl
->json_output
)
7138 jsonw_destroy(&dl
->jw
);
7139 ifname_map_fini(dl
);
7140 mnlg_socket_close(dl
->nlg
);
7143 static struct dl
*dl_alloc(void)
7147 dl
= calloc(1, sizeof(*dl
));
7153 static void dl_free(struct dl
*dl
)
7158 static int dl_batch(struct dl
*dl
, const char *name
, bool force
)
7162 int ret
= EXIT_SUCCESS
;
7164 if (name
&& strcmp(name
, "-") != 0) {
7165 if (freopen(name
, "r", stdin
) == NULL
) {
7167 "Cannot open file \"%s\" for reading: %s\n",
7168 name
, strerror(errno
));
7169 return EXIT_FAILURE
;
7174 while (getcmdline(&line
, &len
, stdin
) != -1) {
7178 largc
= makeargs(line
, largv
, 100);
7180 continue; /* blank line */
7182 if (dl_cmd(dl
, largc
, largv
)) {
7183 fprintf(stderr
, "Command failed %s:%d\n",
7197 int main(int argc
, char **argv
)
7199 static const struct option long_options
[] = {
7200 { "Version", no_argument
, NULL
, 'V' },
7201 { "force", no_argument
, NULL
, 'f' },
7202 { "batch", required_argument
, NULL
, 'b' },
7203 { "no-nice-names", no_argument
, NULL
, 'n' },
7204 { "json", no_argument
, NULL
, 'j' },
7205 { "pretty", no_argument
, NULL
, 'p' },
7206 { "verbose", no_argument
, NULL
, 'v' },
7207 { "statistics", no_argument
, NULL
, 's' },
7208 { "Netns", required_argument
, NULL
, 'N' },
7209 { NULL
, 0, NULL
, 0 }
7211 const char *batch_file
= NULL
;
7220 pr_err("Failed to allocate memory for devlink\n");
7221 return EXIT_FAILURE
;
7224 while ((opt
= getopt_long(argc
, argv
, "Vfb:njpvsN:",
7225 long_options
, NULL
)) >= 0) {
7229 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
7236 batch_file
= optarg
;
7239 dl
->no_nice_names
= true;
7242 dl
->json_output
= true;
7245 dl
->pretty_output
= true;
7254 if (netns_switch(optarg
)) {
7260 pr_err("Unknown option.\n");
7277 err
= dl_batch(dl
, batch_file
, force
);
7279 err
= dl_cmd(dl
, argc
, argv
);