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 ESWITCH_ENCAP_MODE_NONE "none"
45 #define ESWITCH_ENCAP_MODE_BASIC "basic"
47 #define PARAM_CMODE_RUNTIME_STR "runtime"
48 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
49 #define PARAM_CMODE_PERMANENT_STR "permanent"
50 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
52 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
53 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
54 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
56 static int g_new_line_count
;
57 static int g_indent_level
;
58 static bool g_indent_newline
;
60 #define INDENT_STR_STEP 2
61 #define INDENT_STR_MAXLEN 32
62 static char g_indent_str
[INDENT_STR_MAXLEN
+ 1] = "";
64 static void __attribute__((format(printf
, 1, 2)))
65 pr_err(const char *fmt
, ...)
70 vfprintf(stderr
, fmt
, ap
);
74 static void __attribute__((format(printf
, 1, 2)))
75 pr_out(const char *fmt
, ...)
79 if (g_indent_newline
) {
80 printf("%s", g_indent_str
);
81 g_indent_newline
= false;
89 static void __attribute__((format(printf
, 2, 3)))
90 pr_out_sp(unsigned int num
, const char *fmt
, ...)
96 ret
= vprintf(fmt
, ap
);
100 printf("%*s", num
- ret
, "");
101 g_new_line_count
= 0; \
104 static void __attribute__((format(printf
, 1, 2)))
105 pr_out_tty(const char *fmt
, ...)
109 if (!isatty(STDOUT_FILENO
))
116 static void __pr_out_indent_inc(void)
118 if (g_indent_level
+ INDENT_STR_STEP
> INDENT_STR_MAXLEN
)
120 g_indent_level
+= INDENT_STR_STEP
;
121 memset(g_indent_str
, ' ', sizeof(g_indent_str
));
122 g_indent_str
[g_indent_level
] = '\0';
125 static void __pr_out_indent_dec(void)
127 if (g_indent_level
- INDENT_STR_STEP
< 0)
129 g_indent_level
-= INDENT_STR_STEP
;
130 g_indent_str
[g_indent_level
] = '\0';
133 static void __pr_out_newline(void)
135 if (g_new_line_count
< 1) {
137 g_indent_newline
= true;
142 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
143 mnl_cb_t data_cb
, void *data
)
147 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
149 pr_err("devlink answers: %s\n", strerror(errno
));
155 static int _mnlg_socket_send(struct mnlg_socket
*nlg
,
156 const struct nlmsghdr
*nlh
)
160 err
= mnlg_socket_send(nlg
, nlh
);
162 pr_err("Failed to call mnlg_socket_send\n");
168 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
169 const struct nlmsghdr
*nlh
,
170 mnl_cb_t data_cb
, void *data
)
174 err
= _mnlg_socket_send(nlg
, nlh
);
177 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
180 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
181 const char *group_name
)
185 err
= mnlg_socket_group_add(nlg
, group_name
);
187 pr_err("Failed to call mnlg_socket_group_add\n");
194 struct list_head list
;
201 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
202 const char *dev_name
,
206 struct ifname_map
*ifname_map
;
208 ifname_map
= calloc(1, sizeof(*ifname_map
));
211 ifname_map
->bus_name
= strdup(bus_name
);
212 ifname_map
->dev_name
= strdup(dev_name
);
213 ifname_map
->port_index
= port_index
;
214 ifname_map
->ifname
= strdup(ifname
);
215 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
216 !ifname_map
->ifname
) {
217 free(ifname_map
->ifname
);
218 free(ifname_map
->dev_name
);
219 free(ifname_map
->bus_name
);
226 static void ifname_map_free(struct ifname_map
*ifname_map
)
228 free(ifname_map
->ifname
);
229 free(ifname_map
->dev_name
);
230 free(ifname_map
->bus_name
);
234 #define DL_OPT_HANDLE BIT(0)
235 #define DL_OPT_HANDLEP BIT(1)
236 #define DL_OPT_PORT_TYPE BIT(2)
237 #define DL_OPT_PORT_COUNT BIT(3)
238 #define DL_OPT_SB BIT(4)
239 #define DL_OPT_SB_POOL BIT(5)
240 #define DL_OPT_SB_SIZE BIT(6)
241 #define DL_OPT_SB_TYPE BIT(7)
242 #define DL_OPT_SB_THTYPE BIT(8)
243 #define DL_OPT_SB_TH BIT(9)
244 #define DL_OPT_SB_TC BIT(10)
245 #define DL_OPT_ESWITCH_MODE BIT(11)
246 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
247 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
248 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
249 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
250 #define DL_OPT_RESOURCE_PATH BIT(16)
251 #define DL_OPT_RESOURCE_SIZE BIT(17)
252 #define DL_OPT_PARAM_NAME BIT(18)
253 #define DL_OPT_PARAM_VALUE BIT(19)
254 #define DL_OPT_PARAM_CMODE BIT(20)
255 #define DL_OPT_HANDLE_REGION BIT(21)
256 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
257 #define DL_OPT_REGION_ADDRESS BIT(23)
258 #define DL_OPT_REGION_LENGTH BIT(24)
259 #define DL_OPT_FLASH_FILE_NAME BIT(25)
260 #define DL_OPT_FLASH_COMPONENT BIT(26)
261 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
262 #define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(28)
263 #define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(29)
264 #define DL_OPT_TRAP_NAME BIT(30)
265 #define DL_OPT_TRAP_ACTION BIT(31)
266 #define DL_OPT_TRAP_GROUP_NAME BIT(32)
267 #define DL_OPT_NETNS BIT(33)
268 #define DL_OPT_TRAP_POLICER_ID BIT(34)
269 #define DL_OPT_TRAP_POLICER_RATE BIT(35)
270 #define DL_OPT_TRAP_POLICER_BURST BIT(36)
273 uint64_t present
; /* flags of present items */
277 enum devlink_port_type port_type
;
280 uint16_t sb_pool_index
;
281 uint32_t sb_pool_size
;
282 enum devlink_sb_pool_type sb_pool_type
;
283 enum devlink_sb_threshold_type sb_pool_thtype
;
284 uint32_t sb_threshold
;
285 uint16_t sb_tc_index
;
286 enum devlink_eswitch_mode eswitch_mode
;
287 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
288 const char *dpipe_table_name
;
289 bool dpipe_counters_enable
;
290 enum devlink_eswitch_encap_mode eswitch_encap_mode
;
291 const char *resource_path
;
292 uint64_t resource_size
;
293 uint32_t resource_id
;
294 bool resource_id_valid
;
295 const char *param_name
;
296 const char *param_value
;
297 enum devlink_param_cmode cmode
;
299 uint32_t region_snapshot_id
;
300 uint64_t region_address
;
301 uint64_t region_length
;
302 const char *flash_file_name
;
303 const char *flash_component
;
304 const char *reporter_name
;
305 uint64_t reporter_graceful_period
;
306 bool reporter_auto_recover
;
307 const char *trap_name
;
308 const char *trap_group_name
;
309 enum devlink_trap_action trap_action
;
312 uint32_t trap_policer_id
;
313 uint64_t trap_policer_rate
;
314 uint64_t trap_policer_burst
;
318 struct mnlg_socket
*nlg
;
319 struct list_head ifname_map_list
;
337 static int dl_argc(struct dl
*dl
)
342 static char *dl_argv(struct dl
*dl
)
344 if (dl_argc(dl
) == 0)
349 static void dl_arg_inc(struct dl
*dl
)
351 if (dl_argc(dl
) == 0)
357 static void dl_arg_dec(struct dl
*dl
)
363 static char *dl_argv_next(struct dl
*dl
)
367 if (dl_argc(dl
) == 0)
375 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
377 if (index
>= dl_argc(dl
))
379 return dl
->argv
[index
];
382 static int strcmpx(const char *str1
, const char *str2
)
384 if (strlen(str1
) > strlen(str2
))
386 return strncmp(str1
, str2
, strlen(str1
));
389 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
391 if (dl_argc(dl
) == 0)
393 return strcmpx(dl_argv(dl
), pattern
) == 0;
396 static bool dl_no_arg(struct dl
*dl
)
398 return dl_argc(dl
) == 0;
401 static void __pr_out_indent_newline(struct dl
*dl
)
403 if (!g_indent_newline
&& !dl
->json_output
)
407 static void check_indent_newline(struct dl
*dl
)
409 __pr_out_indent_newline(dl
);
411 if (g_indent_newline
&& !is_json_context()) {
412 printf("%s", g_indent_str
);
413 g_indent_newline
= false;
415 g_new_line_count
= 0;
418 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
419 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
420 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
421 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
422 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
423 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
424 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
425 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
426 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
427 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
428 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
429 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
430 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
431 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
432 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
433 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
434 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
435 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
436 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
437 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
438 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
439 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
440 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
441 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
442 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
443 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
444 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
445 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
446 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
447 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
448 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
449 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
450 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
451 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
452 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
453 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
454 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
455 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
456 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
457 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
458 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
459 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
460 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
461 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
462 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
463 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
464 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
465 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
466 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
467 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
468 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
469 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
470 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
471 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
472 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
473 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
474 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
475 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
476 [DEVLINK_ATTR_PARAM
] = MNL_TYPE_NESTED
,
477 [DEVLINK_ATTR_PARAM_NAME
] = MNL_TYPE_STRING
,
478 [DEVLINK_ATTR_PARAM_TYPE
] = MNL_TYPE_U8
,
479 [DEVLINK_ATTR_PARAM_VALUES_LIST
] = MNL_TYPE_NESTED
,
480 [DEVLINK_ATTR_PARAM_VALUE
] = MNL_TYPE_NESTED
,
481 [DEVLINK_ATTR_PARAM_VALUE_CMODE
] = MNL_TYPE_U8
,
482 [DEVLINK_ATTR_REGION_NAME
] = MNL_TYPE_STRING
,
483 [DEVLINK_ATTR_REGION_SIZE
] = MNL_TYPE_U64
,
484 [DEVLINK_ATTR_REGION_SNAPSHOTS
] = MNL_TYPE_NESTED
,
485 [DEVLINK_ATTR_REGION_SNAPSHOT
] = MNL_TYPE_NESTED
,
486 [DEVLINK_ATTR_REGION_SNAPSHOT_ID
] = MNL_TYPE_U32
,
487 [DEVLINK_ATTR_REGION_CHUNKS
] = MNL_TYPE_NESTED
,
488 [DEVLINK_ATTR_REGION_CHUNK
] = MNL_TYPE_NESTED
,
489 [DEVLINK_ATTR_REGION_CHUNK_DATA
] = MNL_TYPE_BINARY
,
490 [DEVLINK_ATTR_REGION_CHUNK_ADDR
] = MNL_TYPE_U64
,
491 [DEVLINK_ATTR_REGION_CHUNK_LEN
] = MNL_TYPE_U64
,
492 [DEVLINK_ATTR_INFO_DRIVER_NAME
] = MNL_TYPE_STRING
,
493 [DEVLINK_ATTR_INFO_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
494 [DEVLINK_ATTR_INFO_VERSION_FIXED
] = MNL_TYPE_NESTED
,
495 [DEVLINK_ATTR_INFO_VERSION_RUNNING
] = MNL_TYPE_NESTED
,
496 [DEVLINK_ATTR_INFO_VERSION_STORED
] = MNL_TYPE_NESTED
,
497 [DEVLINK_ATTR_INFO_VERSION_NAME
] = MNL_TYPE_STRING
,
498 [DEVLINK_ATTR_INFO_VERSION_VALUE
] = MNL_TYPE_STRING
,
499 [DEVLINK_ATTR_HEALTH_REPORTER
] = MNL_TYPE_NESTED
,
500 [DEVLINK_ATTR_HEALTH_REPORTER_NAME
] = MNL_TYPE_STRING
,
501 [DEVLINK_ATTR_HEALTH_REPORTER_STATE
] = MNL_TYPE_U8
,
502 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] = MNL_TYPE_U64
,
503 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] = MNL_TYPE_U64
,
504 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
] = MNL_TYPE_U64
,
505 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] = MNL_TYPE_U64
,
506 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
] = MNL_TYPE_STRING
,
507 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
] = MNL_TYPE_STRING
,
508 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
] = MNL_TYPE_U64
,
509 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
] = MNL_TYPE_U64
,
510 [DEVLINK_ATTR_STATS
] = MNL_TYPE_NESTED
,
511 [DEVLINK_ATTR_TRAP_NAME
] = MNL_TYPE_STRING
,
512 [DEVLINK_ATTR_TRAP_ACTION
] = MNL_TYPE_U8
,
513 [DEVLINK_ATTR_TRAP_TYPE
] = MNL_TYPE_U8
,
514 [DEVLINK_ATTR_TRAP_GENERIC
] = MNL_TYPE_FLAG
,
515 [DEVLINK_ATTR_TRAP_METADATA
] = MNL_TYPE_NESTED
,
516 [DEVLINK_ATTR_TRAP_GROUP_NAME
] = MNL_TYPE_STRING
,
517 [DEVLINK_ATTR_RELOAD_FAILED
] = MNL_TYPE_U8
,
518 [DEVLINK_ATTR_TRAP_POLICER_ID
] = MNL_TYPE_U32
,
519 [DEVLINK_ATTR_TRAP_POLICER_RATE
] = MNL_TYPE_U64
,
520 [DEVLINK_ATTR_TRAP_POLICER_BURST
] = MNL_TYPE_U64
,
523 static const enum mnl_attr_data_type
524 devlink_stats_policy
[DEVLINK_ATTR_STATS_MAX
+ 1] = {
525 [DEVLINK_ATTR_STATS_RX_PACKETS
] = MNL_TYPE_U64
,
526 [DEVLINK_ATTR_STATS_RX_BYTES
] = MNL_TYPE_U64
,
527 [DEVLINK_ATTR_STATS_RX_DROPPED
] = MNL_TYPE_U64
,
530 static int attr_cb(const struct nlattr
*attr
, void *data
)
532 const struct nlattr
**tb
= data
;
535 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
538 type
= mnl_attr_get_type(attr
);
539 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
546 static int attr_stats_cb(const struct nlattr
*attr
, void *data
)
548 const struct nlattr
**tb
= data
;
551 /* Allow the tool to work on top of newer kernels that might contain
554 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_STATS_MAX
) < 0)
557 type
= mnl_attr_get_type(attr
);
558 if (mnl_attr_validate(attr
, devlink_stats_policy
[type
]) < 0)
565 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
567 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
568 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
569 struct dl
*dl
= data
;
570 struct ifname_map
*ifname_map
;
571 const char *bus_name
;
572 const char *dev_name
;
573 uint32_t port_ifindex
;
574 const char *port_ifname
;
576 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
577 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
578 !tb
[DEVLINK_ATTR_PORT_INDEX
])
581 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
584 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
585 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
586 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
587 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
588 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
589 port_ifindex
, port_ifname
);
592 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
597 static void ifname_map_fini(struct dl
*dl
)
599 struct ifname_map
*ifname_map
, *tmp
;
601 list_for_each_entry_safe(ifname_map
, tmp
,
602 &dl
->ifname_map_list
, list
) {
603 list_del(&ifname_map
->list
);
604 ifname_map_free(ifname_map
);
608 static int ifname_map_init(struct dl
*dl
)
610 struct nlmsghdr
*nlh
;
613 INIT_LIST_HEAD(&dl
->ifname_map_list
);
615 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
616 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
618 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
626 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
627 char **p_bus_name
, char **p_dev_name
,
628 uint32_t *p_port_index
)
630 struct ifname_map
*ifname_map
;
632 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
633 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
634 *p_bus_name
= ifname_map
->bus_name
;
635 *p_dev_name
= ifname_map
->dev_name
;
636 *p_port_index
= ifname_map
->port_index
;
643 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
644 const char *dev_name
, uint32_t port_index
,
647 struct ifname_map
*ifname_map
;
649 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
650 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
651 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
652 port_index
== ifname_map
->port_index
) {
653 *p_ifname
= ifname_map
->ifname
;
660 static unsigned int strslashcount(char *str
)
662 unsigned int count
= 0;
665 while ((pos
= strchr(pos
, '/'))) {
672 static int strslashrsplit(char *str
, char **before
, char **after
)
676 slash
= strrchr(str
, '/');
685 static int strtouint64_t(const char *str
, uint64_t *p_val
)
688 unsigned long long int val
;
690 val
= strtoull(str
, &endptr
, 10);
691 if (endptr
== str
|| *endptr
!= '\0')
699 static int strtouint32_t(const char *str
, uint32_t *p_val
)
702 unsigned long int val
;
704 val
= strtoul(str
, &endptr
, 10);
705 if (endptr
== str
|| *endptr
!= '\0')
713 static int strtouint16_t(const char *str
, uint16_t *p_val
)
716 unsigned long int val
;
718 val
= strtoul(str
, &endptr
, 10);
719 if (endptr
== str
|| *endptr
!= '\0')
727 static int strtouint8_t(const char *str
, uint8_t *p_val
)
730 unsigned long int val
;
732 val
= strtoul(str
, &endptr
, 10);
733 if (endptr
== str
|| *endptr
!= '\0')
741 static int strtobool(const char *str
, bool *p_val
)
745 if (!strcmp(str
, "true") || !strcmp(str
, "1") ||
746 !strcmp(str
, "enable"))
748 else if (!strcmp(str
, "false") || !strcmp(str
, "0") ||
749 !strcmp(str
, "disable"))
757 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
759 strslashrsplit(str
, p_bus_name
, p_dev_name
);
763 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
765 char *str
= dl_argv_next(dl
);
768 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
771 if (strslashcount(str
) != 1) {
772 pr_err("Wrong devlink identification string format.\n");
773 pr_err("Expected \"bus_name/dev_name\".\n");
776 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
779 static int __dl_argv_handle_port(char *str
,
780 char **p_bus_name
, char **p_dev_name
,
781 uint32_t *p_port_index
)
787 err
= strslashrsplit(str
, &handlestr
, &portstr
);
789 pr_err("Port identification \"%s\" is invalid\n", str
);
792 err
= strtouint32_t(portstr
, p_port_index
);
794 pr_err("Port index \"%s\" is not a number or not within range\n",
798 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
800 pr_err("Port identification \"%s\" is invalid\n", str
);
806 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
807 char **p_bus_name
, char **p_dev_name
,
808 uint32_t *p_port_index
)
812 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
815 pr_err("Netdevice \"%s\" not found\n", str
);
821 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
822 char **p_dev_name
, uint32_t *p_port_index
)
824 char *str
= dl_argv_next(dl
);
825 unsigned int slash_count
;
828 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
831 slash_count
= strslashcount(str
);
832 switch (slash_count
) {
834 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
835 p_dev_name
, p_port_index
);
837 return __dl_argv_handle_port(str
, p_bus_name
,
838 p_dev_name
, p_port_index
);
840 pr_err("Wrong port identification string format.\n");
841 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
846 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
847 char **p_dev_name
, uint32_t *p_port_index
,
848 uint64_t *p_handle_bit
)
850 char *str
= dl_argv_next(dl
);
851 unsigned int slash_count
;
855 pr_err("One of following identifications expected:\n"
856 "Devlink identification (\"bus_name/dev_name\")\n"
857 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
860 slash_count
= strslashcount(str
);
861 if (slash_count
== 1) {
862 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
865 *p_handle_bit
= DL_OPT_HANDLE
;
866 } else if (slash_count
== 2) {
867 err
= __dl_argv_handle_port(str
, p_bus_name
,
868 p_dev_name
, p_port_index
);
871 *p_handle_bit
= DL_OPT_HANDLEP
;
872 } else if (slash_count
== 0) {
873 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
874 p_dev_name
, p_port_index
);
877 *p_handle_bit
= DL_OPT_HANDLEP
;
879 pr_err("Wrong port identification string format.\n");
880 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
886 static int __dl_argv_handle_region(char *str
, char **p_bus_name
,
887 char **p_dev_name
, char **p_region
)
892 err
= strslashrsplit(str
, &handlestr
, p_region
);
894 pr_err("Region identification \"%s\" is invalid\n", str
);
897 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
899 pr_err("Region identification \"%s\" is invalid\n", str
);
905 static int dl_argv_handle_region(struct dl
*dl
, char **p_bus_name
,
906 char **p_dev_name
, char **p_region
)
908 char *str
= dl_argv_next(dl
);
909 unsigned int slash_count
;
912 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
916 slash_count
= strslashcount(str
);
917 if (slash_count
!= 2) {
918 pr_err("Wrong region identification string format.\n");
919 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
923 return __dl_argv_handle_region(str
, p_bus_name
, p_dev_name
, p_region
);
926 static int dl_argv_uint64_t(struct dl
*dl
, uint64_t *p_val
)
928 char *str
= dl_argv_next(dl
);
932 pr_err("Unsigned number argument expected\n");
936 err
= strtouint64_t(str
, p_val
);
938 pr_err("\"%s\" is not a number or not within range\n", str
);
944 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
946 char *str
= dl_argv_next(dl
);
950 pr_err("Unsigned number argument expected\n");
954 err
= strtouint32_t(str
, p_val
);
956 pr_err("\"%s\" is not a number or not within range\n", str
);
962 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
964 char *str
= dl_argv_next(dl
);
968 pr_err("Unsigned number argument expected\n");
972 err
= strtouint16_t(str
, p_val
);
974 pr_err("\"%s\" is not a number or not within range\n", str
);
980 static int dl_argv_bool(struct dl
*dl
, bool *p_val
)
982 char *str
= dl_argv_next(dl
);
986 pr_err("Boolean argument expected\n");
990 err
= strtobool(str
, p_val
);
992 pr_err("\"%s\" is not a valid boolean value\n", str
);
998 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
1000 const char *str
= dl_argv_next(dl
);
1003 pr_err("String parameter expected\n");
1010 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
1012 if (strcmp(typestr
, "auto") == 0) {
1013 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
1014 } else if (strcmp(typestr
, "eth") == 0) {
1015 *p_type
= DEVLINK_PORT_TYPE_ETH
;
1016 } else if (strcmp(typestr
, "ib") == 0) {
1017 *p_type
= DEVLINK_PORT_TYPE_IB
;
1019 pr_err("Unknown port type \"%s\"\n", typestr
);
1025 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
1027 if (strcmp(typestr
, "ingress") == 0) {
1028 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
1029 } else if (strcmp(typestr
, "egress") == 0) {
1030 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
1032 pr_err("Unknown pool type \"%s\"\n", typestr
);
1038 static int threshold_type_get(const char *typestr
,
1039 enum devlink_sb_threshold_type
*p_type
)
1041 if (strcmp(typestr
, "static") == 0) {
1042 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
1043 } else if (strcmp(typestr
, "dynamic") == 0) {
1044 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
1046 pr_err("Unknown threshold type \"%s\"\n", typestr
);
1052 static int eswitch_mode_get(const char *typestr
,
1053 enum devlink_eswitch_mode
*p_mode
)
1055 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
1056 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
1057 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
1058 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
1060 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
1066 static int eswitch_inline_mode_get(const char *typestr
,
1067 enum devlink_eswitch_inline_mode
*p_mode
)
1069 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
1070 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
1071 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
1072 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
1073 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
1074 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
1075 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
1076 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
1078 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
1085 eswitch_encap_mode_get(const char *typestr
,
1086 enum devlink_eswitch_encap_mode
*p_encap_mode
)
1088 /* The initial implementation incorrectly accepted "enable"/"disable".
1089 * Carry it to maintain backward compatibility.
1091 if (strcmp(typestr
, "disable") == 0 ||
1092 strcmp(typestr
, ESWITCH_ENCAP_MODE_NONE
) == 0) {
1093 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_NONE
;
1094 } else if (strcmp(typestr
, "enable") == 0 ||
1095 strcmp(typestr
, ESWITCH_ENCAP_MODE_BASIC
) == 0) {
1096 *p_encap_mode
= DEVLINK_ESWITCH_ENCAP_MODE_BASIC
;
1098 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
1104 static int param_cmode_get(const char *cmodestr
,
1105 enum devlink_param_cmode
*cmode
)
1107 if (strcmp(cmodestr
, PARAM_CMODE_RUNTIME_STR
) == 0) {
1108 *cmode
= DEVLINK_PARAM_CMODE_RUNTIME
;
1109 } else if (strcmp(cmodestr
, PARAM_CMODE_DRIVERINIT_STR
) == 0) {
1110 *cmode
= DEVLINK_PARAM_CMODE_DRIVERINIT
;
1111 } else if (strcmp(cmodestr
, PARAM_CMODE_PERMANENT_STR
) == 0) {
1112 *cmode
= DEVLINK_PARAM_CMODE_PERMANENT
;
1114 pr_err("Unknown configuration mode \"%s\"\n", cmodestr
);
1120 static int trap_action_get(const char *actionstr
,
1121 enum devlink_trap_action
*p_action
)
1123 if (strcmp(actionstr
, "drop") == 0) {
1124 *p_action
= DEVLINK_TRAP_ACTION_DROP
;
1125 } else if (strcmp(actionstr
, "trap") == 0) {
1126 *p_action
= DEVLINK_TRAP_ACTION_TRAP
;
1128 pr_err("Unknown trap action \"%s\"\n", actionstr
);
1134 struct dl_args_metadata
{
1136 char err_msg
[DL_ARGS_REQUIRED_MAX_ERR_LEN
];
1139 static const struct dl_args_metadata dl_args_required
[] = {
1140 {DL_OPT_PORT_TYPE
, "Port type not set."},
1141 {DL_OPT_PORT_COUNT
, "Port split count option expected."},
1142 {DL_OPT_SB_POOL
, "Pool index option expected."},
1143 {DL_OPT_SB_SIZE
, "Pool size option expected."},
1144 {DL_OPT_SB_TYPE
, "Pool type option expected."},
1145 {DL_OPT_SB_THTYPE
, "Pool threshold type option expected."},
1146 {DL_OPT_SB_TH
, "Threshold option expected."},
1147 {DL_OPT_SB_TC
, "TC index option expected."},
1148 {DL_OPT_ESWITCH_MODE
, "E-Switch mode option expected."},
1149 {DL_OPT_ESWITCH_INLINE_MODE
, "E-Switch inline-mode option expected."},
1150 {DL_OPT_DPIPE_TABLE_NAME
, "Dpipe table name expected."},
1151 {DL_OPT_DPIPE_TABLE_COUNTERS
, "Dpipe table counter state expected."},
1152 {DL_OPT_ESWITCH_ENCAP_MODE
, "E-Switch encapsulation option expected."},
1153 {DL_OPT_RESOURCE_PATH
, "Resource path expected."},
1154 {DL_OPT_RESOURCE_SIZE
, "Resource size expected."},
1155 {DL_OPT_PARAM_NAME
, "Parameter name expected."},
1156 {DL_OPT_PARAM_VALUE
, "Value to set expected."},
1157 {DL_OPT_PARAM_CMODE
, "Configuration mode expected."},
1158 {DL_OPT_REGION_SNAPSHOT_ID
, "Region snapshot id expected."},
1159 {DL_OPT_REGION_ADDRESS
, "Region address value expected."},
1160 {DL_OPT_REGION_LENGTH
, "Region length value expected."},
1161 {DL_OPT_HEALTH_REPORTER_NAME
, "Reporter's name is expected."},
1162 {DL_OPT_TRAP_NAME
, "Trap's name is expected."},
1163 {DL_OPT_TRAP_GROUP_NAME
, "Trap group's name is expected."},
1166 static int dl_args_finding_required_validate(uint64_t o_required
,
1172 for (i
= 0; i
< ARRAY_SIZE(dl_args_required
); i
++) {
1173 o_flag
= dl_args_required
[i
].o_flag
;
1174 if ((o_required
& o_flag
) && !(o_found
& o_flag
)) {
1175 pr_err("%s\n", dl_args_required
[i
].err_msg
);
1179 if (o_required
& ~o_found
) {
1180 pr_err("BUG: unknown argument required but not found\n");
1186 static int dl_argv_parse(struct dl
*dl
, uint64_t o_required
,
1187 uint64_t o_optional
)
1189 struct dl_opts
*opts
= &dl
->opts
;
1190 uint64_t o_all
= o_required
| o_optional
;
1191 uint64_t o_found
= 0;
1194 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
1195 uint64_t handle_bit
;
1197 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
1198 &opts
->port_index
, &handle_bit
);
1201 o_required
&= ~(DL_OPT_HANDLE
| DL_OPT_HANDLEP
) | handle_bit
;
1202 o_found
|= handle_bit
;
1203 } else if (o_required
& DL_OPT_HANDLE
) {
1204 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
1207 o_found
|= DL_OPT_HANDLE
;
1208 } else if (o_required
& DL_OPT_HANDLEP
) {
1209 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
1213 o_found
|= DL_OPT_HANDLEP
;
1214 } else if (o_required
& DL_OPT_HANDLE_REGION
) {
1215 err
= dl_argv_handle_region(dl
, &opts
->bus_name
,
1217 &opts
->region_name
);
1220 o_found
|= DL_OPT_HANDLE_REGION
;
1223 while (dl_argc(dl
)) {
1224 if (dl_argv_match(dl
, "type") &&
1225 (o_all
& DL_OPT_PORT_TYPE
)) {
1226 const char *typestr
;
1229 err
= dl_argv_str(dl
, &typestr
);
1232 err
= port_type_get(typestr
, &opts
->port_type
);
1235 o_found
|= DL_OPT_PORT_TYPE
;
1236 } else if (dl_argv_match(dl
, "count") &&
1237 (o_all
& DL_OPT_PORT_COUNT
)) {
1239 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
1242 o_found
|= DL_OPT_PORT_COUNT
;
1243 } else if (dl_argv_match(dl
, "sb") &&
1244 (o_all
& DL_OPT_SB
)) {
1246 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
1249 o_found
|= DL_OPT_SB
;
1250 } else if (dl_argv_match(dl
, "pool") &&
1251 (o_all
& DL_OPT_SB_POOL
)) {
1253 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
1256 o_found
|= DL_OPT_SB_POOL
;
1257 } else if (dl_argv_match(dl
, "size") &&
1258 (o_all
& DL_OPT_SB_SIZE
)) {
1260 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
1263 o_found
|= DL_OPT_SB_SIZE
;
1264 } else if (dl_argv_match(dl
, "type") &&
1265 (o_all
& DL_OPT_SB_TYPE
)) {
1266 const char *typestr
;
1269 err
= dl_argv_str(dl
, &typestr
);
1272 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
1275 o_found
|= DL_OPT_SB_TYPE
;
1276 } else if (dl_argv_match(dl
, "thtype") &&
1277 (o_all
& DL_OPT_SB_THTYPE
)) {
1278 const char *typestr
;
1281 err
= dl_argv_str(dl
, &typestr
);
1284 err
= threshold_type_get(typestr
,
1285 &opts
->sb_pool_thtype
);
1288 o_found
|= DL_OPT_SB_THTYPE
;
1289 } else if (dl_argv_match(dl
, "th") &&
1290 (o_all
& DL_OPT_SB_TH
)) {
1292 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
1295 o_found
|= DL_OPT_SB_TH
;
1296 } else if (dl_argv_match(dl
, "tc") &&
1297 (o_all
& DL_OPT_SB_TC
)) {
1299 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
1302 o_found
|= DL_OPT_SB_TC
;
1303 } else if (dl_argv_match(dl
, "mode") &&
1304 (o_all
& DL_OPT_ESWITCH_MODE
)) {
1305 const char *typestr
;
1308 err
= dl_argv_str(dl
, &typestr
);
1311 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
1314 o_found
|= DL_OPT_ESWITCH_MODE
;
1315 } else if (dl_argv_match(dl
, "inline-mode") &&
1316 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1317 const char *typestr
;
1320 err
= dl_argv_str(dl
, &typestr
);
1323 err
= eswitch_inline_mode_get(
1324 typestr
, &opts
->eswitch_inline_mode
);
1327 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
1328 } else if (dl_argv_match(dl
, "name") &&
1329 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
1331 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
1334 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
1335 } else if ((dl_argv_match(dl
, "counters") ||
1336 dl_argv_match(dl
, "counters_enabled")) &&
1337 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1339 err
= dl_argv_bool(dl
, &opts
->dpipe_counters_enable
);
1342 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
1343 } else if ((dl_argv_match(dl
, "encap") || /* Original incorrect implementation */
1344 dl_argv_match(dl
, "encap-mode")) &&
1345 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1346 const char *typestr
;
1349 err
= dl_argv_str(dl
, &typestr
);
1352 err
= eswitch_encap_mode_get(typestr
,
1353 &opts
->eswitch_encap_mode
);
1356 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
1357 } else if (dl_argv_match(dl
, "path") &&
1358 (o_all
& DL_OPT_RESOURCE_PATH
)) {
1360 err
= dl_argv_str(dl
, &opts
->resource_path
);
1363 o_found
|= DL_OPT_RESOURCE_PATH
;
1364 } else if (dl_argv_match(dl
, "size") &&
1365 (o_all
& DL_OPT_RESOURCE_SIZE
)) {
1367 err
= dl_argv_uint64_t(dl
, &opts
->resource_size
);
1370 o_found
|= DL_OPT_RESOURCE_SIZE
;
1371 } else if (dl_argv_match(dl
, "name") &&
1372 (o_all
& DL_OPT_PARAM_NAME
)) {
1374 err
= dl_argv_str(dl
, &opts
->param_name
);
1377 o_found
|= DL_OPT_PARAM_NAME
;
1378 } else if (dl_argv_match(dl
, "value") &&
1379 (o_all
& DL_OPT_PARAM_VALUE
)) {
1381 err
= dl_argv_str(dl
, &opts
->param_value
);
1384 o_found
|= DL_OPT_PARAM_VALUE
;
1385 } else if (dl_argv_match(dl
, "cmode") &&
1386 (o_all
& DL_OPT_PARAM_CMODE
)) {
1387 const char *cmodestr
;
1390 err
= dl_argv_str(dl
, &cmodestr
);
1393 err
= param_cmode_get(cmodestr
, &opts
->cmode
);
1396 o_found
|= DL_OPT_PARAM_CMODE
;
1397 } else if (dl_argv_match(dl
, "snapshot") &&
1398 (o_all
& DL_OPT_REGION_SNAPSHOT_ID
)) {
1400 err
= dl_argv_uint32_t(dl
, &opts
->region_snapshot_id
);
1403 o_found
|= DL_OPT_REGION_SNAPSHOT_ID
;
1404 } else if (dl_argv_match(dl
, "address") &&
1405 (o_all
& DL_OPT_REGION_ADDRESS
)) {
1407 err
= dl_argv_uint64_t(dl
, &opts
->region_address
);
1410 o_found
|= DL_OPT_REGION_ADDRESS
;
1411 } else if (dl_argv_match(dl
, "length") &&
1412 (o_all
& DL_OPT_REGION_LENGTH
)) {
1414 err
= dl_argv_uint64_t(dl
, &opts
->region_length
);
1417 o_found
|= DL_OPT_REGION_LENGTH
;
1418 } else if (dl_argv_match(dl
, "file") &&
1419 (o_all
& DL_OPT_FLASH_FILE_NAME
)) {
1421 err
= dl_argv_str(dl
, &opts
->flash_file_name
);
1424 o_found
|= DL_OPT_FLASH_FILE_NAME
;
1425 } else if (dl_argv_match(dl
, "component") &&
1426 (o_all
& DL_OPT_FLASH_COMPONENT
)) {
1428 err
= dl_argv_str(dl
, &opts
->flash_component
);
1431 o_found
|= DL_OPT_FLASH_COMPONENT
;
1432 } else if (dl_argv_match(dl
, "reporter") &&
1433 (o_all
& DL_OPT_HEALTH_REPORTER_NAME
)) {
1435 err
= dl_argv_str(dl
, &opts
->reporter_name
);
1438 o_found
|= DL_OPT_HEALTH_REPORTER_NAME
;
1439 } else if (dl_argv_match(dl
, "grace_period") &&
1440 (o_all
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)) {
1442 err
= dl_argv_uint64_t(dl
,
1443 &opts
->reporter_graceful_period
);
1446 o_found
|= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
;
1447 } else if (dl_argv_match(dl
, "auto_recover") &&
1448 (o_all
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)) {
1450 err
= dl_argv_bool(dl
, &opts
->reporter_auto_recover
);
1453 o_found
|= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
;
1454 } else if (dl_argv_match(dl
, "trap") &&
1455 (o_all
& DL_OPT_TRAP_NAME
)) {
1457 err
= dl_argv_str(dl
, &opts
->trap_name
);
1460 o_found
|= DL_OPT_TRAP_NAME
;
1461 } else if (dl_argv_match(dl
, "group") &&
1462 (o_all
& DL_OPT_TRAP_GROUP_NAME
)) {
1464 err
= dl_argv_str(dl
, &opts
->trap_group_name
);
1467 o_found
|= DL_OPT_TRAP_GROUP_NAME
;
1468 } else if (dl_argv_match(dl
, "action") &&
1469 (o_all
& DL_OPT_TRAP_ACTION
)) {
1470 const char *actionstr
;
1473 err
= dl_argv_str(dl
, &actionstr
);
1476 err
= trap_action_get(actionstr
, &opts
->trap_action
);
1479 o_found
|= DL_OPT_TRAP_ACTION
;
1480 } else if (dl_argv_match(dl
, "netns") &&
1481 (o_all
& DL_OPT_NETNS
)) {
1482 const char *netns_str
;
1485 err
= dl_argv_str(dl
, &netns_str
);
1488 opts
->netns
= netns_get_fd(netns_str
);
1489 if ((int)opts
->netns
< 0) {
1491 err
= dl_argv_uint32_t(dl
, &opts
->netns
);
1494 opts
->netns_is_pid
= true;
1496 o_found
|= DL_OPT_NETNS
;
1497 } else if (dl_argv_match(dl
, "policer") &&
1498 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1500 err
= dl_argv_uint32_t(dl
, &opts
->trap_policer_id
);
1503 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1504 } else if (dl_argv_match(dl
, "nopolicer") &&
1505 (o_all
& DL_OPT_TRAP_POLICER_ID
)) {
1507 opts
->trap_policer_id
= 0;
1508 o_found
|= DL_OPT_TRAP_POLICER_ID
;
1509 } else if (dl_argv_match(dl
, "rate") &&
1510 (o_all
& DL_OPT_TRAP_POLICER_RATE
)) {
1512 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_rate
);
1515 o_found
|= DL_OPT_TRAP_POLICER_RATE
;
1516 } else if (dl_argv_match(dl
, "burst") &&
1517 (o_all
& DL_OPT_TRAP_POLICER_BURST
)) {
1519 err
= dl_argv_uint64_t(dl
, &opts
->trap_policer_burst
);
1522 o_found
|= DL_OPT_TRAP_POLICER_BURST
;
1524 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
1529 opts
->present
= o_found
;
1531 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
1533 opts
->present
|= DL_OPT_SB
;
1536 return dl_args_finding_required_validate(o_required
, o_found
);
1539 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1541 struct dl_opts
*opts
= &dl
->opts
;
1543 if (opts
->present
& DL_OPT_HANDLE
) {
1544 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1545 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1546 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1547 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1548 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1549 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1551 } else if (opts
->present
& DL_OPT_HANDLE_REGION
) {
1552 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1553 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1554 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_REGION_NAME
,
1557 if (opts
->present
& DL_OPT_PORT_TYPE
)
1558 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1560 if (opts
->present
& DL_OPT_PORT_COUNT
)
1561 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1563 if (opts
->present
& DL_OPT_SB
)
1564 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1566 if (opts
->present
& DL_OPT_SB_POOL
)
1567 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1568 opts
->sb_pool_index
);
1569 if (opts
->present
& DL_OPT_SB_SIZE
)
1570 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1571 opts
->sb_pool_size
);
1572 if (opts
->present
& DL_OPT_SB_TYPE
)
1573 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1574 opts
->sb_pool_type
);
1575 if (opts
->present
& DL_OPT_SB_THTYPE
)
1576 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1577 opts
->sb_pool_thtype
);
1578 if (opts
->present
& DL_OPT_SB_TH
)
1579 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1580 opts
->sb_threshold
);
1581 if (opts
->present
& DL_OPT_SB_TC
)
1582 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1584 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1585 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1586 opts
->eswitch_mode
);
1587 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1588 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1589 opts
->eswitch_inline_mode
);
1590 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1591 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1592 opts
->dpipe_table_name
);
1593 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1594 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1595 opts
->dpipe_counters_enable
);
1596 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1597 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1598 opts
->eswitch_encap_mode
);
1599 if ((opts
->present
& DL_OPT_RESOURCE_PATH
) && opts
->resource_id_valid
)
1600 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_ID
,
1602 if (opts
->present
& DL_OPT_RESOURCE_SIZE
)
1603 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_SIZE
,
1604 opts
->resource_size
);
1605 if (opts
->present
& DL_OPT_PARAM_NAME
)
1606 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_NAME
,
1608 if (opts
->present
& DL_OPT_PARAM_CMODE
)
1609 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_CMODE
,
1611 if (opts
->present
& DL_OPT_REGION_SNAPSHOT_ID
)
1612 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_REGION_SNAPSHOT_ID
,
1613 opts
->region_snapshot_id
);
1614 if (opts
->present
& DL_OPT_REGION_ADDRESS
)
1615 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_ADDR
,
1616 opts
->region_address
);
1617 if (opts
->present
& DL_OPT_REGION_LENGTH
)
1618 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_LEN
,
1619 opts
->region_length
);
1620 if (opts
->present
& DL_OPT_FLASH_FILE_NAME
)
1621 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME
,
1622 opts
->flash_file_name
);
1623 if (opts
->present
& DL_OPT_FLASH_COMPONENT
)
1624 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
,
1625 opts
->flash_component
);
1626 if (opts
->present
& DL_OPT_HEALTH_REPORTER_NAME
)
1627 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
1628 opts
->reporter_name
);
1629 if (opts
->present
& DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
)
1630 mnl_attr_put_u64(nlh
,
1631 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
,
1632 opts
->reporter_graceful_period
);
1633 if (opts
->present
& DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
)
1634 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
,
1635 opts
->reporter_auto_recover
);
1636 if (opts
->present
& DL_OPT_TRAP_NAME
)
1637 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_NAME
,
1639 if (opts
->present
& DL_OPT_TRAP_GROUP_NAME
)
1640 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_TRAP_GROUP_NAME
,
1641 opts
->trap_group_name
);
1642 if (opts
->present
& DL_OPT_TRAP_ACTION
)
1643 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_TRAP_ACTION
,
1645 if (opts
->present
& DL_OPT_NETNS
)
1646 mnl_attr_put_u32(nlh
,
1647 opts
->netns_is_pid
? DEVLINK_ATTR_NETNS_PID
:
1648 DEVLINK_ATTR_NETNS_FD
,
1650 if (opts
->present
& DL_OPT_TRAP_POLICER_ID
)
1651 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_TRAP_POLICER_ID
,
1652 opts
->trap_policer_id
);
1653 if (opts
->present
& DL_OPT_TRAP_POLICER_RATE
)
1654 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_RATE
,
1655 opts
->trap_policer_rate
);
1656 if (opts
->present
& DL_OPT_TRAP_POLICER_BURST
)
1657 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_TRAP_POLICER_BURST
,
1658 opts
->trap_policer_burst
);
1661 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1662 uint64_t o_required
, uint64_t o_optional
)
1666 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1669 dl_opts_put(nlh
, dl
);
1673 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1675 struct dl_opts
*opts
= &dl
->opts
;
1676 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1677 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1678 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1679 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1681 if (opts
->present
& DL_OPT_HANDLE
&&
1682 attr_bus_name
&& attr_dev_name
) {
1683 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1684 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1686 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1687 strcmp(dev_name
, opts
->dev_name
) != 0)
1690 if (opts
->present
& DL_OPT_HANDLEP
&&
1691 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1692 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1693 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1694 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1696 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1697 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1698 port_index
!= opts
->port_index
)
1701 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1702 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1704 if (sb_index
!= opts
->sb_index
)
1710 static void cmd_dev_help(void)
1712 pr_err("Usage: devlink dev show [ DEV ]\n");
1713 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1714 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1715 pr_err(" [ encap-mode { none | basic } ]\n");
1716 pr_err(" devlink dev eswitch show DEV\n");
1717 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1718 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1719 pr_err(" devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
1720 pr_err(" devlink dev info [ DEV ]\n");
1721 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1724 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1725 const char *dev_name
)
1727 if (!dl
->arr_last
.present
)
1729 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1730 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1733 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1734 const char *dev_name
)
1736 dl
->arr_last
.present
= true;
1737 free(dl
->arr_last
.dev_name
);
1738 free(dl
->arr_last
.bus_name
);
1739 dl
->arr_last
.bus_name
= strdup(bus_name
);
1740 dl
->arr_last
.dev_name
= strdup(dev_name
);
1743 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1744 const char *dev_name
)
1746 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1749 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1750 const char *dev_name
)
1752 return dl
->arr_last
.present
&&
1753 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1756 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1757 bool content
, bool array
)
1759 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1760 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1763 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
1765 if (dl
->json_output
) {
1767 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1768 close_json_array(PRINT_JSON
, NULL
);
1769 if (should_arr_last_handle_start(dl
, bus_name
,
1771 open_json_array(PRINT_JSON
, buf
);
1772 open_json_object(NULL
);
1773 arr_last_handle_set(dl
, bus_name
, dev_name
);
1775 open_json_object(NULL
);
1778 open_json_object(buf
);
1782 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1783 __pr_out_indent_dec();
1784 if (should_arr_last_handle_start(dl
, bus_name
,
1786 pr_out("%s%s", buf
, content
? ":" : "");
1788 __pr_out_indent_inc();
1789 arr_last_handle_set(dl
, bus_name
, dev_name
);
1792 pr_out("%s%s", buf
, content
? ":" : "");
1797 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
1799 __pr_out_handle_start(dl
, tb
, true, true);
1802 static void pr_out_handle_end(struct dl
*dl
)
1804 if (dl
->json_output
)
1805 close_json_object();
1810 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
1812 __pr_out_handle_start(dl
, tb
, false, false);
1813 pr_out_handle_end(dl
);
1816 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
1817 const char *dev_name
, uint32_t port_index
)
1819 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
1820 dl
->arr_last
.port_index
== port_index
;
1823 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
1824 const char *dev_name
, uint32_t port_index
)
1826 arr_last_handle_set(dl
, bus_name
, dev_name
);
1827 dl
->arr_last
.port_index
= port_index
;
1830 static bool should_arr_last_port_handle_start(struct dl
*dl
,
1831 const char *bus_name
,
1832 const char *dev_name
,
1833 uint32_t port_index
)
1835 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1838 static bool should_arr_last_port_handle_end(struct dl
*dl
,
1839 const char *bus_name
,
1840 const char *dev_name
,
1841 uint32_t port_index
)
1843 return dl
->arr_last
.present
&&
1844 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1847 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
1848 const char *dev_name
,
1849 uint32_t port_index
, bool try_nice
,
1852 static char buf
[64];
1853 char *ifname
= NULL
;
1855 if (dl
->no_nice_names
|| !try_nice
||
1856 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
1857 port_index
, &ifname
) != 0)
1858 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
1860 sprintf(buf
, "%s", ifname
);
1862 if (dl
->json_output
) {
1864 if (should_arr_last_port_handle_end(dl
, bus_name
,
1867 close_json_array(PRINT_JSON
, NULL
);
1868 if (should_arr_last_port_handle_start(dl
, bus_name
,
1871 open_json_array(PRINT_JSON
, buf
);
1872 open_json_object(NULL
);
1873 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
1876 open_json_object(NULL
);
1879 open_json_object(buf
);
1886 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1888 const char *bus_name
;
1889 const char *dev_name
;
1890 uint32_t port_index
;
1892 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1893 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1894 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1895 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
1898 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1900 const char *bus_name
;
1901 const char *dev_name
;
1902 uint32_t port_index
;
1904 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1905 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1906 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1907 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
1910 static void pr_out_port_handle_end(struct dl
*dl
)
1912 if (dl
->json_output
)
1913 close_json_object();
1918 static void pr_out_u64(struct dl
*dl
, const char *name
, uint64_t val
)
1920 __pr_out_indent_newline(dl
);
1921 if (val
== (uint64_t) -1)
1922 return print_string_name_value(name
, "unlimited");
1924 if (dl
->json_output
)
1925 print_u64(PRINT_JSON
, name
, NULL
, val
);
1927 pr_out("%s %"PRIu64
, name
, val
);
1930 static bool is_binary_eol(int i
)
1935 static void pr_out_binary_value(struct dl
*dl
, uint8_t *data
, uint32_t len
)
1940 if (dl
->json_output
)
1941 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
1943 pr_out("%02x ", data
[i
]);
1945 if (!dl
->json_output
&& is_binary_eol(i
))
1948 if (!dl
->json_output
&& !is_binary_eol(i
))
1952 static void pr_out_name(struct dl
*dl
, const char *name
)
1954 __pr_out_indent_newline(dl
);
1955 if (dl
->json_output
)
1956 print_string(PRINT_JSON
, name
, NULL
, NULL
);
1958 pr_out("%s:", name
);
1961 static void pr_out_region_chunk_start(struct dl
*dl
, uint64_t addr
)
1963 if (dl
->json_output
) {
1964 print_uint(PRINT_JSON
, "address", NULL
, addr
);
1965 open_json_array(PRINT_JSON
, "data");
1969 static void pr_out_region_chunk_end(struct dl
*dl
)
1971 if (dl
->json_output
)
1972 close_json_array(PRINT_JSON
, NULL
);
1975 static void pr_out_region_chunk(struct dl
*dl
, uint8_t *data
, uint32_t len
,
1978 static uint64_t align_val
;
1981 pr_out_region_chunk_start(dl
, addr
);
1983 if (!dl
->json_output
)
1984 if (!(align_val
% 16))
1985 pr_out("%s%016"PRIx64
" ",
1986 align_val
? "\n" : "",
1991 if (dl
->json_output
)
1992 print_int(PRINT_JSON
, NULL
, NULL
, data
[i
]);
1994 pr_out("%02x ", data
[i
]);
1999 pr_out_region_chunk_end(dl
);
2002 static void pr_out_section_start(struct dl
*dl
, const char *name
)
2004 if (dl
->json_output
) {
2005 open_json_object(NULL
);
2006 open_json_object(name
);
2010 static void pr_out_section_end(struct dl
*dl
)
2012 if (dl
->json_output
) {
2013 if (dl
->arr_last
.present
)
2014 close_json_array(PRINT_JSON
, NULL
);
2015 close_json_object();
2016 close_json_object();
2020 static void pr_out_array_start(struct dl
*dl
, const char *name
)
2022 if (dl
->json_output
) {
2023 open_json_array(PRINT_JSON
, name
);
2025 __pr_out_indent_inc();
2027 pr_out("%s:", name
);
2028 __pr_out_indent_inc();
2033 static void pr_out_array_end(struct dl
*dl
)
2035 if (dl
->json_output
) {
2036 close_json_array(PRINT_JSON
, NULL
);
2038 __pr_out_indent_dec();
2039 __pr_out_indent_dec();
2043 static void pr_out_object_start(struct dl
*dl
, const char *name
)
2045 if (dl
->json_output
) {
2046 open_json_object(name
);
2048 __pr_out_indent_inc();
2050 pr_out("%s:", name
);
2051 __pr_out_indent_inc();
2056 static void pr_out_object_end(struct dl
*dl
)
2058 if (dl
->json_output
) {
2059 close_json_object();
2061 __pr_out_indent_dec();
2062 __pr_out_indent_dec();
2066 static void pr_out_entry_start(struct dl
*dl
)
2068 if (dl
->json_output
)
2069 open_json_object(NULL
);
2072 static void pr_out_entry_end(struct dl
*dl
)
2074 if (dl
->json_output
)
2075 close_json_object();
2080 static void pr_out_stats(struct dl
*dl
, struct nlattr
*nla_stats
)
2082 struct nlattr
*tb
[DEVLINK_ATTR_STATS_MAX
+ 1] = {};
2088 err
= mnl_attr_parse_nested(nla_stats
, attr_stats_cb
, tb
);
2089 if (err
!= MNL_CB_OK
)
2092 pr_out_object_start(dl
, "stats");
2093 pr_out_object_start(dl
, "rx");
2094 if (tb
[DEVLINK_ATTR_STATS_RX_BYTES
])
2095 pr_out_u64(dl
, "bytes",
2096 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_BYTES
]));
2097 if (tb
[DEVLINK_ATTR_STATS_RX_PACKETS
])
2098 pr_out_u64(dl
, "packets",
2099 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_PACKETS
]));
2100 if (tb
[DEVLINK_ATTR_STATS_RX_DROPPED
])
2101 pr_out_u64(dl
, "dropped",
2102 mnl_attr_get_u64(tb
[DEVLINK_ATTR_STATS_RX_DROPPED
]));
2103 pr_out_object_end(dl
);
2104 pr_out_object_end(dl
);
2107 static const char *param_cmode_name(uint8_t cmode
)
2110 case DEVLINK_PARAM_CMODE_RUNTIME
:
2111 return PARAM_CMODE_RUNTIME_STR
;
2112 case DEVLINK_PARAM_CMODE_DRIVERINIT
:
2113 return PARAM_CMODE_DRIVERINIT_STR
;
2114 case DEVLINK_PARAM_CMODE_PERMANENT
:
2115 return PARAM_CMODE_PERMANENT_STR
;
2116 default: return "<unknown type>";
2120 static const char *eswitch_mode_name(uint32_t mode
)
2123 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
2124 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
2125 default: return "<unknown mode>";
2129 static const char *eswitch_inline_mode_name(uint32_t mode
)
2132 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
2133 return ESWITCH_INLINE_MODE_NONE
;
2134 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
2135 return ESWITCH_INLINE_MODE_LINK
;
2136 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
2137 return ESWITCH_INLINE_MODE_NETWORK
;
2138 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
2139 return ESWITCH_INLINE_MODE_TRANSPORT
;
2141 return "<unknown mode>";
2145 static const char *eswitch_encap_mode_name(uint32_t mode
)
2148 case DEVLINK_ESWITCH_ENCAP_MODE_NONE
:
2149 return ESWITCH_ENCAP_MODE_NONE
;
2150 case DEVLINK_ESWITCH_ENCAP_MODE_BASIC
:
2151 return ESWITCH_ENCAP_MODE_BASIC
;
2153 return "<unknown mode>";
2157 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
2159 __pr_out_handle_start(dl
, tb
, true, false);
2161 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
]) {
2162 check_indent_newline(dl
);
2163 print_string(PRINT_ANY
, "mode", "mode %s",
2164 eswitch_mode_name(mnl_attr_get_u16(
2165 tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
2167 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
]) {
2168 check_indent_newline(dl
);
2169 print_string(PRINT_ANY
, "inline-mode", "inline-mode %s",
2170 eswitch_inline_mode_name(mnl_attr_get_u8(
2171 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
2173 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
2174 check_indent_newline(dl
);
2175 print_string(PRINT_ANY
, "encap-mode", "encap-mode %s",
2176 eswitch_encap_mode_name(mnl_attr_get_u8(
2177 tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
])));
2180 pr_out_handle_end(dl
);
2183 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2185 struct dl
*dl
= data
;
2186 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2187 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2189 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2190 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2191 return MNL_CB_ERROR
;
2192 pr_out_eswitch(dl
, tb
);
2196 static int cmd_dev_eswitch_show(struct dl
*dl
)
2198 struct nlmsghdr
*nlh
;
2201 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
2202 NLM_F_REQUEST
| NLM_F_ACK
);
2204 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2208 pr_out_section_start(dl
, "dev");
2209 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
2210 pr_out_section_end(dl
);
2214 static int cmd_dev_eswitch_set(struct dl
*dl
)
2216 struct nlmsghdr
*nlh
;
2219 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
2220 NLM_F_REQUEST
| NLM_F_ACK
);
2222 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
2223 DL_OPT_ESWITCH_MODE
|
2224 DL_OPT_ESWITCH_INLINE_MODE
|
2225 DL_OPT_ESWITCH_ENCAP_MODE
);
2230 if (dl
->opts
.present
== 1) {
2231 pr_err("Need to set at least one option\n");
2235 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2238 static int cmd_dev_eswitch(struct dl
*dl
)
2240 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2243 } else if (dl_argv_match(dl
, "set")) {
2245 return cmd_dev_eswitch_set(dl
);
2246 } else if (dl_argv_match(dl
, "show")) {
2248 return cmd_dev_eswitch_show(dl
);
2250 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2254 struct param_val_conv
{
2260 static bool param_val_conv_exists(const struct param_val_conv
*param_val_conv
,
2261 uint32_t len
, const char *name
)
2265 for (i
= 0; i
< len
; i
++)
2266 if (!strcmp(param_val_conv
[i
].name
, name
))
2273 param_val_conv_uint_get(const struct param_val_conv
*param_val_conv
,
2274 uint32_t len
, const char *name
, const char *vstr
,
2279 for (i
= 0; i
< len
; i
++)
2280 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2281 !strcmp(param_val_conv
[i
].vstr
, vstr
)) {
2282 *vuint
= param_val_conv
[i
].vuint
;
2290 param_val_conv_str_get(const struct param_val_conv
*param_val_conv
,
2291 uint32_t len
, const char *name
, uint32_t vuint
,
2296 for (i
= 0; i
< len
; i
++)
2297 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2298 param_val_conv
[i
].vuint
== vuint
) {
2299 *vstr
= param_val_conv
[i
].vstr
;
2306 static const struct param_val_conv param_val_conv
[] = {
2308 .name
= "fw_load_policy",
2310 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER
,
2313 .name
= "fw_load_policy",
2315 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH
,
2318 .name
= "reset_dev_on_drv_probe",
2320 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN
,
2323 .name
= "fw_load_policy",
2325 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN
,
2328 .name
= "reset_dev_on_drv_probe",
2330 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS
,
2333 .name
= "reset_dev_on_drv_probe",
2335 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER
,
2338 .name
= "reset_dev_on_drv_probe",
2340 .vuint
= DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK
,
2344 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2346 static void pr_out_param_value(struct dl
*dl
, const char *nla_name
,
2347 int nla_type
, struct nlattr
*nl
)
2349 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2350 struct nlattr
*val_attr
;
2355 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_value
);
2356 if (err
!= MNL_CB_OK
)
2359 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2360 (nla_type
!= MNL_TYPE_FLAG
&&
2361 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2364 check_indent_newline(dl
);
2365 print_string(PRINT_ANY
, "cmode", "cmode %s",
2366 param_cmode_name(mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
])));
2368 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2370 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2376 err
= param_val_conv_str_get(param_val_conv
,
2379 mnl_attr_get_u8(val_attr
),
2383 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2385 print_uint(PRINT_ANY
, "value", " value %u",
2386 mnl_attr_get_u8(val_attr
));
2391 err
= param_val_conv_str_get(param_val_conv
,
2394 mnl_attr_get_u16(val_attr
),
2398 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2400 print_uint(PRINT_ANY
, "value", " value %u",
2401 mnl_attr_get_u16(val_attr
));
2406 err
= param_val_conv_str_get(param_val_conv
,
2409 mnl_attr_get_u32(val_attr
),
2413 print_string(PRINT_ANY
, "value", " value %s", vstr
);
2415 print_uint(PRINT_ANY
, "value", " value %u",
2416 mnl_attr_get_u32(val_attr
));
2419 case MNL_TYPE_STRING
:
2420 print_string(PRINT_ANY
, "value", " value %s",
2421 mnl_attr_get_str(val_attr
));
2424 print_bool(PRINT_ANY
, "value", " value %s", val_attr
);
2429 static void pr_out_param(struct dl
*dl
, struct nlattr
**tb
, bool array
)
2431 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2432 struct nlattr
*param_value_attr
;
2433 const char *nla_name
;
2437 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2438 if (err
!= MNL_CB_OK
)
2440 if (!nla_param
[DEVLINK_ATTR_PARAM_NAME
] ||
2441 !nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2442 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2446 pr_out_handle_start_arr(dl
, tb
);
2448 __pr_out_handle_start(dl
, tb
, true, false);
2450 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2452 nla_name
= mnl_attr_get_str(nla_param
[DEVLINK_ATTR_PARAM_NAME
]);
2453 check_indent_newline(dl
);
2454 print_string(PRINT_ANY
, "name", "name %s ", nla_name
);
2455 if (!nla_param
[DEVLINK_ATTR_PARAM_GENERIC
])
2456 print_string(PRINT_ANY
, "type", "type %s", "driver-specific");
2458 print_string(PRINT_ANY
, "type", "type %s", "generic");
2460 pr_out_array_start(dl
, "values");
2461 mnl_attr_for_each_nested(param_value_attr
,
2462 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2463 pr_out_entry_start(dl
);
2464 pr_out_param_value(dl
, nla_name
, nla_type
, param_value_attr
);
2465 pr_out_entry_end(dl
);
2467 pr_out_array_end(dl
);
2468 pr_out_handle_end(dl
);
2471 static int cmd_dev_param_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2473 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2474 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2475 struct dl
*dl
= data
;
2477 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2478 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2479 !tb
[DEVLINK_ATTR_PARAM
])
2480 return MNL_CB_ERROR
;
2481 pr_out_param(dl
, tb
, true);
2497 static int cmd_dev_param_set_cb(const struct nlmsghdr
*nlh
, void *data
)
2499 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2500 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2501 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2502 struct nlattr
*param_value_attr
;
2503 enum devlink_param_cmode cmode
;
2504 struct param_ctx
*ctx
= data
;
2505 struct dl
*dl
= ctx
->dl
;
2509 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2510 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2511 !tb
[DEVLINK_ATTR_PARAM
])
2512 return MNL_CB_ERROR
;
2514 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2515 if (err
!= MNL_CB_OK
)
2516 return MNL_CB_ERROR
;
2518 if (!nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2519 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2520 return MNL_CB_ERROR
;
2522 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2523 mnl_attr_for_each_nested(param_value_attr
,
2524 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2525 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2526 struct nlattr
*val_attr
;
2528 err
= mnl_attr_parse_nested(param_value_attr
,
2529 attr_cb
, nla_value
);
2530 if (err
!= MNL_CB_OK
)
2531 return MNL_CB_ERROR
;
2533 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2534 (nla_type
!= MNL_TYPE_FLAG
&&
2535 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2536 return MNL_CB_ERROR
;
2538 cmode
= mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
]);
2539 if (cmode
== dl
->opts
.cmode
) {
2540 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2543 ctx
->value
.vu8
= mnl_attr_get_u8(val_attr
);
2546 ctx
->value
.vu16
= mnl_attr_get_u16(val_attr
);
2549 ctx
->value
.vu32
= mnl_attr_get_u32(val_attr
);
2551 case MNL_TYPE_STRING
:
2552 ctx
->value
.vstr
= mnl_attr_get_str(val_attr
);
2555 ctx
->value
.vbool
= val_attr
? true : false;
2561 ctx
->nla_type
= nla_type
;
2565 static int cmd_dev_param_set(struct dl
*dl
)
2567 struct param_ctx ctx
= {};
2568 struct nlmsghdr
*nlh
;
2576 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
|
2578 DL_OPT_PARAM_VALUE
|
2579 DL_OPT_PARAM_CMODE
, 0);
2583 /* Get value type */
2584 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
,
2585 NLM_F_REQUEST
| NLM_F_ACK
);
2586 dl_opts_put(nlh
, dl
);
2589 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_set_cb
, &ctx
);
2593 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_SET
,
2594 NLM_F_REQUEST
| NLM_F_ACK
);
2595 dl_opts_put(nlh
, dl
);
2597 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2598 dl
->opts
.param_name
);
2600 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_TYPE
, ctx
.nla_type
);
2601 switch (ctx
.nla_type
) {
2604 err
= param_val_conv_uint_get(param_val_conv
,
2606 dl
->opts
.param_name
,
2607 dl
->opts
.param_value
,
2611 err
= strtouint8_t(dl
->opts
.param_value
, &val_u8
);
2614 goto err_param_value_parse
;
2615 if (val_u8
== ctx
.value
.vu8
)
2617 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u8
);
2621 err
= param_val_conv_uint_get(param_val_conv
,
2623 dl
->opts
.param_name
,
2624 dl
->opts
.param_value
,
2628 err
= strtouint16_t(dl
->opts
.param_value
, &val_u16
);
2631 goto err_param_value_parse
;
2632 if (val_u16
== ctx
.value
.vu16
)
2634 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u16
);
2638 err
= param_val_conv_uint_get(param_val_conv
,
2640 dl
->opts
.param_name
,
2641 dl
->opts
.param_value
,
2644 err
= strtouint32_t(dl
->opts
.param_value
, &val_u32
);
2646 goto err_param_value_parse
;
2647 if (val_u32
== ctx
.value
.vu32
)
2649 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u32
);
2652 err
= strtobool(dl
->opts
.param_value
, &val_bool
);
2654 goto err_param_value_parse
;
2655 if (val_bool
== ctx
.value
.vbool
)
2658 mnl_attr_put(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2661 case MNL_TYPE_STRING
:
2662 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2663 dl
->opts
.param_value
);
2664 if (!strcmp(dl
->opts
.param_value
, ctx
.value
.vstr
))
2668 printf("Value type not supported\n");
2671 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2673 err_param_value_parse
:
2674 pr_err("Value \"%s\" is not a number or not within range\n",
2675 dl
->opts
.param_value
);
2679 static int cmd_dev_param_show(struct dl
*dl
)
2681 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2682 struct nlmsghdr
*nlh
;
2685 if (dl_argc(dl
) == 0)
2686 flags
|= NLM_F_DUMP
;
2688 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
, flags
);
2690 if (dl_argc(dl
) > 0) {
2691 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
|
2692 DL_OPT_PARAM_NAME
, 0);
2697 pr_out_section_start(dl
, "param");
2698 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_show_cb
, dl
);
2699 pr_out_section_end(dl
);
2703 static int cmd_dev_param(struct dl
*dl
)
2705 if (dl_argv_match(dl
, "help")) {
2708 } else if (dl_argv_match(dl
, "show") ||
2709 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2711 return cmd_dev_param_show(dl
);
2712 } else if (dl_argv_match(dl
, "set")) {
2714 return cmd_dev_param_set(dl
);
2716 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2719 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2721 struct dl
*dl
= data
;
2722 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2723 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2724 uint8_t reload_failed
= 0;
2726 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2727 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2728 return MNL_CB_ERROR
;
2730 if (tb
[DEVLINK_ATTR_RELOAD_FAILED
])
2731 reload_failed
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_RELOAD_FAILED
]);
2733 if (reload_failed
) {
2734 __pr_out_handle_start(dl
, tb
, true, false);
2735 check_indent_newline(dl
);
2736 print_bool(PRINT_ANY
, "reload_failed", "reload_failed %s", true);
2737 pr_out_handle_end(dl
);
2739 pr_out_handle(dl
, tb
);
2745 static int cmd_dev_show(struct dl
*dl
)
2747 struct nlmsghdr
*nlh
;
2748 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2751 if (dl_argc(dl
) == 0)
2752 flags
|= NLM_F_DUMP
;
2754 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
2756 if (dl_argc(dl
) > 0) {
2757 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2762 pr_out_section_start(dl
, "dev");
2763 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
2764 pr_out_section_end(dl
);
2768 static void cmd_dev_reload_help(void)
2770 pr_err("Usage: devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
2773 static int cmd_dev_reload(struct dl
*dl
)
2775 struct nlmsghdr
*nlh
;
2778 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2779 cmd_dev_reload_help();
2783 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RELOAD
,
2784 NLM_F_REQUEST
| NLM_F_ACK
);
2786 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_NETNS
);
2790 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2793 static void pr_out_versions_single(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2794 const char *name
, int type
)
2796 struct nlattr
*version
;
2798 mnl_attr_for_each(version
, nlh
, sizeof(struct genlmsghdr
)) {
2799 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2800 const char *ver_value
;
2801 const char *ver_name
;
2804 if (mnl_attr_get_type(version
) != type
)
2807 err
= mnl_attr_parse_nested(version
, attr_cb
, tb
);
2808 if (err
!= MNL_CB_OK
)
2811 if (!tb
[DEVLINK_ATTR_INFO_VERSION_NAME
] ||
2812 !tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
])
2816 pr_out_object_start(dl
, name
);
2820 ver_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_NAME
]);
2821 ver_value
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
]);
2823 check_indent_newline(dl
);
2824 print_string_name_value(ver_name
, ver_value
);
2825 if (!dl
->json_output
)
2830 pr_out_object_end(dl
);
2833 static void pr_out_info(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2834 struct nlattr
**tb
, bool has_versions
)
2836 __pr_out_handle_start(dl
, tb
, true, false);
2838 __pr_out_indent_inc();
2839 if (tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
]) {
2840 struct nlattr
*nla_drv
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
];
2842 if (!dl
->json_output
)
2844 check_indent_newline(dl
);
2845 print_string(PRINT_ANY
, "driver", "driver %s",
2846 mnl_attr_get_str(nla_drv
));
2849 if (tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
]) {
2850 struct nlattr
*nla_sn
= tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
];
2852 if (!dl
->json_output
)
2854 check_indent_newline(dl
);
2855 print_string(PRINT_ANY
, "serial_number", "serial_number %s",
2856 mnl_attr_get_str(nla_sn
));
2858 __pr_out_indent_dec();
2861 pr_out_object_start(dl
, "versions");
2863 pr_out_versions_single(dl
, nlh
, "fixed",
2864 DEVLINK_ATTR_INFO_VERSION_FIXED
);
2865 pr_out_versions_single(dl
, nlh
, "running",
2866 DEVLINK_ATTR_INFO_VERSION_RUNNING
);
2867 pr_out_versions_single(dl
, nlh
, "stored",
2868 DEVLINK_ATTR_INFO_VERSION_STORED
);
2870 pr_out_object_end(dl
);
2873 pr_out_handle_end(dl
);
2876 static int cmd_versions_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2878 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2879 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2880 bool has_versions
, has_info
;
2881 struct dl
*dl
= data
;
2883 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2885 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2886 return MNL_CB_ERROR
;
2888 has_versions
= tb
[DEVLINK_ATTR_INFO_VERSION_FIXED
] ||
2889 tb
[DEVLINK_ATTR_INFO_VERSION_RUNNING
] ||
2890 tb
[DEVLINK_ATTR_INFO_VERSION_STORED
];
2891 has_info
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
] ||
2892 tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
] ||
2896 pr_out_info(dl
, nlh
, tb
, has_versions
);
2901 static void cmd_dev_info_help(void)
2903 pr_err("Usage: devlink dev info [ DEV ]\n");
2906 static int cmd_dev_info(struct dl
*dl
)
2908 struct nlmsghdr
*nlh
;
2909 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2912 if (dl_argv_match(dl
, "help")) {
2913 cmd_dev_info_help();
2917 if (dl_argc(dl
) == 0)
2918 flags
|= NLM_F_DUMP
;
2920 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_INFO_GET
, flags
);
2922 if (dl_argc(dl
) > 0) {
2923 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2928 pr_out_section_start(dl
, "info");
2929 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_versions_show_cb
, dl
);
2930 pr_out_section_end(dl
);
2934 static void cmd_dev_flash_help(void)
2936 pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
2940 struct cmd_dev_flash_status_ctx
{
2943 char *last_component
;
2944 uint8_t not_first
:1,
2950 static int nullstrcmp(const char *str1
, const char *str2
)
2953 return strcmp(str1
, str2
);
2956 return str1
? 1 : -1;
2959 static int cmd_dev_flash_status_cb(const struct nlmsghdr
*nlh
, void *data
)
2961 struct cmd_dev_flash_status_ctx
*ctx
= data
;
2962 struct dl_opts
*opts
= &ctx
->dl
->opts
;
2963 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2964 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2965 const char *component
= NULL
;
2966 uint64_t done
= 0, total
= 0;
2967 const char *msg
= NULL
;
2968 const char *bus_name
;
2969 const char *dev_name
;
2971 if (genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_STATUS
&&
2972 genl
->cmd
!= DEVLINK_CMD_FLASH_UPDATE_END
)
2975 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2976 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2977 return MNL_CB_ERROR
;
2978 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
2979 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
2980 if (strcmp(bus_name
, opts
->bus_name
) ||
2981 strcmp(dev_name
, opts
->dev_name
))
2982 return MNL_CB_ERROR
;
2984 if (genl
->cmd
== DEVLINK_CMD_FLASH_UPDATE_END
&& ctx
->not_first
) {
2986 free(ctx
->last_msg
);
2987 free(ctx
->last_component
);
2988 ctx
->received_end
= 1;
2992 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
])
2993 msg
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]);
2994 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
])
2995 component
= mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]);
2996 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
2997 done
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]);
2998 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
2999 total
= mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]);
3001 if (!nullstrcmp(msg
, ctx
->last_msg
) &&
3002 !nullstrcmp(component
, ctx
->last_component
) &&
3003 ctx
->last_pc
&& ctx
->not_first
) {
3004 pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3009 pr_out("[%s] ", component
);
3010 free(ctx
->last_component
);
3011 ctx
->last_component
= strdup(component
);
3015 free(ctx
->last_msg
);
3016 ctx
->last_msg
= strdup(msg
);
3020 pr_out_tty(" %3lu%%", (done
* 100) / total
);
3031 static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx
*ctx
,
3032 struct mnlg_socket
*nlg_ntf
,
3035 int nlfd
= mnlg_socket_get_fd(nlg_ntf
);
3042 for (i
= 0; i
< 3; i
++)
3044 FD_SET(pipe_r
, &fds
[0]);
3046 FD_SET(nlfd
, &fds
[0]);
3050 while (select(fdmax
, &fds
[0], &fds
[1], &fds
[2], NULL
) < 0) {
3053 pr_err("select() failed\n");
3056 if (FD_ISSET(nlfd
, &fds
[0])) {
3057 err
= _mnlg_socket_recv_run(nlg_ntf
,
3058 cmd_dev_flash_status_cb
, ctx
);
3062 if (FD_ISSET(pipe_r
, &fds
[0])) {
3063 err
= read(pipe_r
, &err2
, sizeof(err2
));
3065 pr_err("Failed to read pipe\n");
3070 ctx
->flash_done
= 1;
3076 static int cmd_dev_flash(struct dl
*dl
)
3078 struct cmd_dev_flash_status_ctx ctx
= {.dl
= dl
,};
3079 struct mnlg_socket
*nlg_ntf
;
3080 struct nlmsghdr
*nlh
;
3086 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3087 cmd_dev_flash_help();
3091 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_FLASH_UPDATE
,
3092 NLM_F_REQUEST
| NLM_F_ACK
);
3094 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_FLASH_FILE_NAME
,
3095 DL_OPT_FLASH_COMPONENT
);
3099 nlg_ntf
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
3103 err
= _mnlg_socket_group_add(nlg_ntf
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
3107 err
= pipe(pipe_fds
);
3110 pipe_r
= pipe_fds
[0];
3111 pipe_w
= pipe_fds
[1];
3119 /* In child, just execute the flash and pass returned
3120 * value through pipe once it is done.
3125 err
= _mnlg_socket_send(dl
->nlg
, nlh
);
3126 cc
= write(pipe_w
, &err
, sizeof(err
));
3128 exit(cc
!= sizeof(err
));
3133 err
= cmd_dev_flash_fds_process(&ctx
, nlg_ntf
, pipe_r
);
3136 } while (!ctx
.flash_done
|| (ctx
.not_first
&& !ctx
.received_end
));
3138 err
= _mnlg_socket_recv_run(dl
->nlg
, NULL
, NULL
);
3141 mnlg_socket_close(nlg_ntf
);
3145 static int cmd_dev(struct dl
*dl
)
3147 if (dl_argv_match(dl
, "help")) {
3150 } else if (dl_argv_match(dl
, "show") ||
3151 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3153 return cmd_dev_show(dl
);
3154 } else if (dl_argv_match(dl
, "eswitch")) {
3156 return cmd_dev_eswitch(dl
);
3157 } else if (dl_argv_match(dl
, "reload")) {
3159 return cmd_dev_reload(dl
);
3160 } else if (dl_argv_match(dl
, "param")) {
3162 return cmd_dev_param(dl
);
3163 } else if (dl_argv_match(dl
, "info")) {
3165 return cmd_dev_info(dl
);
3166 } else if (dl_argv_match(dl
, "flash")) {
3168 return cmd_dev_flash(dl
);
3170 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3174 static void cmd_port_help(void)
3176 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3177 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3178 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3179 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3182 static const char *port_type_name(uint32_t type
)
3185 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
3186 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
3187 case DEVLINK_PORT_TYPE_ETH
: return "eth";
3188 case DEVLINK_PORT_TYPE_IB
: return "ib";
3189 default: return "<unknown type>";
3193 static const char *port_flavour_name(uint16_t flavour
)
3196 case DEVLINK_PORT_FLAVOUR_PHYSICAL
:
3198 case DEVLINK_PORT_FLAVOUR_CPU
:
3200 case DEVLINK_PORT_FLAVOUR_DSA
:
3202 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3204 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3206 case DEVLINK_PORT_FLAVOUR_VIRTUAL
:
3209 return "<unknown flavour>";
3213 static void pr_out_port_pfvf_num(struct dl
*dl
, struct nlattr
**tb
)
3217 if (tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]) {
3218 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_PF_NUMBER
]);
3219 print_uint(PRINT_ANY
, "pfnum", " pfnum %u", fn_num
);
3221 if (tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]) {
3222 fn_num
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_PCI_VF_NUMBER
]);
3223 print_uint(PRINT_ANY
, "vfnum", " vfnum %u", fn_num
);
3227 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
3229 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
3230 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
3232 pr_out_port_handle_start(dl
, tb
, false);
3233 check_indent_newline(dl
);
3235 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
3237 print_string(PRINT_ANY
, "type", "type %s",
3238 port_type_name(port_type
));
3240 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
3242 if (port_type
!= des_port_type
)
3243 print_string(PRINT_ANY
, "des_type", " des_type %s",
3244 port_type_name(des_port_type
));
3247 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]) {
3248 print_string(PRINT_ANY
, "netdev", " netdev %s",
3249 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
3251 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]) {
3252 print_string(PRINT_ANY
, "ibdev", " ibdev %s",
3253 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
3255 if (tb
[DEVLINK_ATTR_PORT_FLAVOUR
]) {
3256 uint16_t port_flavour
=
3257 mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_FLAVOUR
]);
3259 print_string(PRINT_ANY
, "flavour", " flavour %s",
3260 port_flavour_name(port_flavour
));
3262 switch (port_flavour
) {
3263 case DEVLINK_PORT_FLAVOUR_PCI_PF
:
3264 case DEVLINK_PORT_FLAVOUR_PCI_VF
:
3265 pr_out_port_pfvf_num(dl
, tb
);
3271 if (tb
[DEVLINK_ATTR_PORT_NUMBER
]) {
3272 uint32_t port_number
;
3274 port_number
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_NUMBER
]);
3275 print_uint(PRINT_ANY
, "port", " port %u", port_number
);
3277 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
3278 print_uint(PRINT_ANY
, "split_group", " split_group %u",
3279 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
3280 pr_out_port_handle_end(dl
);
3283 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3285 struct dl
*dl
= data
;
3286 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3287 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3289 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3290 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3291 !tb
[DEVLINK_ATTR_PORT_INDEX
])
3292 return MNL_CB_ERROR
;
3293 pr_out_port(dl
, tb
);
3297 static int cmd_port_show(struct dl
*dl
)
3299 struct nlmsghdr
*nlh
;
3300 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3303 if (dl_argc(dl
) == 0)
3304 flags
|= NLM_F_DUMP
;
3306 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
3308 if (dl_argc(dl
) > 0) {
3309 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3314 pr_out_section_start(dl
, "port");
3315 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
3316 pr_out_section_end(dl
);
3320 static int cmd_port_set(struct dl
*dl
)
3322 struct nlmsghdr
*nlh
;
3325 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
3326 NLM_F_REQUEST
| NLM_F_ACK
);
3328 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
3332 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3335 static int cmd_port_split(struct dl
*dl
)
3337 struct nlmsghdr
*nlh
;
3340 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
3341 NLM_F_REQUEST
| NLM_F_ACK
);
3343 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
3347 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3350 static int cmd_port_unsplit(struct dl
*dl
)
3352 struct nlmsghdr
*nlh
;
3355 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
3356 NLM_F_REQUEST
| NLM_F_ACK
);
3358 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
3362 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3365 static int cmd_port(struct dl
*dl
)
3367 if (dl_argv_match(dl
, "help")) {
3370 } else if (dl_argv_match(dl
, "show") ||
3371 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3373 return cmd_port_show(dl
);
3374 } else if (dl_argv_match(dl
, "set")) {
3376 return cmd_port_set(dl
);
3377 } else if (dl_argv_match(dl
, "split")) {
3379 return cmd_port_split(dl
);
3380 } else if (dl_argv_match(dl
, "unsplit")) {
3382 return cmd_port_unsplit(dl
);
3384 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3388 static void cmd_sb_help(void)
3390 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
3391 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
3392 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
3393 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
3394 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3395 pr_err(" pool POOL_INDEX ]\n");
3396 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3397 pr_err(" pool POOL_INDEX th THRESHOLD\n");
3398 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3399 pr_err(" type { ingress | egress } ]\n");
3400 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3401 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
3402 pr_err(" th THRESHOLD\n");
3403 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
3404 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
3405 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
3408 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
3410 pr_out_handle_start_arr(dl
, tb
);
3411 check_indent_newline(dl
);
3412 print_uint(PRINT_ANY
, "sb", "sb %u",
3413 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3414 print_uint(PRINT_ANY
, "size", " size %u",
3415 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
3416 print_uint(PRINT_ANY
, "ing_pools", " ing_pools %u",
3417 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
3418 print_uint(PRINT_ANY
, "eg_pools", " eg_pools %u",
3419 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
3420 print_uint(PRINT_ANY
, "ing_tcs", " ing_tcs %u",
3421 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
3422 print_uint(PRINT_ANY
, "eg_tcs", " eg_tcs %u",
3423 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
3424 pr_out_handle_end(dl
);
3427 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3429 struct dl
*dl
= data
;
3430 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3431 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3433 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3434 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3435 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
3436 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
3437 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
3438 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
3439 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
3440 return MNL_CB_ERROR
;
3445 static int cmd_sb_show(struct dl
*dl
)
3447 struct nlmsghdr
*nlh
;
3448 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3451 if (dl_argc(dl
) == 0)
3452 flags
|= NLM_F_DUMP
;
3454 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
3456 if (dl_argc(dl
) > 0) {
3457 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3462 pr_out_section_start(dl
, "sb");
3463 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
3464 pr_out_section_end(dl
);
3468 static const char *pool_type_name(uint8_t type
)
3471 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
3472 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
3473 default: return "<unknown type>";
3477 static const char *threshold_type_name(uint8_t type
)
3480 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
3481 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
3482 default: return "<unknown type>";
3486 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
3488 pr_out_handle_start_arr(dl
, tb
);
3489 check_indent_newline(dl
);
3490 print_uint(PRINT_ANY
, "sb", "sb %u",
3491 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3492 print_uint(PRINT_ANY
, "pool", " pool %u",
3493 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3494 print_string(PRINT_ANY
, "type", " type %s",
3495 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3496 print_uint(PRINT_ANY
, "size", " size %u",
3497 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
3498 print_string(PRINT_ANY
, "thtype", " thtype %s",
3499 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
3500 if (tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
])
3501 print_uint(PRINT_ANY
, "cell_size", " cell size %u",
3502 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
]));
3503 pr_out_handle_end(dl
);
3506 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3508 struct dl
*dl
= data
;
3509 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3510 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3512 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3513 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3514 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3515 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
3516 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
3517 return MNL_CB_ERROR
;
3518 pr_out_sb_pool(dl
, tb
);
3522 static int cmd_sb_pool_show(struct dl
*dl
)
3524 struct nlmsghdr
*nlh
;
3525 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3528 if (dl_argc(dl
) == 0)
3529 flags
|= NLM_F_DUMP
;
3531 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
3533 if (dl_argc(dl
) > 0) {
3534 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
3540 pr_out_section_start(dl
, "pool");
3541 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
3542 pr_out_section_end(dl
);
3546 static int cmd_sb_pool_set(struct dl
*dl
)
3548 struct nlmsghdr
*nlh
;
3551 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
3552 NLM_F_REQUEST
| NLM_F_ACK
);
3554 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
3555 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
3559 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3562 static int cmd_sb_pool(struct dl
*dl
)
3564 if (dl_argv_match(dl
, "help")) {
3567 } else if (dl_argv_match(dl
, "show") ||
3568 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3570 return cmd_sb_pool_show(dl
);
3571 } else if (dl_argv_match(dl
, "set")) {
3573 return cmd_sb_pool_set(dl
);
3575 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3579 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
3581 pr_out_port_handle_start_arr(dl
, tb
, true);
3582 check_indent_newline(dl
);
3583 print_uint(PRINT_ANY
, "sb", "sb %u",
3584 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3585 print_uint(PRINT_ANY
, "pool", " pool %u",
3586 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3587 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3588 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3589 pr_out_port_handle_end(dl
);
3592 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3594 struct dl
*dl
= data
;
3595 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3596 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3598 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3599 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3600 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3601 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3602 return MNL_CB_ERROR
;
3603 pr_out_sb_port_pool(dl
, tb
);
3607 static int cmd_sb_port_pool_show(struct dl
*dl
)
3609 struct nlmsghdr
*nlh
;
3610 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3613 if (dl_argc(dl
) == 0)
3614 flags
|= NLM_F_DUMP
;
3616 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3618 if (dl_argc(dl
) > 0) {
3619 err
= dl_argv_parse_put(nlh
, dl
,
3620 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
3626 pr_out_section_start(dl
, "port_pool");
3627 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
3628 pr_out_section_end(dl
);
3632 static int cmd_sb_port_pool_set(struct dl
*dl
)
3634 struct nlmsghdr
*nlh
;
3637 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
3638 NLM_F_REQUEST
| NLM_F_ACK
);
3640 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
3641 DL_OPT_SB_TH
, DL_OPT_SB
);
3645 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3648 static int cmd_sb_port_pool(struct dl
*dl
)
3650 if (dl_argv_match(dl
, "help")) {
3653 } else if (dl_argv_match(dl
, "show") ||
3654 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3656 return cmd_sb_port_pool_show(dl
);
3657 } else if (dl_argv_match(dl
, "set")) {
3659 return cmd_sb_port_pool_set(dl
);
3661 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3665 static int cmd_sb_port(struct dl
*dl
)
3667 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3670 } else if (dl_argv_match(dl
, "pool")) {
3672 return cmd_sb_port_pool(dl
);
3674 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3678 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
3680 pr_out_port_handle_start_arr(dl
, tb
, true);
3681 check_indent_newline(dl
);
3682 print_uint(PRINT_ANY
, "sb", "sb %u",
3683 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3684 print_uint(PRINT_ANY
, "tc", " tc %u",
3685 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
3686 print_string(PRINT_ANY
, "type", " type %s",
3687 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3688 print_uint(PRINT_ANY
, "pool", " pool %u",
3689 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3690 print_uint(PRINT_ANY
, "threshold", " threshold %u",
3691 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3692 pr_out_port_handle_end(dl
);
3695 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3697 struct dl
*dl
= data
;
3698 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3699 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3701 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3702 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3703 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3704 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3705 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3706 return MNL_CB_ERROR
;
3707 pr_out_sb_tc_bind(dl
, tb
);
3711 static int cmd_sb_tc_bind_show(struct dl
*dl
)
3713 struct nlmsghdr
*nlh
;
3714 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3717 if (dl_argc(dl
) == 0)
3718 flags
|= NLM_F_DUMP
;
3720 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3722 if (dl_argc(dl
) > 0) {
3723 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3724 DL_OPT_SB_TYPE
, DL_OPT_SB
);
3729 pr_out_section_start(dl
, "tc_bind");
3730 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
3731 pr_out_section_end(dl
);
3735 static int cmd_sb_tc_bind_set(struct dl
*dl
)
3737 struct nlmsghdr
*nlh
;
3740 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
3741 NLM_F_REQUEST
| NLM_F_ACK
);
3743 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3744 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
3749 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3752 static int cmd_sb_tc_bind(struct dl
*dl
)
3754 if (dl_argv_match(dl
, "help")) {
3757 } else if (dl_argv_match(dl
, "show") ||
3758 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3760 return cmd_sb_tc_bind_show(dl
);
3761 } else if (dl_argv_match(dl
, "set")) {
3763 return cmd_sb_tc_bind_set(dl
);
3765 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3769 static int cmd_sb_tc(struct dl
*dl
)
3771 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3774 } else if (dl_argv_match(dl
, "bind")) {
3776 return cmd_sb_tc_bind(dl
);
3778 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3783 struct list_head list
;
3787 uint32_t bound_pool_index
;
3791 struct list_head list
;
3794 uint32_t port_index
;
3796 struct list_head pool_list
;
3797 struct list_head ing_tc_list
;
3798 struct list_head eg_tc_list
;
3804 struct list_head port_list
;
3807 static struct occ_item
*occ_item_alloc(void)
3809 return calloc(1, sizeof(struct occ_item
));
3812 static void occ_item_free(struct occ_item
*occ_item
)
3817 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
3819 struct occ_port
*occ_port
;
3821 occ_port
= calloc(1, sizeof(*occ_port
));
3824 occ_port
->port_index
= port_index
;
3825 INIT_LIST_HEAD(&occ_port
->pool_list
);
3826 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
3827 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
3831 static void occ_port_free(struct occ_port
*occ_port
)
3833 struct occ_item
*occ_item
, *tmp
;
3835 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
3836 occ_item_free(occ_item
);
3837 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
3838 occ_item_free(occ_item
);
3839 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
3840 occ_item_free(occ_item
);
3843 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
3845 struct occ_show
*occ_show
;
3847 occ_show
= calloc(1, sizeof(*occ_show
));
3851 INIT_LIST_HEAD(&occ_show
->port_list
);
3855 static void occ_show_free(struct occ_show
*occ_show
)
3857 struct occ_port
*occ_port
, *tmp
;
3859 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
3860 occ_port_free(occ_port
);
3863 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
3866 struct occ_port
*occ_port
;
3867 uint32_t port_index
;
3869 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
3871 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
3872 if (occ_port
->port_index
== port_index
)
3875 occ_port
= occ_port_alloc(port_index
);
3878 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
3882 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
3885 struct occ_item
*occ_item
;
3888 pr_out_sp(7, " %s:", label
);
3889 list_for_each_entry(occ_item
, list
, list
) {
3890 if ((i
- 1) % 4 == 0 && i
!= 1)
3893 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
3894 occ_item
->bound_pool_index
);
3896 pr_out_sp(7, "%2u:", occ_item
->index
);
3897 pr_out_sp(21, "%10u/%u", occ_item
->cur
, occ_item
->max
);
3901 if ((i
- 1) % 4 != 0)
3905 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
3906 struct list_head
*list
,
3909 struct occ_item
*occ_item
;
3912 open_json_object(label
);
3913 list_for_each_entry(occ_item
, list
, list
) {
3914 sprintf(buf
, "%u", occ_item
->index
);
3915 open_json_object(buf
);
3917 print_uint(PRINT_JSON
, "bound_pool", NULL
,
3918 occ_item
->bound_pool_index
);
3919 print_uint(PRINT_JSON
, "current", NULL
, occ_item
->cur
);
3920 print_uint(PRINT_JSON
, "max", NULL
, occ_item
->max
);
3921 close_json_object();
3923 close_json_object();
3926 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
3928 if (dl
->json_output
) {
3929 pr_out_json_occ_show_item_list(dl
, "pool",
3930 &occ_port
->pool_list
, false);
3931 pr_out_json_occ_show_item_list(dl
, "itc",
3932 &occ_port
->ing_tc_list
, true);
3933 pr_out_json_occ_show_item_list(dl
, "etc",
3934 &occ_port
->eg_tc_list
, true);
3937 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
3938 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
3939 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
3943 static void pr_out_occ_show(struct occ_show
*occ_show
)
3945 struct dl
*dl
= occ_show
->dl
;
3946 struct dl_opts
*opts
= &dl
->opts
;
3947 struct occ_port
*occ_port
;
3949 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
3950 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
3951 occ_port
->port_index
, true, false);
3952 pr_out_occ_show_port(dl
, occ_port
);
3953 pr_out_port_handle_end(dl
);
3957 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
3960 struct occ_port
*occ_port
;
3961 struct occ_item
*occ_item
;
3963 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
3966 occ_port
= occ_port_get(occ_show
, tb
);
3968 occ_show
->err
= -ENOMEM
;
3972 occ_item
= occ_item_alloc();
3974 occ_show
->err
= -ENOMEM
;
3977 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
3978 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
3979 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
3980 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
3983 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
3985 struct occ_show
*occ_show
= data
;
3986 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3987 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3989 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3990 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3991 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3992 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3993 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
3994 return MNL_CB_ERROR
;
3995 cmd_sb_occ_port_pool_process(occ_show
, tb
);
3999 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
4002 struct occ_port
*occ_port
;
4003 struct occ_item
*occ_item
;
4006 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
4009 occ_port
= occ_port_get(occ_show
, tb
);
4011 occ_show
->err
= -ENOMEM
;
4015 occ_item
= occ_item_alloc();
4017 occ_show
->err
= -ENOMEM
;
4020 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
4021 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
4022 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
4023 occ_item
->bound_pool_index
=
4024 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
4025 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
4026 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
4027 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
4028 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
4029 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
4031 occ_item_free(occ_item
);
4034 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
4036 struct occ_show
*occ_show
= data
;
4037 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4038 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4040 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4041 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4042 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
4043 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
4044 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
4045 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
4046 return MNL_CB_ERROR
;
4047 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
4051 static int cmd_sb_occ_show(struct dl
*dl
)
4053 struct nlmsghdr
*nlh
;
4054 struct occ_show
*occ_show
;
4055 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
4058 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
4062 occ_show
= occ_show_alloc(dl
);
4066 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
4068 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4069 cmd_sb_occ_port_pool_process_cb
, occ_show
);
4073 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
4075 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
4076 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
4080 pr_out_section_start(dl
, "occupancy");
4081 pr_out_occ_show(occ_show
);
4082 pr_out_section_end(dl
);
4085 occ_show_free(occ_show
);
4089 static int cmd_sb_occ_snapshot(struct dl
*dl
)
4091 struct nlmsghdr
*nlh
;
4094 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
4095 NLM_F_REQUEST
| NLM_F_ACK
);
4097 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4101 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4104 static int cmd_sb_occ_clearmax(struct dl
*dl
)
4106 struct nlmsghdr
*nlh
;
4109 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
4110 NLM_F_REQUEST
| NLM_F_ACK
);
4112 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
4116 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4119 static int cmd_sb_occ(struct dl
*dl
)
4121 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4124 } else if (dl_argv_match(dl
, "show") ||
4125 dl_argv_match(dl
, "list")) {
4127 return cmd_sb_occ_show(dl
);
4128 } else if (dl_argv_match(dl
, "snapshot")) {
4130 return cmd_sb_occ_snapshot(dl
);
4131 } else if (dl_argv_match(dl
, "clearmax")) {
4133 return cmd_sb_occ_clearmax(dl
);
4135 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4139 static int cmd_sb(struct dl
*dl
)
4141 if (dl_argv_match(dl
, "help")) {
4144 } else if (dl_argv_match(dl
, "show") ||
4145 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
4147 return cmd_sb_show(dl
);
4148 } else if (dl_argv_match(dl
, "pool")) {
4150 return cmd_sb_pool(dl
);
4151 } else if (dl_argv_match(dl
, "port")) {
4153 return cmd_sb_port(dl
);
4154 } else if (dl_argv_match(dl
, "tc")) {
4156 return cmd_sb_tc(dl
);
4157 } else if (dl_argv_match(dl
, "occupancy")) {
4159 return cmd_sb_occ(dl
);
4161 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4165 static const char *cmd_name(uint8_t cmd
)
4168 case DEVLINK_CMD_UNSPEC
: return "unspec";
4169 case DEVLINK_CMD_GET
: return "get";
4170 case DEVLINK_CMD_SET
: return "set";
4171 case DEVLINK_CMD_NEW
: return "new";
4172 case DEVLINK_CMD_DEL
: return "del";
4173 case DEVLINK_CMD_PORT_GET
: return "get";
4174 case DEVLINK_CMD_PORT_SET
: return "set";
4175 case DEVLINK_CMD_PORT_NEW
: return "new";
4176 case DEVLINK_CMD_PORT_DEL
: return "del";
4177 case DEVLINK_CMD_PARAM_GET
: return "get";
4178 case DEVLINK_CMD_PARAM_SET
: return "set";
4179 case DEVLINK_CMD_PARAM_NEW
: return "new";
4180 case DEVLINK_CMD_PARAM_DEL
: return "del";
4181 case DEVLINK_CMD_REGION_GET
: return "get";
4182 case DEVLINK_CMD_REGION_SET
: return "set";
4183 case DEVLINK_CMD_REGION_NEW
: return "new";
4184 case DEVLINK_CMD_REGION_DEL
: return "del";
4185 case DEVLINK_CMD_FLASH_UPDATE
: return "begin";
4186 case DEVLINK_CMD_FLASH_UPDATE_END
: return "end";
4187 case DEVLINK_CMD_FLASH_UPDATE_STATUS
: return "status";
4188 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
: return "status";
4189 case DEVLINK_CMD_TRAP_GET
: return "get";
4190 case DEVLINK_CMD_TRAP_SET
: return "set";
4191 case DEVLINK_CMD_TRAP_NEW
: return "new";
4192 case DEVLINK_CMD_TRAP_DEL
: return "del";
4193 case DEVLINK_CMD_TRAP_GROUP_GET
: return "get";
4194 case DEVLINK_CMD_TRAP_GROUP_SET
: return "set";
4195 case DEVLINK_CMD_TRAP_GROUP_NEW
: return "new";
4196 case DEVLINK_CMD_TRAP_GROUP_DEL
: return "del";
4197 case DEVLINK_CMD_TRAP_POLICER_GET
: return "get";
4198 case DEVLINK_CMD_TRAP_POLICER_SET
: return "set";
4199 case DEVLINK_CMD_TRAP_POLICER_NEW
: return "new";
4200 case DEVLINK_CMD_TRAP_POLICER_DEL
: return "del";
4201 default: return "<unknown cmd>";
4205 static const char *cmd_obj(uint8_t cmd
)
4208 case DEVLINK_CMD_UNSPEC
: return "unspec";
4209 case DEVLINK_CMD_GET
:
4210 case DEVLINK_CMD_SET
:
4211 case DEVLINK_CMD_NEW
:
4212 case DEVLINK_CMD_DEL
:
4214 case DEVLINK_CMD_PORT_GET
:
4215 case DEVLINK_CMD_PORT_SET
:
4216 case DEVLINK_CMD_PORT_NEW
:
4217 case DEVLINK_CMD_PORT_DEL
:
4219 case DEVLINK_CMD_PARAM_GET
:
4220 case DEVLINK_CMD_PARAM_SET
:
4221 case DEVLINK_CMD_PARAM_NEW
:
4222 case DEVLINK_CMD_PARAM_DEL
:
4224 case DEVLINK_CMD_REGION_GET
:
4225 case DEVLINK_CMD_REGION_SET
:
4226 case DEVLINK_CMD_REGION_NEW
:
4227 case DEVLINK_CMD_REGION_DEL
:
4229 case DEVLINK_CMD_FLASH_UPDATE
:
4230 case DEVLINK_CMD_FLASH_UPDATE_END
:
4231 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4233 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4235 case DEVLINK_CMD_TRAP_GET
:
4236 case DEVLINK_CMD_TRAP_SET
:
4237 case DEVLINK_CMD_TRAP_NEW
:
4238 case DEVLINK_CMD_TRAP_DEL
:
4240 case DEVLINK_CMD_TRAP_GROUP_GET
:
4241 case DEVLINK_CMD_TRAP_GROUP_SET
:
4242 case DEVLINK_CMD_TRAP_GROUP_NEW
:
4243 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4244 return "trap-group";
4245 case DEVLINK_CMD_TRAP_POLICER_GET
:
4246 case DEVLINK_CMD_TRAP_POLICER_SET
:
4247 case DEVLINK_CMD_TRAP_POLICER_NEW
:
4248 case DEVLINK_CMD_TRAP_POLICER_DEL
:
4249 return "trap-policer";
4250 default: return "<unknown obj>";
4254 static void pr_out_mon_header(uint8_t cmd
)
4256 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
4259 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
4261 const char *obj
= cmd_obj(cmd
);
4262 unsigned int index
= 0;
4263 const char *cur_obj
;
4267 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4268 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
4274 static void pr_out_flash_update(struct dl
*dl
, struct nlattr
**tb
)
4276 __pr_out_handle_start(dl
, tb
, true, false);
4278 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]) {
4279 check_indent_newline(dl
);
4280 print_string(PRINT_ANY
, "msg", "msg %s",
4281 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG
]));
4283 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]) {
4284 check_indent_newline(dl
);
4285 print_string(PRINT_ANY
, "component", "component %s",
4286 mnl_attr_get_str(tb
[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
]));
4289 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
])
4290 pr_out_u64(dl
, "done",
4291 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE
]));
4293 if (tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
])
4294 pr_out_u64(dl
, "total",
4295 mnl_attr_get_u64(tb
[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL
]));
4297 pr_out_handle_end(dl
);
4300 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
);
4301 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
);
4302 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4303 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4304 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
);
4306 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
4308 struct dl
*dl
= data
;
4309 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4310 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4311 uint8_t cmd
= genl
->cmd
;
4313 if (!cmd_filter_check(dl
, cmd
))
4317 case DEVLINK_CMD_GET
: /* fall through */
4318 case DEVLINK_CMD_SET
: /* fall through */
4319 case DEVLINK_CMD_NEW
: /* fall through */
4320 case DEVLINK_CMD_DEL
:
4321 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4322 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4323 return MNL_CB_ERROR
;
4324 pr_out_mon_header(genl
->cmd
);
4325 pr_out_handle(dl
, tb
);
4327 case DEVLINK_CMD_PORT_GET
: /* fall through */
4328 case DEVLINK_CMD_PORT_SET
: /* fall through */
4329 case DEVLINK_CMD_PORT_NEW
: /* fall through */
4330 case DEVLINK_CMD_PORT_DEL
:
4331 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4332 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4333 !tb
[DEVLINK_ATTR_PORT_INDEX
])
4334 return MNL_CB_ERROR
;
4335 pr_out_mon_header(genl
->cmd
);
4336 pr_out_port(dl
, tb
);
4338 case DEVLINK_CMD_PARAM_GET
: /* fall through */
4339 case DEVLINK_CMD_PARAM_SET
: /* fall through */
4340 case DEVLINK_CMD_PARAM_NEW
: /* fall through */
4341 case DEVLINK_CMD_PARAM_DEL
:
4342 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4343 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4344 !tb
[DEVLINK_ATTR_PARAM
])
4345 return MNL_CB_ERROR
;
4346 pr_out_mon_header(genl
->cmd
);
4347 pr_out_param(dl
, tb
, false);
4349 case DEVLINK_CMD_REGION_GET
: /* fall through */
4350 case DEVLINK_CMD_REGION_SET
: /* fall through */
4351 case DEVLINK_CMD_REGION_NEW
: /* fall through */
4352 case DEVLINK_CMD_REGION_DEL
:
4353 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4354 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4355 !tb
[DEVLINK_ATTR_REGION_NAME
])
4356 return MNL_CB_ERROR
;
4357 pr_out_mon_header(genl
->cmd
);
4358 pr_out_region(dl
, tb
);
4360 case DEVLINK_CMD_FLASH_UPDATE
: /* fall through */
4361 case DEVLINK_CMD_FLASH_UPDATE_END
: /* fall through */
4362 case DEVLINK_CMD_FLASH_UPDATE_STATUS
:
4363 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4364 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
4365 return MNL_CB_ERROR
;
4366 pr_out_mon_header(genl
->cmd
);
4367 pr_out_flash_update(dl
, tb
);
4369 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER
:
4370 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4371 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4372 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
4373 return MNL_CB_ERROR
;
4374 pr_out_mon_header(genl
->cmd
);
4375 pr_out_health(dl
, tb
);
4377 case DEVLINK_CMD_TRAP_GET
: /* fall through */
4378 case DEVLINK_CMD_TRAP_SET
: /* fall through */
4379 case DEVLINK_CMD_TRAP_NEW
: /* fall through */
4380 case DEVLINK_CMD_TRAP_DEL
:
4381 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4382 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4383 !tb
[DEVLINK_ATTR_TRAP_NAME
] ||
4384 !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
4385 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
4386 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4387 !tb
[DEVLINK_ATTR_TRAP_METADATA
] ||
4388 !tb
[DEVLINK_ATTR_STATS
])
4389 return MNL_CB_ERROR
;
4390 pr_out_mon_header(genl
->cmd
);
4391 pr_out_trap(dl
, tb
, false);
4393 case DEVLINK_CMD_TRAP_GROUP_GET
: /* fall through */
4394 case DEVLINK_CMD_TRAP_GROUP_SET
: /* fall through */
4395 case DEVLINK_CMD_TRAP_GROUP_NEW
: /* fall through */
4396 case DEVLINK_CMD_TRAP_GROUP_DEL
:
4397 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4398 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4399 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
4400 !tb
[DEVLINK_ATTR_STATS
])
4401 return MNL_CB_ERROR
;
4402 pr_out_mon_header(genl
->cmd
);
4403 pr_out_trap_group(dl
, tb
, false);
4405 case DEVLINK_CMD_TRAP_POLICER_GET
: /* fall through */
4406 case DEVLINK_CMD_TRAP_POLICER_SET
: /* fall through */
4407 case DEVLINK_CMD_TRAP_POLICER_NEW
: /* fall through */
4408 case DEVLINK_CMD_TRAP_POLICER_DEL
: /* fall through */
4409 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4410 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4411 !tb
[DEVLINK_ATTR_TRAP_POLICER_ID
] ||
4412 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
4413 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
4414 return MNL_CB_ERROR
;
4415 pr_out_mon_header(genl
->cmd
);
4416 pr_out_trap_policer(dl
, tb
, false);
4422 static int cmd_mon_show(struct dl
*dl
)
4425 unsigned int index
= 0;
4426 const char *cur_obj
;
4428 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
4429 if (strcmp(cur_obj
, "all") != 0 &&
4430 strcmp(cur_obj
, "dev") != 0 &&
4431 strcmp(cur_obj
, "port") != 0 &&
4432 strcmp(cur_obj
, "health") != 0 &&
4433 strcmp(cur_obj
, "trap") != 0 &&
4434 strcmp(cur_obj
, "trap-group") != 0 &&
4435 strcmp(cur_obj
, "trap-policer") != 0) {
4436 pr_err("Unknown object \"%s\"\n", cur_obj
);
4440 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
4443 err
= _mnlg_socket_recv_run(dl
->nlg
, cmd_mon_show_cb
, dl
);
4449 static void cmd_mon_help(void)
4451 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
4452 "where OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
4455 static int cmd_mon(struct dl
*dl
)
4457 if (dl_argv_match(dl
, "help")) {
4461 return cmd_mon_show(dl
);
4464 struct dpipe_field
{
4467 unsigned int bitwidth
;
4468 enum devlink_dpipe_field_mapping_type mapping_type
;
4471 struct dpipe_header
{
4472 struct list_head list
;
4475 struct dpipe_field
*fields
;
4476 unsigned int fields_count
;
4479 struct dpipe_table
{
4480 struct list_head list
;
4482 unsigned int resource_id
;
4483 bool resource_valid
;
4486 struct dpipe_tables
{
4487 struct list_head table_list
;
4497 enum devlink_resource_unit unit
;
4502 struct list_head list
;
4503 struct list_head resource_list
;
4504 struct resource
*parent
;
4508 struct list_head resource_list
;
4511 struct resource_ctx
{
4514 struct resources
*resources
;
4515 struct dpipe_tables
*tables
;
4516 bool print_resources
;
4517 bool pending_change
;
4520 static struct resource
*resource_alloc(void)
4522 struct resource
*resource
;
4524 resource
= calloc(1, sizeof(struct resource
));
4527 INIT_LIST_HEAD(&resource
->resource_list
);
4531 static void resource_free(struct resource
*resource
)
4533 struct resource
*child_resource
, *tmp
;
4535 list_for_each_entry_safe(child_resource
, tmp
, &resource
->resource_list
,
4537 free(child_resource
->name
);
4538 resource_free(child_resource
);
4543 static struct resources
*resources_alloc(void)
4545 struct resources
*resources
;
4547 resources
= calloc(1, sizeof(struct resources
));
4550 INIT_LIST_HEAD(&resources
->resource_list
);
4554 static void resources_free(struct resources
*resources
)
4556 struct resource
*resource
, *tmp
;
4558 list_for_each_entry_safe(resource
, tmp
, &resources
->resource_list
, list
)
4559 resource_free(resource
);
4562 static int resource_ctx_init(struct resource_ctx
*ctx
, struct dl
*dl
)
4564 ctx
->resources
= resources_alloc();
4565 if (!ctx
->resources
)
4571 static void resource_ctx_fini(struct resource_ctx
*ctx
)
4573 resources_free(ctx
->resources
);
4579 struct list_head global_headers
;
4580 struct list_head local_headers
;
4581 struct dpipe_tables
*tables
;
4582 struct resources
*resources
;
4587 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
4589 struct dpipe_header
*header
;
4591 header
= calloc(1, sizeof(struct dpipe_header
));
4594 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
4595 if (!header
->fields
)
4596 goto err_fields_alloc
;
4597 header
->fields_count
= fields_count
;
4605 static void dpipe_header_free(struct dpipe_header
*header
)
4607 free(header
->fields
);
4611 static void dpipe_header_clear(struct dpipe_header
*header
)
4613 struct dpipe_field
*field
;
4616 for (i
= 0; i
< header
->fields_count
; i
++) {
4617 field
= &header
->fields
[i
];
4623 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
4624 struct dpipe_header
*header
, bool global
)
4627 list_add(&header
->list
, &ctx
->global_headers
);
4629 list_add(&header
->list
, &ctx
->local_headers
);
4632 static void dpipe_header_del(struct dpipe_header
*header
)
4634 list_del(&header
->list
);
4637 static struct dpipe_table
*dpipe_table_alloc(void)
4639 return calloc(1, sizeof(struct dpipe_table
));
4642 static void dpipe_table_free(struct dpipe_table
*table
)
4647 static struct dpipe_tables
*dpipe_tables_alloc(void)
4649 struct dpipe_tables
*tables
;
4651 tables
= calloc(1, sizeof(struct dpipe_tables
));
4654 INIT_LIST_HEAD(&tables
->table_list
);
4658 static void dpipe_tables_free(struct dpipe_tables
*tables
)
4660 struct dpipe_table
*table
, *tmp
;
4662 list_for_each_entry_safe(table
, tmp
, &tables
->table_list
, list
)
4663 dpipe_table_free(table
);
4667 static int dpipe_ctx_init(struct dpipe_ctx
*ctx
, struct dl
*dl
)
4669 ctx
->tables
= dpipe_tables_alloc();
4674 INIT_LIST_HEAD(&ctx
->global_headers
);
4675 INIT_LIST_HEAD(&ctx
->local_headers
);
4679 static void dpipe_ctx_fini(struct dpipe_ctx
*ctx
)
4681 struct dpipe_header
*header
, *tmp
;
4683 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
4685 dpipe_header_del(header
);
4686 dpipe_header_clear(header
);
4687 dpipe_header_free(header
);
4689 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
4691 dpipe_header_del(header
);
4692 dpipe_header_clear(header
);
4693 dpipe_header_free(header
);
4695 dpipe_tables_free(ctx
->tables
);
4698 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
4699 uint32_t header_id
, bool global
)
4701 struct list_head
*header_list
;
4702 struct dpipe_header
*header
;
4705 header_list
= &ctx
->global_headers
;
4707 header_list
= &ctx
->local_headers
;
4708 list_for_each_entry(header
, header_list
, list
) {
4709 if (header
->id
!= header_id
)
4711 return header
->name
;
4716 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
4718 uint32_t field_id
, bool global
)
4720 struct list_head
*header_list
;
4721 struct dpipe_header
*header
;
4724 header_list
= &ctx
->global_headers
;
4726 header_list
= &ctx
->local_headers
;
4727 list_for_each_entry(header
, header_list
, list
) {
4728 if (header
->id
!= header_id
)
4730 return header
->fields
[field_id
].name
;
4736 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
4738 switch (mapping_type
) {
4739 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
4741 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
4749 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
4750 uint32_t field_id
, bool global
)
4752 enum devlink_dpipe_field_mapping_type mapping_type
;
4753 struct list_head
*header_list
;
4754 struct dpipe_header
*header
;
4757 header_list
= &ctx
->global_headers
;
4759 header_list
= &ctx
->local_headers
;
4760 list_for_each_entry(header
, header_list
, list
) {
4761 if (header
->id
!= header_id
)
4763 mapping_type
= header
->fields
[field_id
].mapping_type
;
4764 return dpipe_field_mapping_e2s(mapping_type
);
4769 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
4770 struct dpipe_field
*fields
,
4771 unsigned int field_count
)
4773 struct dpipe_field
*field
;
4776 for (i
= 0; i
< field_count
; i
++) {
4778 pr_out_entry_start(ctx
->dl
);
4779 check_indent_newline(ctx
->dl
);
4780 print_string(PRINT_ANY
, "name", "name %s", field
->name
);
4781 if (ctx
->dl
->verbose
)
4782 print_uint(PRINT_ANY
, "id", " id %u", field
->id
);
4783 print_uint(PRINT_ANY
, "bitwidth", " bitwidth %u", field
->bitwidth
);
4784 if (field
->mapping_type
) {
4785 print_string(PRINT_ANY
, "mapping_type", " mapping_type %s",
4786 dpipe_field_mapping_e2s(field
->mapping_type
));
4788 pr_out_entry_end(ctx
->dl
);
4793 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
4794 struct dpipe_header
*header
, bool global
)
4796 pr_out_handle_start_arr(ctx
->dl
, tb
);
4797 check_indent_newline(ctx
->dl
);
4798 print_string(PRINT_ANY
, "name", "name %s", header
->name
);
4799 if (ctx
->dl
->verbose
) {
4800 print_uint(PRINT_ANY
, "id", " id %u", header
->id
);
4801 print_bool(PRINT_ANY
, "global", " global %s", global
);
4803 pr_out_array_start(ctx
->dl
, "field");
4804 pr_out_dpipe_fields(ctx
, header
->fields
,
4805 header
->fields_count
);
4806 pr_out_array_end(ctx
->dl
);
4807 pr_out_handle_end(ctx
->dl
);
4810 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
4813 struct dpipe_header
*header
;
4815 list_for_each_entry(header
, &ctx
->local_headers
, list
)
4816 pr_out_dpipe_header(ctx
, tb
, header
, false);
4818 list_for_each_entry(header
, &ctx
->global_headers
, list
)
4819 pr_out_dpipe_header(ctx
, tb
, header
, true);
4822 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
4824 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
4828 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
4829 if (err
!= MNL_CB_OK
)
4831 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
4832 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
4833 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
4834 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
4837 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
4838 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4839 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
4840 field
->name
= strdup(name
);
4843 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
4847 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
4848 struct dpipe_field
*fields
)
4850 struct nlattr
*nla_field
;
4854 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
4855 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
4863 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
4865 struct nlattr
*nla_field
;
4866 unsigned int count
= 0;
4868 mnl_attr_for_each_nested(nla_field
, nla_fields
)
4873 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
4875 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
4876 struct dpipe_header
*header
;
4877 unsigned int fields_count
;
4878 const char *header_name
;
4882 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
4883 if (err
!= MNL_CB_OK
)
4886 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
4887 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4888 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
4891 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
4892 header
= dpipe_header_alloc(fields_count
);
4896 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
4897 header
->name
= strdup(header_name
);
4898 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4899 header
->fields_count
= fields_count
;
4900 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4902 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
4906 dpipe_header_add(ctx
, header
, global
);
4910 dpipe_header_free(header
);
4914 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
4916 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
4917 struct nlattr
*nla_header
;
4920 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
4921 err
= dpipe_header_get(ctx
, nla_header
);
4928 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
4930 struct dpipe_ctx
*ctx
= data
;
4931 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4932 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4935 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4936 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4937 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
4938 return MNL_CB_ERROR
;
4939 err
= dpipe_headers_get(ctx
, tb
);
4942 return MNL_CB_ERROR
;
4945 if (ctx
->print_headers
)
4946 pr_out_dpipe_headers(ctx
, tb
);
4950 static int cmd_dpipe_headers_show(struct dl
*dl
)
4952 struct nlmsghdr
*nlh
;
4953 struct dpipe_ctx ctx
= {};
4954 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
4957 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
4959 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
4963 err
= dpipe_ctx_init(&ctx
, dl
);
4967 ctx
.print_headers
= true;
4969 pr_out_section_start(dl
, "header");
4970 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
4972 pr_err("error get headers %s\n", strerror(ctx
.err
));
4973 pr_out_section_end(dl
);
4975 dpipe_ctx_fini(&ctx
);
4979 static void cmd_dpipe_header_help(void)
4981 pr_err("Usage: devlink dpipe headers show DEV\n");
4984 static int cmd_dpipe_header(struct dl
*dl
)
4986 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4987 cmd_dpipe_header_help();
4989 } else if (dl_argv_match(dl
, "show")) {
4991 return cmd_dpipe_headers_show(dl
);
4993 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4998 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
5000 switch (action_type
) {
5001 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
5002 return "field_modify";
5008 struct dpipe_op_info
{
5014 struct dpipe_action
{
5015 struct dpipe_op_info info
;
5019 static void pr_out_dpipe_action(struct dpipe_action
*action
,
5020 struct dpipe_ctx
*ctx
)
5022 struct dpipe_op_info
*op_info
= &action
->info
;
5023 const char *mapping
;
5025 check_indent_newline(ctx
->dl
);
5026 print_string(PRINT_ANY
, "type", "type %s",
5027 dpipe_action_type_e2s(action
->type
));
5028 print_string(PRINT_ANY
, "header", " header %s",
5029 dpipe_header_id2s(ctx
, op_info
->header_id
,
5030 op_info
->header_global
));
5031 print_string(PRINT_ANY
, "field", " field %s",
5032 dpipe_field_id2s(ctx
, op_info
->header_id
,
5034 op_info
->header_global
));
5035 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5037 op_info
->header_global
);
5039 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5042 static int dpipe_action_parse(struct dpipe_action
*action
, struct nlattr
*nl
)
5044 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
5047 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
5048 if (err
!= MNL_CB_OK
)
5051 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
5052 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5053 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5054 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5058 action
->type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
5059 action
->info
.header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5060 action
->info
.field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5061 action
->info
.header_global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5066 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
5067 struct nlattr
*nla_actions
)
5069 struct nlattr
*nla_action
;
5070 struct dpipe_action action
;
5072 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
5073 pr_out_entry_start(ctx
->dl
);
5074 if (dpipe_action_parse(&action
, nla_action
))
5075 goto err_action_parse
;
5076 pr_out_dpipe_action(&action
, ctx
);
5077 pr_out_entry_end(ctx
->dl
);
5082 pr_out_entry_end(ctx
->dl
);
5087 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
5089 switch (match_type
) {
5090 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
5091 return "field_exact";
5097 struct dpipe_match
{
5098 struct dpipe_op_info info
;
5102 static void pr_out_dpipe_match(struct dpipe_match
*match
,
5103 struct dpipe_ctx
*ctx
)
5105 struct dpipe_op_info
*op_info
= &match
->info
;
5106 const char *mapping
;
5108 check_indent_newline(ctx
->dl
);
5109 print_string(PRINT_ANY
, "type", "type %s",
5110 dpipe_match_type_e2s(match
->type
));
5111 print_string(PRINT_ANY
, "header", " header %s",
5112 dpipe_header_id2s(ctx
, op_info
->header_id
,
5113 op_info
->header_global
));
5114 print_string(PRINT_ANY
, "field", " field %s",
5115 dpipe_field_id2s(ctx
, op_info
->header_id
,
5117 op_info
->header_global
));
5118 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
5120 op_info
->header_global
);
5122 print_string(PRINT_ANY
, "mapping", " mapping %s", mapping
);
5125 static int dpipe_match_parse(struct dpipe_match
*match
,
5129 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
5132 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
5133 if (err
!= MNL_CB_OK
)
5136 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
5137 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
5138 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
5139 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
5143 match
->type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
5144 match
->info
.header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
5145 match
->info
.field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
5146 match
->info
.header_global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
5151 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
5152 struct nlattr
*nla_matches
)
5154 struct nlattr
*nla_match
;
5155 struct dpipe_match match
;
5157 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
5158 pr_out_entry_start(ctx
->dl
);
5159 if (dpipe_match_parse(&match
, nla_match
))
5160 goto err_match_parse
;
5161 pr_out_dpipe_match(&match
, ctx
);
5162 pr_out_entry_end(ctx
->dl
);
5167 pr_out_entry_end(ctx
->dl
);
5171 static struct resource
*
5172 resource_find(struct resources
*resources
, struct resource
*resource
,
5173 uint64_t resource_id
)
5175 struct list_head
*list_head
;
5178 list_head
= &resources
->resource_list
;
5180 list_head
= &resource
->resource_list
;
5182 list_for_each_entry(resource
, list_head
, list
) {
5183 struct resource
*child_resource
;
5185 if (resource
->id
== resource_id
)
5188 child_resource
= resource_find(resources
, resource
,
5191 return child_resource
;
5197 resource_path_print(struct dl
*dl
, struct resources
*resources
,
5198 uint64_t resource_id
)
5200 struct resource
*resource
, *parent_resource
;
5201 const char del
[] = "/";
5205 resource
= resource_find(resources
, NULL
, resource_id
);
5209 for (parent_resource
= resource
; parent_resource
;
5210 parent_resource
= parent_resource
->parent
)
5211 path_len
+= strlen(parent_resource
->name
) + 1;
5214 path
= calloc(1, path_len
);
5218 path
+= path_len
- 1;
5219 for (parent_resource
= resource
; parent_resource
;
5220 parent_resource
= parent_resource
->parent
) {
5221 path
-= strlen(parent_resource
->name
);
5222 memcpy(path
, parent_resource
->name
,
5223 strlen(parent_resource
->name
));
5224 path
-= strlen(del
);
5225 memcpy(path
, del
, strlen(del
));
5227 check_indent_newline(dl
);
5228 print_string(PRINT_ANY
, "resource_path", "resource_path %s", path
);
5232 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5234 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
5235 struct dpipe_table
*table
;
5236 uint32_t resource_units
;
5237 bool counters_enabled
;
5238 bool resource_valid
;
5242 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
5243 if (err
!= MNL_CB_OK
)
5246 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
5247 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
5248 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
5249 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
5250 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
5254 table
= dpipe_table_alloc();
5258 table
->name
= strdup(mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]));
5259 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
5260 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
5262 resource_valid
= nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
] &&
5264 if (resource_valid
) {
5265 table
->resource_id
= mnl_attr_get_u64(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
]);
5266 table
->resource_valid
= true;
5269 list_add_tail(&table
->list
, &ctx
->tables
->table_list
);
5270 if (!ctx
->print_tables
)
5273 check_indent_newline(ctx
->dl
);
5274 print_string(PRINT_ANY
, "name", "name %s", table
->name
);
5275 print_uint(PRINT_ANY
, "size", " size %u", size
);
5276 print_bool(PRINT_ANY
, "counters_enabled", " counters_enabled %s", counters_enabled
);
5278 if (resource_valid
) {
5279 resource_units
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS
]);
5280 resource_path_print(ctx
->dl
, ctx
->resources
,
5281 table
->resource_id
);
5282 print_uint(PRINT_ANY
, "resource_units", " resource_units %u",
5286 pr_out_array_start(ctx
->dl
, "match");
5287 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
5288 goto err_matches_show
;
5289 pr_out_array_end(ctx
->dl
);
5291 pr_out_array_start(ctx
->dl
, "action");
5292 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
5293 goto err_actions_show
;
5294 pr_out_array_end(ctx
->dl
);
5300 pr_out_array_end(ctx
->dl
);
5304 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5306 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
5307 struct nlattr
*nla_table
;
5309 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
5310 if (ctx
->print_tables
)
5311 pr_out_handle_start_arr(ctx
->dl
, tb
);
5312 if (dpipe_table_show(ctx
, nla_table
))
5313 goto err_table_show
;
5314 if (ctx
->print_tables
)
5315 pr_out_handle_end(ctx
->dl
);
5320 if (ctx
->print_tables
)
5321 pr_out_handle_end(ctx
->dl
);
5325 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5327 struct dpipe_ctx
*ctx
= data
;
5328 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5329 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5331 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5332 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5333 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
5334 return MNL_CB_ERROR
;
5336 if (dpipe_tables_show(ctx
, tb
))
5337 return MNL_CB_ERROR
;
5341 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
);
5343 static int cmd_dpipe_table_show(struct dl
*dl
)
5345 struct nlmsghdr
*nlh
;
5346 struct dpipe_ctx dpipe_ctx
= {};
5347 struct resource_ctx resource_ctx
= {};
5348 uint16_t flags
= NLM_F_REQUEST
;
5351 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
5355 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5357 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5361 dpipe_ctx
.print_tables
= true;
5363 dl_opts_put(nlh
, dl
);
5364 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
,
5367 pr_err("error get headers %s\n", strerror(dpipe_ctx
.err
));
5368 goto err_headers_get
;
5371 err
= resource_ctx_init(&resource_ctx
, dl
);
5373 goto err_resource_ctx_init
;
5375 resource_ctx
.print_resources
= false;
5376 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
, flags
);
5377 dl_opts_put(nlh
, dl
);
5378 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
5381 dpipe_ctx
.resources
= resource_ctx
.resources
;
5383 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5384 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
5385 dl_opts_put(nlh
, dl
);
5387 pr_out_section_start(dl
, "table");
5388 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, &dpipe_ctx
);
5389 pr_out_section_end(dl
);
5391 resource_ctx_fini(&resource_ctx
);
5392 dpipe_ctx_fini(&dpipe_ctx
);
5395 err_resource_ctx_init
:
5397 dpipe_ctx_fini(&dpipe_ctx
);
5401 static int cmd_dpipe_table_set(struct dl
*dl
)
5403 struct nlmsghdr
*nlh
;
5406 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
5407 NLM_F_REQUEST
| NLM_F_ACK
);
5409 err
= dl_argv_parse_put(nlh
, dl
,
5410 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
5411 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
5415 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5418 enum dpipe_value_type
{
5419 DPIPE_VALUE_TYPE_VALUE
,
5420 DPIPE_VALUE_TYPE_MASK
,
5424 dpipe_value_type_e2s(enum dpipe_value_type type
)
5427 case DPIPE_VALUE_TYPE_VALUE
:
5429 case DPIPE_VALUE_TYPE_MASK
:
5430 return "value_mask";
5436 struct dpipe_field_printer
{
5437 unsigned int field_id
;
5438 void (*printer
)(struct dpipe_ctx
*, enum dpipe_value_type
, void *);
5441 struct dpipe_header_printer
{
5442 struct dpipe_field_printer
*printers
;
5443 unsigned int printers_count
;
5444 unsigned int header_id
;
5447 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx
*ctx
,
5448 enum dpipe_value_type type
,
5451 struct in_addr ip_addr
;
5453 ip_addr
.s_addr
= htonl(*(uint32_t *)value
);
5454 check_indent_newline(ctx
->dl
);
5455 print_string_name_value(dpipe_value_type_e2s(type
), inet_ntoa(ip_addr
));
5459 dpipe_field_printer_ethernet_addr(struct dpipe_ctx
*ctx
,
5460 enum dpipe_value_type type
,
5463 check_indent_newline(ctx
->dl
);
5464 print_string_name_value(dpipe_value_type_e2s(type
),
5465 ether_ntoa((struct ether_addr
*)value
));
5468 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx
*ctx
,
5469 enum dpipe_value_type type
,
5472 char str
[INET6_ADDRSTRLEN
];
5474 inet_ntop(AF_INET6
, value
, str
, INET6_ADDRSTRLEN
);
5475 check_indent_newline(ctx
->dl
);
5476 print_string_name_value(dpipe_value_type_e2s(type
), str
);
5479 static struct dpipe_field_printer dpipe_field_printers_ipv4
[] = {
5481 .printer
= dpipe_field_printer_ipv4_addr
,
5482 .field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
,
5486 static struct dpipe_header_printer dpipe_header_printer_ipv4
= {
5487 .printers
= dpipe_field_printers_ipv4
,
5488 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv4
),
5489 .header_id
= DEVLINK_DPIPE_HEADER_IPV4
,
5492 static struct dpipe_field_printer dpipe_field_printers_ethernet
[] = {
5494 .printer
= dpipe_field_printer_ethernet_addr
,
5495 .field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
,
5499 static struct dpipe_header_printer dpipe_header_printer_ethernet
= {
5500 .printers
= dpipe_field_printers_ethernet
,
5501 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ethernet
),
5502 .header_id
= DEVLINK_DPIPE_HEADER_ETHERNET
,
5505 static struct dpipe_field_printer dpipe_field_printers_ipv6
[] = {
5507 .printer
= dpipe_field_printer_ipv6_addr
,
5508 .field_id
= DEVLINK_DPIPE_FIELD_IPV6_DST_IP
,
5512 static struct dpipe_header_printer dpipe_header_printer_ipv6
= {
5513 .printers
= dpipe_field_printers_ipv6
,
5514 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv6
),
5515 .header_id
= DEVLINK_DPIPE_HEADER_IPV6
,
5518 static struct dpipe_header_printer
*dpipe_header_printers
[] = {
5519 &dpipe_header_printer_ipv4
,
5520 &dpipe_header_printer_ethernet
,
5521 &dpipe_header_printer_ipv6
,
5524 static int dpipe_print_prot_header(struct dpipe_ctx
*ctx
,
5525 struct dpipe_op_info
*info
,
5526 enum dpipe_value_type type
,
5529 unsigned int header_printers_count
= ARRAY_SIZE(dpipe_header_printers
);
5530 struct dpipe_header_printer
*header_printer
;
5531 struct dpipe_field_printer
*field_printer
;
5532 unsigned int field_printers_count
;
5536 for (i
= 0; i
< header_printers_count
; i
++) {
5537 header_printer
= dpipe_header_printers
[i
];
5538 if (header_printer
->header_id
!= info
->header_id
)
5540 field_printers_count
= header_printer
->printers_count
;
5541 for (j
= 0; j
< field_printers_count
; j
++) {
5542 field_printer
= &header_printer
->printers
[j
];
5543 if (field_printer
->field_id
!= info
->field_id
)
5545 field_printer
->printer(ctx
, type
, value
);
5553 static void __pr_out_entry_value(struct dpipe_ctx
*ctx
,
5555 unsigned int value_len
,
5556 struct dpipe_op_info
*info
,
5557 enum dpipe_value_type type
)
5559 if (info
->header_global
&&
5560 !dpipe_print_prot_header(ctx
, info
, type
, value
))
5563 if (value_len
== sizeof(uint32_t)) {
5564 uint32_t *value_32
= value
;
5566 check_indent_newline(ctx
->dl
);
5567 print_uint_name_value(dpipe_value_type_e2s(type
), *value_32
);
5571 static void pr_out_dpipe_entry_value(struct dpipe_ctx
*ctx
,
5572 struct nlattr
**nla_match_value
,
5573 struct dpipe_op_info
*info
)
5575 void *value
, *value_mask
;
5576 uint32_t value_mapping
;
5580 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
5581 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
5583 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5584 value
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5587 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
5588 check_indent_newline(ctx
->dl
);
5589 print_uint(PRINT_ANY
, "mapping_value", "mapping_value %u", value_mapping
);
5593 value_mask
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
5594 __pr_out_entry_value(ctx
, value_mask
, value_len
, info
,
5595 DPIPE_VALUE_TYPE_MASK
);
5598 __pr_out_entry_value(ctx
, value
, value_len
, info
, DPIPE_VALUE_TYPE_VALUE
);
5601 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
5604 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5605 struct dpipe_match match
;
5608 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
5609 if (err
!= MNL_CB_OK
)
5612 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
5613 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5617 pr_out_entry_start(ctx
->dl
);
5618 if (dpipe_match_parse(&match
,
5619 nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
5620 goto err_match_parse
;
5621 pr_out_dpipe_match(&match
, ctx
);
5622 pr_out_dpipe_entry_value(ctx
, nla_match_value
, &match
.info
);
5623 pr_out_entry_end(ctx
->dl
);
5628 pr_out_entry_end(ctx
->dl
);
5632 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
5635 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
5636 struct dpipe_action action
;
5639 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
5640 if (err
!= MNL_CB_OK
)
5643 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
5644 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
5648 pr_out_entry_start(ctx
->dl
);
5649 if (dpipe_action_parse(&action
,
5650 nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
5651 goto err_action_parse
;
5652 pr_out_dpipe_action(&action
, ctx
);
5653 pr_out_dpipe_entry_value(ctx
, nla_action_value
, &action
.info
);
5654 pr_out_entry_end(ctx
->dl
);
5659 pr_out_entry_end(ctx
->dl
);
5664 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
5665 struct nlattr
*nla_action_values
)
5667 struct nlattr
*nla_action_value
;
5669 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
5670 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
5677 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
5678 struct nlattr
*nla_match_values
)
5680 struct nlattr
*nla_match_value
;
5682 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
5683 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
5689 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5691 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
5692 uint32_t entry_index
;
5696 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
5697 if (err
!= MNL_CB_OK
)
5700 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
5701 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
5702 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
5706 check_indent_newline(ctx
->dl
);
5707 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
5708 print_uint(PRINT_ANY
, "index", "index %u", entry_index
);
5710 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
5711 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
5712 print_uint(PRINT_ANY
, "counter", " counter %u", counter
);
5715 pr_out_array_start(ctx
->dl
, "match_value");
5716 if (dpipe_tables_match_values_show(ctx
,
5717 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
5718 goto err_match_values_show
;
5719 pr_out_array_end(ctx
->dl
);
5721 pr_out_array_start(ctx
->dl
, "action_value");
5722 if (dpipe_tables_action_values_show(ctx
,
5723 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
5724 goto err_action_values_show
;
5725 pr_out_array_end(ctx
->dl
);
5728 err_action_values_show
:
5729 err_match_values_show
:
5730 pr_out_array_end(ctx
->dl
);
5734 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5736 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
5737 struct nlattr
*nla_entry
;
5739 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
5740 pr_out_handle_start_arr(ctx
->dl
, tb
);
5741 if (dpipe_entry_show(ctx
, nla_entry
))
5742 goto err_entry_show
;
5743 pr_out_handle_end(ctx
->dl
);
5748 pr_out_handle_end(ctx
->dl
);
5752 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5754 struct dpipe_ctx
*ctx
= data
;
5755 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5756 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5758 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5759 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5760 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
5761 return MNL_CB_ERROR
;
5763 if (dpipe_table_entries_show(ctx
, tb
))
5764 return MNL_CB_ERROR
;
5768 static int cmd_dpipe_table_dump(struct dl
*dl
)
5770 struct nlmsghdr
*nlh
;
5771 struct dpipe_ctx ctx
= {};
5772 uint16_t flags
= NLM_F_REQUEST
;
5775 err
= dpipe_ctx_init(&ctx
, dl
);
5779 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
5783 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5784 dl_opts_put(nlh
, dl
);
5785 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5787 pr_err("error get headers %s\n", strerror(ctx
.err
));
5791 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5792 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
5793 dl_opts_put(nlh
, dl
);
5795 pr_out_section_start(dl
, "table_entry");
5796 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, &ctx
);
5797 pr_out_section_end(dl
);
5799 dpipe_ctx_fini(&ctx
);
5803 static void cmd_dpipe_table_help(void)
5805 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
5806 "where OBJECT-LIST := { show | set | dump }\n");
5809 static int cmd_dpipe_table(struct dl
*dl
)
5811 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5812 cmd_dpipe_table_help();
5814 } else if (dl_argv_match(dl
, "show")) {
5816 return cmd_dpipe_table_show(dl
);
5817 } else if (dl_argv_match(dl
, "set")) {
5819 return cmd_dpipe_table_set(dl
);
5820 } else if (dl_argv_match(dl
, "dump")) {
5822 return cmd_dpipe_table_dump(dl
);
5824 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5828 static void cmd_dpipe_help(void)
5830 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
5831 "where OBJECT-LIST := { header | table }\n");
5834 static int cmd_dpipe(struct dl
*dl
)
5836 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5839 } else if (dl_argv_match(dl
, "header")) {
5841 return cmd_dpipe_header(dl
);
5842 } else if (dl_argv_match(dl
, "table")) {
5844 return cmd_dpipe_table(dl
);
5846 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5851 resource_parse(struct resource_ctx
*ctx
, struct resource
*resource
,
5852 struct nlattr
**nla_resource
)
5854 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
] ||
5855 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
] ||
5856 !nla_resource
[DEVLINK_ATTR_RESOURCE_ID
] ||
5857 !nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
] ||
5858 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
] ||
5859 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
] ||
5860 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]) {
5864 resource
->name
= strdup(mnl_attr_get_str(nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
]));
5865 resource
->size
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
]);
5866 resource
->id
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_ID
]);
5867 resource
->unit
= mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
]);
5868 resource
->size_min
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
]);
5869 resource
->size_max
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
]);
5870 resource
->size_gran
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]);
5872 if (nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
])
5873 resource
->size_new
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
]);
5875 resource
->size_new
= resource
->size
;
5877 if (nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]) {
5878 resource
->size_occ
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]);
5879 resource
->occ_valid
= true;
5882 if (resource
->size_new
!= resource
->size
)
5883 ctx
->pending_change
= true;
5889 resource_get(struct resource_ctx
*ctx
, struct resource
*resource
,
5890 struct resource
*parent_resource
, struct nlattr
*nl
)
5892 struct nlattr
*nla_resource
[DEVLINK_ATTR_MAX
+ 1] = {};
5893 struct nlattr
*nla_child_resource
;
5894 struct nlattr
*nla_resources
;
5904 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_resource
);
5905 if (err
!= MNL_CB_OK
)
5908 err
= resource_parse(ctx
, resource
, nla_resource
);
5912 resource
->parent
= parent_resource
;
5913 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
])
5916 resource
->size_valid
= !!mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_VALID
]);
5917 nla_resources
= nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
];
5919 mnl_attr_for_each_nested(nla_child_resource
, nla_resources
) {
5920 struct resource
*child_resource
;
5921 struct list_head
*list
;
5923 child_resource
= resource_alloc();
5924 if (!child_resource
)
5928 list
= &ctx
->resources
->resource_list
;
5930 list
= &resource
->resource_list
;
5932 list_add_tail(&child_resource
->list
, list
);
5933 err
= resource_get(ctx
, child_resource
, resource
,
5934 nla_child_resource
);
5942 static const char *resource_unit_str_get(enum devlink_resource_unit unit
)
5945 case DEVLINK_RESOURCE_UNIT_ENTRY
: return "entry";
5946 default: return "<unknown unit>";
5950 static void resource_show(struct resource
*resource
,
5951 struct resource_ctx
*ctx
)
5953 struct resource
*child_resource
;
5954 struct dpipe_table
*table
;
5955 struct dl
*dl
= ctx
->dl
;
5958 check_indent_newline(dl
);
5959 print_string(PRINT_ANY
, "name", "name %s", resource
->name
);
5961 resource_path_print(dl
, ctx
->resources
, resource
->id
);
5962 pr_out_u64(dl
, "size", resource
->size
);
5963 if (resource
->size
!= resource
->size_new
)
5964 pr_out_u64(dl
, "size_new", resource
->size_new
);
5965 if (resource
->occ_valid
)
5966 print_uint(PRINT_ANY
, "occ", " occ %u", resource
->size_occ
);
5967 print_string(PRINT_ANY
, "unit", " unit %s",
5968 resource_unit_str_get(resource
->unit
));
5970 if (resource
->size_min
!= resource
->size_max
) {
5971 print_uint(PRINT_ANY
, "size_min", " size_min %u",
5972 resource
->size_min
);
5973 pr_out_u64(dl
, "size_max", resource
->size_max
);
5974 print_uint(PRINT_ANY
, "size_gran", " size_gran %u",
5975 resource
->size_gran
);
5978 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
)
5979 if (table
->resource_id
== resource
->id
&&
5980 table
->resource_valid
)
5984 pr_out_array_start(dl
, "dpipe_tables");
5986 print_string(PRINT_ANY
, "dpipe_tables", " dpipe_tables none",
5989 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
) {
5990 if (table
->resource_id
!= resource
->id
||
5991 !table
->resource_valid
)
5993 pr_out_entry_start(dl
);
5994 check_indent_newline(dl
);
5995 print_string(PRINT_ANY
, "table_name", "table_name %s",
5997 pr_out_entry_end(dl
);
6000 pr_out_array_end(dl
);
6002 if (list_empty(&resource
->resource_list
))
6005 if (ctx
->pending_change
) {
6006 check_indent_newline(dl
);
6007 print_string(PRINT_ANY
, "size_valid", "size_valid %s",
6008 resource
->size_valid
? "true" : "false");
6010 pr_out_array_start(dl
, "resources");
6011 list_for_each_entry(child_resource
, &resource
->resource_list
, list
) {
6012 pr_out_entry_start(dl
);
6013 resource_show(child_resource
, ctx
);
6014 pr_out_entry_end(dl
);
6016 pr_out_array_end(dl
);
6020 resources_show(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6022 struct resources
*resources
= ctx
->resources
;
6023 struct resource
*resource
;
6025 list_for_each_entry(resource
, &resources
->resource_list
, list
) {
6026 pr_out_handle_start_arr(ctx
->dl
, tb
);
6027 resource_show(resource
, ctx
);
6028 pr_out_handle_end(ctx
->dl
);
6032 static int resources_get(struct resource_ctx
*ctx
, struct nlattr
**tb
)
6034 return resource_get(ctx
, NULL
, NULL
, tb
[DEVLINK_ATTR_RESOURCE_LIST
]);
6037 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
6039 struct resource_ctx
*ctx
= data
;
6040 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6041 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6044 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6045 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6046 !tb
[DEVLINK_ATTR_RESOURCE_LIST
])
6047 return MNL_CB_ERROR
;
6049 err
= resources_get(ctx
, tb
);
6052 return MNL_CB_ERROR
;
6055 if (ctx
->print_resources
)
6056 resources_show(ctx
, tb
);
6061 static int cmd_resource_show(struct dl
*dl
)
6063 struct nlmsghdr
*nlh
;
6064 struct dpipe_ctx dpipe_ctx
= {};
6065 struct resource_ctx resource_ctx
= {};
6068 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, 0);
6072 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
,
6074 dl_opts_put(nlh
, dl
);
6076 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
6080 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
,
6083 pr_err("error get tables %s\n", strerror(dpipe_ctx
.err
));
6087 err
= resource_ctx_init(&resource_ctx
, dl
);
6091 resource_ctx
.print_resources
= true;
6092 resource_ctx
.tables
= dpipe_ctx
.tables
;
6093 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6094 NLM_F_REQUEST
| NLM_F_ACK
);
6095 dl_opts_put(nlh
, dl
);
6096 pr_out_section_start(dl
, "resources");
6097 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
6099 pr_out_section_end(dl
);
6100 resource_ctx_fini(&resource_ctx
);
6102 dpipe_ctx_fini(&dpipe_ctx
);
6106 static void cmd_resource_help(void)
6108 pr_err("Usage: devlink resource show DEV\n"
6109 " devlink resource set DEV path PATH size SIZE\n");
6112 static struct resource
*
6113 resource_find_by_name(struct list_head
*list
, char *name
)
6115 struct resource
*resource
;
6117 list_for_each_entry(resource
, list
, list
) {
6118 if (!strcmp(resource
->name
, name
))
6125 resource_path_parse(struct resource_ctx
*ctx
, const char *resource_path
,
6126 uint32_t *p_resource_id
, bool *p_resource_valid
)
6128 struct resource
*resource
;
6129 uint32_t resource_id
= 0;
6130 char *resource_path_dup
;
6131 struct list_head
*list
;
6132 const char del
[] = "/";
6133 char *resource_name
;
6135 resource_path_dup
= strdup(resource_path
);
6136 list
= &ctx
->resources
->resource_list
;
6137 resource_name
= strtok(resource_path_dup
, del
);
6138 while (resource_name
!= NULL
) {
6139 resource
= resource_find_by_name(list
, resource_name
);
6141 goto err_resource_lookup
;
6143 list
= &resource
->resource_list
;
6144 resource_name
= strtok(NULL
, del
);
6145 resource_id
= resource
->id
;
6147 free(resource_path_dup
);
6148 *p_resource_valid
= true;
6149 *p_resource_id
= resource_id
;
6152 err_resource_lookup
:
6153 free(resource_path_dup
);
6157 static int cmd_resource_set(struct dl
*dl
)
6159 struct nlmsghdr
*nlh
;
6160 struct resource_ctx ctx
= {};
6163 err
= resource_ctx_init(&ctx
, dl
);
6167 ctx
.print_resources
= false;
6168 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_RESOURCE_PATH
|
6169 DL_OPT_RESOURCE_SIZE
, 0);
6173 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
6175 dl_opts_put(nlh
, dl
);
6176 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
, &ctx
);
6178 pr_err("error getting resources %s\n", strerror(ctx
.err
));
6182 err
= resource_path_parse(&ctx
, dl
->opts
.resource_path
,
6183 &dl
->opts
.resource_id
,
6184 &dl
->opts
.resource_id_valid
);
6186 pr_err("error parsing resource path %s\n", strerror(-err
));
6190 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_SET
,
6191 NLM_F_REQUEST
| NLM_F_ACK
);
6193 dl_opts_put(nlh
, dl
);
6194 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6196 resource_ctx_fini(&ctx
);
6200 static int cmd_resource(struct dl
*dl
)
6202 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6203 cmd_resource_help();
6205 } else if (dl_argv_match(dl
, "show")) {
6207 return cmd_resource_show(dl
);
6208 } else if (dl_argv_match(dl
, "set")) {
6210 return cmd_resource_set(dl
);
6212 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6216 static void pr_out_region_handle_start(struct dl
*dl
, struct nlattr
**tb
)
6218 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
6219 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
6220 const char *region_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_REGION_NAME
]);
6223 sprintf(buf
, "%s/%s/%s", bus_name
, dev_name
, region_name
);
6224 if (dl
->json_output
)
6225 open_json_object(buf
);
6230 static void pr_out_region_handle_end(struct dl
*dl
)
6232 if (dl
->json_output
)
6233 close_json_object();
6238 static void pr_out_region_snapshots_start(struct dl
*dl
, bool array
)
6240 __pr_out_indent_newline(dl
);
6241 if (dl
->json_output
)
6242 open_json_array(PRINT_JSON
, "snapshot");
6244 pr_out("snapshot %s", array
? "[" : "");
6247 static void pr_out_region_snapshots_end(struct dl
*dl
, bool array
)
6249 if (dl
->json_output
)
6250 close_json_array(PRINT_JSON
, NULL
);
6255 static void pr_out_region_snapshots_id(struct dl
*dl
, struct nlattr
**tb
, int index
)
6257 uint32_t snapshot_id
;
6259 if (!tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6262 snapshot_id
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
]);
6264 if (dl
->json_output
)
6265 print_uint(PRINT_JSON
, NULL
, NULL
, snapshot_id
);
6267 pr_out("%s%u", index
? " " : "", snapshot_id
);
6270 static void pr_out_snapshots(struct dl
*dl
, struct nlattr
**tb
)
6272 struct nlattr
*tb_snapshot
[DEVLINK_ATTR_MAX
+ 1] = {};
6273 struct nlattr
*nla_sanpshot
;
6276 pr_out_region_snapshots_start(dl
, true);
6277 mnl_attr_for_each_nested(nla_sanpshot
, tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
]) {
6278 err
= mnl_attr_parse_nested(nla_sanpshot
, attr_cb
, tb_snapshot
);
6279 if (err
!= MNL_CB_OK
)
6281 pr_out_region_snapshots_id(dl
, tb_snapshot
, index
++);
6283 pr_out_region_snapshots_end(dl
, true);
6286 static void pr_out_snapshot(struct dl
*dl
, struct nlattr
**tb
)
6288 pr_out_region_snapshots_start(dl
, false);
6289 pr_out_region_snapshots_id(dl
, tb
, 0);
6290 pr_out_region_snapshots_end(dl
, false);
6293 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
)
6295 pr_out_region_handle_start(dl
, tb
);
6297 if (tb
[DEVLINK_ATTR_REGION_SIZE
])
6298 pr_out_u64(dl
, "size",
6299 mnl_attr_get_u64(tb
[DEVLINK_ATTR_REGION_SIZE
]));
6301 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
])
6302 pr_out_snapshots(dl
, tb
);
6304 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
6305 pr_out_snapshot(dl
, tb
);
6307 pr_out_region_handle_end(dl
);
6310 static int cmd_region_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6312 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6313 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6314 struct dl
*dl
= data
;
6316 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6317 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6318 !tb
[DEVLINK_ATTR_REGION_NAME
] || !tb
[DEVLINK_ATTR_REGION_SIZE
])
6319 return MNL_CB_ERROR
;
6321 pr_out_region(dl
, tb
);
6326 static int cmd_region_show(struct dl
*dl
)
6328 struct nlmsghdr
*nlh
;
6329 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6332 if (dl_argc(dl
) == 0)
6333 flags
|= NLM_F_DUMP
;
6335 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_GET
, flags
);
6337 if (dl_argc(dl
) > 0) {
6338 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
, 0);
6343 pr_out_section_start(dl
, "regions");
6344 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_show_cb
, dl
);
6345 pr_out_section_end(dl
);
6349 static int cmd_region_snapshot_del(struct dl
*dl
)
6351 struct nlmsghdr
*nlh
;
6354 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_DEL
,
6355 NLM_F_REQUEST
| NLM_F_ACK
);
6357 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6358 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6362 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6365 static int cmd_region_read_cb(const struct nlmsghdr
*nlh
, void *data
)
6367 struct nlattr
*nla_entry
, *nla_chunk_data
, *nla_chunk_addr
;
6368 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6369 struct nlattr
*tb_field
[DEVLINK_ATTR_MAX
+ 1] = {};
6370 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6371 struct dl
*dl
= data
;
6374 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6375 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6376 !tb
[DEVLINK_ATTR_REGION_CHUNKS
])
6377 return MNL_CB_ERROR
;
6379 mnl_attr_for_each_nested(nla_entry
, tb
[DEVLINK_ATTR_REGION_CHUNKS
]) {
6380 err
= mnl_attr_parse_nested(nla_entry
, attr_cb
, tb_field
);
6381 if (err
!= MNL_CB_OK
)
6382 return MNL_CB_ERROR
;
6384 nla_chunk_data
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_DATA
];
6385 if (!nla_chunk_data
)
6388 nla_chunk_addr
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_ADDR
];
6389 if (!nla_chunk_addr
)
6392 pr_out_region_chunk(dl
, mnl_attr_get_payload(nla_chunk_data
),
6393 mnl_attr_get_payload_len(nla_chunk_data
),
6394 mnl_attr_get_u64(nla_chunk_addr
));
6399 static int cmd_region_dump(struct dl
*dl
)
6401 struct nlmsghdr
*nlh
;
6404 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6405 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6407 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6408 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6412 pr_out_section_start(dl
, "dump");
6413 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6414 pr_out_section_end(dl
);
6415 if (!dl
->json_output
)
6420 static int cmd_region_read(struct dl
*dl
)
6422 struct nlmsghdr
*nlh
;
6425 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
6426 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
6428 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
6429 DL_OPT_REGION_ADDRESS
| DL_OPT_REGION_LENGTH
|
6430 DL_OPT_REGION_SNAPSHOT_ID
, 0);
6434 pr_out_section_start(dl
, "read");
6435 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
6436 pr_out_section_end(dl
);
6437 if (!dl
->json_output
)
6442 static void cmd_region_help(void)
6444 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
6445 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
6446 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
6447 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
6450 static int cmd_region(struct dl
*dl
)
6452 if (dl_no_arg(dl
)) {
6453 return cmd_region_show(dl
);
6454 } else if (dl_argv_match(dl
, "help")) {
6457 } else if (dl_argv_match(dl
, "show")) {
6459 return cmd_region_show(dl
);
6460 } else if (dl_argv_match(dl
, "del")) {
6462 return cmd_region_snapshot_del(dl
);
6463 } else if (dl_argv_match(dl
, "dump")) {
6465 return cmd_region_dump(dl
);
6466 } else if (dl_argv_match(dl
, "read")) {
6468 return cmd_region_read(dl
);
6470 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6474 static int cmd_health_set_params(struct dl
*dl
)
6476 struct nlmsghdr
*nlh
;
6479 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_SET
,
6480 NLM_F_REQUEST
| NLM_F_ACK
);
6481 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
,
6482 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD
|
6483 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER
);
6487 dl_opts_put(nlh
, dl
);
6488 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6491 static int cmd_health_dump_clear(struct dl
*dl
)
6493 struct nlmsghdr
*nlh
;
6496 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR
,
6497 NLM_F_REQUEST
| NLM_F_ACK
);
6499 err
= dl_argv_parse_put(nlh
, dl
,
6500 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6504 dl_opts_put(nlh
, dl
);
6505 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6508 static int fmsg_value_show(struct dl
*dl
, int type
, struct nlattr
*nl_data
)
6513 check_indent_newline(dl
);
6516 print_bool(PRINT_ANY
, NULL
, "%s", mnl_attr_get_u8(nl_data
));
6519 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u8(nl_data
));
6522 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u16(nl_data
));
6525 print_uint(PRINT_ANY
, NULL
, "%u", mnl_attr_get_u32(nl_data
));
6528 print_u64(PRINT_ANY
, NULL
, "%"PRIu64
, mnl_attr_get_u64(nl_data
));
6530 case MNL_TYPE_NUL_STRING
:
6531 print_string(PRINT_ANY
, NULL
, "%s", mnl_attr_get_str(nl_data
));
6533 case MNL_TYPE_BINARY
:
6534 len
= mnl_attr_get_payload_len(nl_data
);
6535 data
= mnl_attr_get_payload(nl_data
);
6536 pr_out_binary_value(dl
, data
, len
);
6544 static void pr_out_fmsg_name(struct dl
*dl
, char **name
)
6549 pr_out_name(dl
, *name
);
6556 struct list_head list
;
6559 struct fmsg_cb_data
{
6563 struct list_head entry_list
;
6566 static int cmd_fmsg_nest_queue(struct fmsg_cb_data
*fmsg_data
,
6567 uint8_t *attr_value
, bool insert
)
6569 struct nest_entry
*entry
;
6572 entry
= malloc(sizeof(struct nest_entry
));
6576 entry
->attr_type
= *attr_value
;
6577 list_add(&entry
->list
, &fmsg_data
->entry_list
);
6579 if (list_empty(&fmsg_data
->entry_list
))
6580 return MNL_CB_ERROR
;
6581 entry
= list_first_entry(&fmsg_data
->entry_list
,
6582 struct nest_entry
, list
);
6583 *attr_value
= entry
->attr_type
;
6584 list_del(&entry
->list
);
6590 static void pr_out_fmsg_group_start(struct dl
*dl
, char **name
)
6593 pr_out_fmsg_name(dl
, name
);
6595 __pr_out_indent_inc();
6598 static void pr_out_fmsg_group_end(struct dl
*dl
)
6601 __pr_out_indent_dec();
6604 static void pr_out_fmsg_start_object(struct dl
*dl
, char **name
)
6606 if (dl
->json_output
) {
6607 pr_out_fmsg_name(dl
, name
);
6608 open_json_object(NULL
);
6610 pr_out_fmsg_group_start(dl
, name
);
6614 static void pr_out_fmsg_end_object(struct dl
*dl
)
6616 if (dl
->json_output
)
6617 close_json_object();
6619 pr_out_fmsg_group_end(dl
);
6622 static void pr_out_fmsg_start_array(struct dl
*dl
, char **name
)
6624 if (dl
->json_output
) {
6625 pr_out_fmsg_name(dl
, name
);
6626 open_json_array(PRINT_JSON
, NULL
);
6628 pr_out_fmsg_group_start(dl
, name
);
6632 static void pr_out_fmsg_end_array(struct dl
*dl
)
6634 if (dl
->json_output
)
6635 close_json_array(PRINT_JSON
, NULL
);
6637 pr_out_fmsg_group_end(dl
);
6640 static int cmd_fmsg_nest(struct fmsg_cb_data
*fmsg_data
, uint8_t nest_value
,
6643 struct dl
*dl
= fmsg_data
->dl
;
6644 uint8_t value
= nest_value
;
6647 err
= cmd_fmsg_nest_queue(fmsg_data
, &value
, start
);
6648 if (err
!= MNL_CB_OK
)
6652 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6654 pr_out_fmsg_start_object(dl
, &fmsg_data
->name
);
6656 pr_out_fmsg_end_object(dl
);
6658 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6660 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6662 pr_out_fmsg_start_array(dl
, &fmsg_data
->name
);
6664 pr_out_fmsg_end_array(dl
);
6672 static int cmd_fmsg_object_cb(const struct nlmsghdr
*nlh
, void *data
)
6674 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6675 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6676 struct fmsg_cb_data
*fmsg_data
= data
;
6677 struct dl
*dl
= fmsg_data
->dl
;
6678 struct nlattr
*nla_object
;
6682 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6683 if (!tb
[DEVLINK_ATTR_FMSG
])
6684 return MNL_CB_ERROR
;
6686 mnl_attr_for_each_nested(nla_object
, tb
[DEVLINK_ATTR_FMSG
]) {
6687 attr_type
= mnl_attr_get_type(nla_object
);
6688 switch (attr_type
) {
6689 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
6690 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
6691 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
6692 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, true);
6693 if (err
!= MNL_CB_OK
)
6696 case DEVLINK_ATTR_FMSG_NEST_END
:
6697 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, false);
6698 if (err
!= MNL_CB_OK
)
6701 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
6702 free(fmsg_data
->name
);
6703 fmsg_data
->name
= strdup(mnl_attr_get_str(nla_object
));
6704 if (!fmsg_data
->name
)
6707 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
:
6708 fmsg_data
->value_type
= mnl_attr_get_u8(nla_object
);
6710 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
6711 pr_out_fmsg_name(dl
, &fmsg_data
->name
);
6712 err
= fmsg_value_show(dl
, fmsg_data
->value_type
,
6714 if (err
!= MNL_CB_OK
)
6724 static void cmd_fmsg_init(struct dl
*dl
, struct fmsg_cb_data
*data
)
6726 /* FMSG is dynamic: opening of an object or array causes a
6727 * newline. JSON starts with an { or [, but plain text should
6728 * not start with a new line. Ensure this by setting
6729 * g_new_line_count to 1: avoiding newline before the first
6732 g_new_line_count
= 1;
6735 INIT_LIST_HEAD(&data
->entry_list
);
6738 static int cmd_health_object_common(struct dl
*dl
, uint8_t cmd
, uint16_t flags
)
6740 struct fmsg_cb_data data
;
6741 struct nlmsghdr
*nlh
;
6744 nlh
= mnlg_msg_prepare(dl
->nlg
, cmd
, flags
| NLM_F_REQUEST
| NLM_F_ACK
);
6746 err
= dl_argv_parse_put(nlh
, dl
,
6747 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6751 cmd_fmsg_init(dl
, &data
);
6752 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_fmsg_object_cb
, &data
);
6757 static int cmd_health_dump_show(struct dl
*dl
)
6759 return cmd_health_object_common(dl
,
6760 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
,
6764 static int cmd_health_diagnose(struct dl
*dl
)
6766 return cmd_health_object_common(dl
,
6767 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
,
6771 static int cmd_health_recover(struct dl
*dl
)
6773 struct nlmsghdr
*nlh
;
6776 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
,
6777 NLM_F_REQUEST
| NLM_F_ACK
);
6779 err
= dl_argv_parse_put(nlh
, dl
,
6780 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6784 dl_opts_put(nlh
, dl
);
6785 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6788 enum devlink_health_reporter_state
{
6789 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
,
6790 DEVLINK_HEALTH_REPORTER_STATE_ERROR
,
6793 static const char *health_state_name(uint8_t state
)
6796 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
:
6797 return HEALTH_REPORTER_STATE_HEALTHY_STR
;
6798 case DEVLINK_HEALTH_REPORTER_STATE_ERROR
:
6799 return HEALTH_REPORTER_STATE_ERROR_STR
;
6801 return "<unknown state>";
6805 static void pr_out_dump_reporter_format_logtime(struct dl
*dl
, const struct nlattr
*attr
)
6807 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6808 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6809 uint64_t time_ms
= mnl_attr_get_u64(attr
);
6810 struct sysinfo s_info
;
6816 info
= localtime(&now
);
6817 err
= sysinfo(&s_info
);
6820 /* Subtract uptime in sec from now yields the time of system
6821 * uptime. To this, add time_ms which is the amount of
6822 * milliseconds elapsed between uptime and the dump taken.
6824 sec
= now
- s_info
.uptime
+ time_ms
/ 1000;
6825 info
= localtime(&sec
);
6827 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", info
);
6828 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", info
);
6829 check_indent_newline(dl
);
6830 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
6831 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
6834 static void pr_out_dump_report_timestamp(struct dl
*dl
, const struct nlattr
*attr
)
6836 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6837 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6842 ts
= mnl_attr_get_u64(attr
);
6843 tv_sec
= ts
/ 1000000000;
6844 tm
= localtime(&tv_sec
);
6846 strftime(dump_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", tm
);
6847 strftime(dump_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", tm
);
6849 check_indent_newline(dl
);
6850 print_string(PRINT_ANY
, "last_dump_date", "last_dump_date %s", dump_date
);
6851 print_string(PRINT_ANY
, "last_dump_time", " last_dump_time %s", dump_time
);
6854 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
)
6856 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6857 enum devlink_health_reporter_state state
;
6860 err
= mnl_attr_parse_nested(tb_health
[DEVLINK_ATTR_HEALTH_REPORTER
],
6862 if (err
!= MNL_CB_OK
)
6865 if (!tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
] ||
6866 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] ||
6867 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] ||
6868 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
])
6871 pr_out_handle_start_arr(dl
, tb_health
);
6873 check_indent_newline(dl
);
6874 print_string(PRINT_ANY
, "reporter", "reporter %s",
6875 mnl_attr_get_str(tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]));
6876 if (!dl
->json_output
) {
6878 __pr_out_indent_inc();
6880 state
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
]);
6881 check_indent_newline(dl
);
6882 print_string(PRINT_ANY
, "state", "state %s", health_state_name(state
));
6883 pr_out_u64(dl
, "error",
6884 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
]));
6885 pr_out_u64(dl
, "recover",
6886 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
]));
6887 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
])
6888 pr_out_dump_report_timestamp(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS
]);
6889 else if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
])
6890 pr_out_dump_reporter_format_logtime(dl
, tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
]);
6891 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
6892 pr_out_u64(dl
, "grace_period",
6893 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]));
6894 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
6895 print_bool(PRINT_ANY
, "auto_recover", " auto_recover %s",
6896 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]));
6898 __pr_out_indent_dec();
6899 pr_out_handle_end(dl
);
6902 static int cmd_health_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6904 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6905 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6906 struct dl
*dl
= data
;
6908 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6909 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6910 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
6911 return MNL_CB_ERROR
;
6913 pr_out_health(dl
, tb
);
6918 static int cmd_health_show(struct dl
*dl
)
6920 struct nlmsghdr
*nlh
;
6921 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6924 if (dl_argc(dl
) == 0)
6925 flags
|= NLM_F_DUMP
;
6926 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_GET
,
6929 if (dl_argc(dl
) > 0) {
6930 err
= dl_argv_parse_put(nlh
, dl
,
6932 DL_OPT_HEALTH_REPORTER_NAME
, 0);
6936 pr_out_section_start(dl
, "health");
6938 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_health_show_cb
, dl
);
6939 pr_out_section_end(dl
);
6943 static void cmd_health_help(void)
6945 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
6946 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
6947 pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n");
6948 pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n");
6949 pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n");
6950 pr_err(" devlink health set DEV reporter REPORTER_NAME\n");
6951 pr_err(" [ grace_period MSEC ]\n");
6952 pr_err(" [ auto_recover { true | false } ]\n");
6955 static int cmd_health(struct dl
*dl
)
6957 if (dl_argv_match(dl
, "help")) {
6960 } else if (dl_argv_match(dl
, "show") ||
6961 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
6963 return cmd_health_show(dl
);
6964 } else if (dl_argv_match(dl
, "recover")) {
6966 return cmd_health_recover(dl
);
6967 } else if (dl_argv_match(dl
, "diagnose")) {
6969 return cmd_health_diagnose(dl
);
6970 } else if (dl_argv_match(dl
, "dump")) {
6972 if (dl_argv_match(dl
, "show")) {
6974 return cmd_health_dump_show(dl
);
6975 } else if (dl_argv_match(dl
, "clear")) {
6977 return cmd_health_dump_clear(dl
);
6979 } else if (dl_argv_match(dl
, "set")) {
6981 return cmd_health_set_params(dl
);
6983 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6987 static const char *trap_type_name(uint8_t type
)
6990 case DEVLINK_TRAP_TYPE_DROP
:
6992 case DEVLINK_TRAP_TYPE_EXCEPTION
:
6995 return "<unknown type>";
6999 static const char *trap_action_name(uint8_t action
)
7002 case DEVLINK_TRAP_ACTION_DROP
:
7004 case DEVLINK_TRAP_ACTION_TRAP
:
7007 return "<unknown action>";
7011 static const char *trap_metadata_name(const struct nlattr
*attr
)
7013 switch (attr
->nla_type
) {
7014 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT
:
7015 return "input_port";
7016 case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE
:
7017 return "flow_action_cookie";
7019 return "<unknown metadata type>";
7022 static void pr_out_trap_metadata(struct dl
*dl
, struct nlattr
*attr
)
7024 struct nlattr
*attr_metadata
;
7026 pr_out_array_start(dl
, "metadata");
7027 mnl_attr_for_each_nested(attr_metadata
, attr
) {
7028 check_indent_newline(dl
);
7029 print_string(PRINT_ANY
, NULL
, "%s",
7030 trap_metadata_name(attr_metadata
));
7032 pr_out_array_end(dl
);
7035 static void pr_out_trap(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7037 uint8_t action
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_ACTION
]);
7038 uint8_t type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_TRAP_TYPE
]);
7041 pr_out_handle_start_arr(dl
, tb
);
7043 __pr_out_handle_start(dl
, tb
, true, false);
7045 check_indent_newline(dl
);
7046 print_string(PRINT_ANY
, "name", "name %s",
7047 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_NAME
]));
7048 print_string(PRINT_ANY
, "type", " type %s", trap_type_name(type
));
7049 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7050 print_string(PRINT_ANY
, "action", " action %s", trap_action_name(action
));
7051 print_string(PRINT_ANY
, "group", " group %s",
7052 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7054 pr_out_trap_metadata(dl
, tb
[DEVLINK_ATTR_TRAP_METADATA
]);
7055 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7056 pr_out_handle_end(dl
);
7059 static int cmd_trap_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7061 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7062 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7063 struct dl
*dl
= data
;
7065 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7066 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7067 !tb
[DEVLINK_ATTR_TRAP_NAME
] || !tb
[DEVLINK_ATTR_TRAP_TYPE
] ||
7068 !tb
[DEVLINK_ATTR_TRAP_ACTION
] ||
7069 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] ||
7070 !tb
[DEVLINK_ATTR_TRAP_METADATA
] || !tb
[DEVLINK_ATTR_STATS
])
7071 return MNL_CB_ERROR
;
7073 pr_out_trap(dl
, tb
, true);
7078 static void cmd_trap_help(void)
7080 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop } ]\n");
7081 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
7082 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop } ]\n");
7083 pr_err(" [ policer POLICER ] [ nopolicer ]\n");
7084 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
7085 pr_err(" devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
7086 pr_err(" devlink trap policer show DEV policer POLICER\n");
7089 static int cmd_trap_show(struct dl
*dl
)
7091 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7092 struct nlmsghdr
*nlh
;
7095 if (dl_argc(dl
) == 0)
7096 flags
|= NLM_F_DUMP
;
7098 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GET
, flags
);
7100 if (dl_argc(dl
) > 0) {
7101 err
= dl_argv_parse_put(nlh
, dl
,
7102 DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
, 0);
7107 pr_out_section_start(dl
, "trap");
7108 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_show_cb
, dl
);
7109 pr_out_section_end(dl
);
7114 static int cmd_trap_set(struct dl
*dl
)
7116 struct nlmsghdr
*nlh
;
7119 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_SET
,
7120 NLM_F_REQUEST
| NLM_F_ACK
);
7122 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_TRAP_NAME
,
7123 DL_OPT_TRAP_ACTION
);
7127 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7130 static void pr_out_trap_group(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7133 pr_out_handle_start_arr(dl
, tb
);
7135 __pr_out_handle_start(dl
, tb
, true, false);
7137 check_indent_newline(dl
);
7138 print_string(PRINT_ANY
, "name", "name %s",
7139 mnl_attr_get_str(tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
]));
7140 print_bool(PRINT_ANY
, "generic", " generic %s", !!tb
[DEVLINK_ATTR_TRAP_GENERIC
]);
7141 if (tb
[DEVLINK_ATTR_TRAP_POLICER_ID
])
7142 print_uint(PRINT_ANY
, "policer", " policer %u",
7143 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7144 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7145 pr_out_handle_end(dl
);
7148 static int cmd_trap_group_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7150 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7151 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7152 struct dl
*dl
= data
;
7154 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7155 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7156 !tb
[DEVLINK_ATTR_TRAP_GROUP_NAME
] || !tb
[DEVLINK_ATTR_STATS
])
7157 return MNL_CB_ERROR
;
7159 pr_out_trap_group(dl
, tb
, true);
7164 static int cmd_trap_group_show(struct dl
*dl
)
7166 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7167 struct nlmsghdr
*nlh
;
7170 if (dl_argc(dl
) == 0)
7171 flags
|= NLM_F_DUMP
;
7173 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_GET
, flags
);
7175 if (dl_argc(dl
) > 0) {
7176 err
= dl_argv_parse_put(nlh
, dl
,
7177 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7183 pr_out_section_start(dl
, "trap_group");
7184 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_group_show_cb
, dl
);
7185 pr_out_section_end(dl
);
7190 static int cmd_trap_group_set(struct dl
*dl
)
7192 struct nlmsghdr
*nlh
;
7195 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_GROUP_SET
,
7196 NLM_F_REQUEST
| NLM_F_ACK
);
7198 err
= dl_argv_parse_put(nlh
, dl
,
7199 DL_OPT_HANDLE
| DL_OPT_TRAP_GROUP_NAME
,
7200 DL_OPT_TRAP_ACTION
| DL_OPT_TRAP_POLICER_ID
);
7204 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7207 static int cmd_trap_group(struct dl
*dl
)
7209 if (dl_argv_match(dl
, "help")) {
7212 } else if (dl_argv_match(dl
, "show") ||
7213 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7215 return cmd_trap_group_show(dl
);
7216 } else if (dl_argv_match(dl
, "set")) {
7218 return cmd_trap_group_set(dl
);
7220 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7224 static void pr_out_trap_policer(struct dl
*dl
, struct nlattr
**tb
, bool array
)
7227 pr_out_handle_start_arr(dl
, tb
);
7229 __pr_out_handle_start(dl
, tb
, true, false);
7231 check_indent_newline(dl
);
7232 print_uint(PRINT_ANY
, "policer", "policer %u",
7233 mnl_attr_get_u32(tb
[DEVLINK_ATTR_TRAP_POLICER_ID
]));
7234 print_u64(PRINT_ANY
, "rate", " rate %llu",
7235 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
]));
7236 print_u64(PRINT_ANY
, "burst", " burst %llu",
7237 mnl_attr_get_u64(tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
]));
7238 if (tb
[DEVLINK_ATTR_STATS
])
7239 pr_out_stats(dl
, tb
[DEVLINK_ATTR_STATS
]);
7240 pr_out_handle_end(dl
);
7243 static int cmd_trap_policer_show_cb(const struct nlmsghdr
*nlh
, void *data
)
7245 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
7246 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
7247 struct dl
*dl
= data
;
7249 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
7250 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
7251 !tb
[DEVLINK_ATTR_TRAP_POLICER_ID
] ||
7252 !tb
[DEVLINK_ATTR_TRAP_POLICER_RATE
] ||
7253 !tb
[DEVLINK_ATTR_TRAP_POLICER_BURST
])
7254 return MNL_CB_ERROR
;
7256 pr_out_trap_policer(dl
, tb
, true);
7261 static int cmd_trap_policer_show(struct dl
*dl
)
7263 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
7264 struct nlmsghdr
*nlh
;
7267 if (dl_argc(dl
) == 0)
7268 flags
|= NLM_F_DUMP
;
7270 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_GET
, flags
);
7272 if (dl_argc(dl
) > 0) {
7273 err
= dl_argv_parse_put(nlh
, dl
,
7274 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7280 pr_out_section_start(dl
, "trap_policer");
7281 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_trap_policer_show_cb
, dl
);
7282 pr_out_section_end(dl
);
7287 static int cmd_trap_policer_set(struct dl
*dl
)
7289 struct nlmsghdr
*nlh
;
7292 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_TRAP_POLICER_SET
,
7293 NLM_F_REQUEST
| NLM_F_ACK
);
7295 err
= dl_argv_parse_put(nlh
, dl
,
7296 DL_OPT_HANDLE
| DL_OPT_TRAP_POLICER_ID
,
7297 DL_OPT_TRAP_POLICER_RATE
|
7298 DL_OPT_TRAP_POLICER_BURST
);
7302 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
7305 static int cmd_trap_policer(struct dl
*dl
)
7307 if (dl_argv_match(dl
, "help")) {
7310 } else if (dl_argv_match(dl
, "show") ||
7311 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7313 return cmd_trap_policer_show(dl
);
7314 } else if (dl_argv_match(dl
, "set")) {
7316 return cmd_trap_policer_set(dl
);
7318 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7322 static int cmd_trap(struct dl
*dl
)
7324 if (dl_argv_match(dl
, "help")) {
7327 } else if (dl_argv_match(dl
, "show") ||
7328 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
7330 return cmd_trap_show(dl
);
7331 } else if (dl_argv_match(dl
, "set")) {
7333 return cmd_trap_set(dl
);
7334 } else if (dl_argv_match(dl
, "group")) {
7336 return cmd_trap_group(dl
);
7337 } else if (dl_argv_match(dl
, "policer")) {
7339 return cmd_trap_policer(dl
);
7341 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
7345 static void help(void)
7347 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
7348 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
7349 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
7350 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
7353 static int dl_cmd(struct dl
*dl
, int argc
, char **argv
)
7358 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
7361 } else if (dl_argv_match(dl
, "dev")) {
7364 } else if (dl_argv_match(dl
, "port")) {
7366 return cmd_port(dl
);
7367 } else if (dl_argv_match(dl
, "sb")) {
7370 } else if (dl_argv_match(dl
, "monitor")) {
7373 } else if (dl_argv_match(dl
, "dpipe")) {
7375 return cmd_dpipe(dl
);
7376 } else if (dl_argv_match(dl
, "resource")) {
7378 return cmd_resource(dl
);
7379 } else if (dl_argv_match(dl
, "region")) {
7381 return cmd_region(dl
);
7382 } else if (dl_argv_match(dl
, "health")) {
7384 return cmd_health(dl
);
7385 } else if (dl_argv_match(dl
, "trap")) {
7387 return cmd_trap(dl
);
7389 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
7393 static int dl_init(struct dl
*dl
)
7397 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
7399 pr_err("Failed to connect to devlink Netlink\n");
7403 err
= ifname_map_init(dl
);
7405 pr_err("Failed to create index map\n");
7406 goto err_ifname_map_create
;
7408 new_json_obj_plain(dl
->json_output
);
7411 err_ifname_map_create
:
7412 mnlg_socket_close(dl
->nlg
);
7416 static void dl_fini(struct dl
*dl
)
7418 delete_json_obj_plain();
7419 ifname_map_fini(dl
);
7420 mnlg_socket_close(dl
->nlg
);
7423 static struct dl
*dl_alloc(void)
7427 dl
= calloc(1, sizeof(*dl
));
7433 static void dl_free(struct dl
*dl
)
7438 static int dl_batch(struct dl
*dl
, const char *name
, bool force
)
7442 int ret
= EXIT_SUCCESS
;
7444 if (name
&& strcmp(name
, "-") != 0) {
7445 if (freopen(name
, "r", stdin
) == NULL
) {
7447 "Cannot open file \"%s\" for reading: %s\n",
7448 name
, strerror(errno
));
7449 return EXIT_FAILURE
;
7454 while (getcmdline(&line
, &len
, stdin
) != -1) {
7458 largc
= makeargs(line
, largv
, 100);
7460 continue; /* blank line */
7462 if (dl_cmd(dl
, largc
, largv
)) {
7463 fprintf(stderr
, "Command failed %s:%d\n",
7477 int main(int argc
, char **argv
)
7479 static const struct option long_options
[] = {
7480 { "Version", no_argument
, NULL
, 'V' },
7481 { "force", no_argument
, NULL
, 'f' },
7482 { "batch", required_argument
, NULL
, 'b' },
7483 { "no-nice-names", no_argument
, NULL
, 'n' },
7484 { "json", no_argument
, NULL
, 'j' },
7485 { "pretty", no_argument
, NULL
, 'p' },
7486 { "verbose", no_argument
, NULL
, 'v' },
7487 { "statistics", no_argument
, NULL
, 's' },
7488 { "Netns", required_argument
, NULL
, 'N' },
7489 { NULL
, 0, NULL
, 0 }
7491 const char *batch_file
= NULL
;
7500 pr_err("Failed to allocate memory for devlink\n");
7501 return EXIT_FAILURE
;
7504 while ((opt
= getopt_long(argc
, argv
, "Vfb:njpvsN:",
7505 long_options
, NULL
)) >= 0) {
7509 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
7516 batch_file
= optarg
;
7519 dl
->no_nice_names
= true;
7522 dl
->json_output
= true;
7534 if (netns_switch(optarg
)) {
7540 pr_err("Unknown option.\n");
7557 err
= dl_batch(dl
, batch_file
, force
);
7559 err
= dl_cmd(dl
, argc
, argv
);