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>
21 #include <linux/genetlink.h>
22 #include <linux/devlink.h>
23 #include <libmnl/libmnl.h>
24 #include <netinet/ether.h>
25 #include <sys/sysinfo.h>
26 #include <sys/queue.h>
31 #include "json_writer.h"
34 #define ESWITCH_MODE_LEGACY "legacy"
35 #define ESWITCH_MODE_SWITCHDEV "switchdev"
36 #define ESWITCH_INLINE_MODE_NONE "none"
37 #define ESWITCH_INLINE_MODE_LINK "link"
38 #define ESWITCH_INLINE_MODE_NETWORK "network"
39 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
41 #define PARAM_CMODE_RUNTIME_STR "runtime"
42 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
43 #define PARAM_CMODE_PERMANENT_STR "permanent"
44 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
46 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
47 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
48 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
50 static int g_new_line_count
;
52 #define pr_err(args...) fprintf(stderr, ##args)
53 #define pr_out(args...) \
55 if (g_indent_newline) { \
56 fprintf(stdout, "%s", g_indent_str); \
57 g_indent_newline = false; \
59 fprintf(stdout, ##args); \
60 g_new_line_count = 0; \
63 #define pr_out_sp(num, args...) \
65 int ret = fprintf(stdout, ##args); \
67 fprintf(stdout, "%*s", num - ret, ""); \
68 g_new_line_count = 0; \
71 static int g_indent_level
;
72 static bool g_indent_newline
;
73 #define INDENT_STR_STEP 2
74 #define INDENT_STR_MAXLEN 32
75 static char g_indent_str
[INDENT_STR_MAXLEN
+ 1] = "";
77 static void __pr_out_indent_inc(void)
79 if (g_indent_level
+ INDENT_STR_STEP
> INDENT_STR_MAXLEN
)
81 g_indent_level
+= INDENT_STR_STEP
;
82 memset(g_indent_str
, ' ', sizeof(g_indent_str
));
83 g_indent_str
[g_indent_level
] = '\0';
86 static void __pr_out_indent_dec(void)
88 if (g_indent_level
- INDENT_STR_STEP
< 0)
90 g_indent_level
-= INDENT_STR_STEP
;
91 g_indent_str
[g_indent_level
] = '\0';
94 static void __pr_out_newline(void)
96 if (g_new_line_count
< 1) {
98 g_indent_newline
= true;
103 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
104 mnl_cb_t data_cb
, void *data
)
108 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
110 pr_err("devlink answers: %s\n", strerror(errno
));
116 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
117 const struct nlmsghdr
*nlh
,
118 mnl_cb_t data_cb
, void *data
)
122 err
= mnlg_socket_send(nlg
, nlh
);
124 pr_err("Failed to call mnlg_socket_send\n");
127 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
130 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
131 const char *group_name
)
135 err
= mnlg_socket_group_add(nlg
, group_name
);
137 pr_err("Failed to call mnlg_socket_group_add\n");
144 struct list_head list
;
151 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
152 const char *dev_name
,
156 struct ifname_map
*ifname_map
;
158 ifname_map
= calloc(1, sizeof(*ifname_map
));
161 ifname_map
->bus_name
= strdup(bus_name
);
162 ifname_map
->dev_name
= strdup(dev_name
);
163 ifname_map
->port_index
= port_index
;
164 ifname_map
->ifname
= strdup(ifname
);
165 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
166 !ifname_map
->ifname
) {
167 free(ifname_map
->ifname
);
168 free(ifname_map
->dev_name
);
169 free(ifname_map
->bus_name
);
176 static void ifname_map_free(struct ifname_map
*ifname_map
)
178 free(ifname_map
->ifname
);
179 free(ifname_map
->dev_name
);
180 free(ifname_map
->bus_name
);
184 #define DL_OPT_HANDLE BIT(0)
185 #define DL_OPT_HANDLEP BIT(1)
186 #define DL_OPT_PORT_TYPE BIT(2)
187 #define DL_OPT_PORT_COUNT BIT(3)
188 #define DL_OPT_SB BIT(4)
189 #define DL_OPT_SB_POOL BIT(5)
190 #define DL_OPT_SB_SIZE BIT(6)
191 #define DL_OPT_SB_TYPE BIT(7)
192 #define DL_OPT_SB_THTYPE BIT(8)
193 #define DL_OPT_SB_TH BIT(9)
194 #define DL_OPT_SB_TC BIT(10)
195 #define DL_OPT_ESWITCH_MODE BIT(11)
196 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
197 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
198 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
199 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
200 #define DL_OPT_RESOURCE_PATH BIT(16)
201 #define DL_OPT_RESOURCE_SIZE BIT(17)
202 #define DL_OPT_PARAM_NAME BIT(18)
203 #define DL_OPT_PARAM_VALUE BIT(19)
204 #define DL_OPT_PARAM_CMODE BIT(20)
205 #define DL_OPT_HANDLE_REGION BIT(21)
206 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
207 #define DL_OPT_REGION_ADDRESS BIT(23)
208 #define DL_OPT_REGION_LENGTH BIT(24)
209 #define DL_OPT_FLASH_FILE_NAME BIT(25)
210 #define DL_OPT_FLASH_COMPONENT BIT(26)
211 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
214 uint32_t present
; /* flags of present items */
218 enum devlink_port_type port_type
;
221 uint16_t sb_pool_index
;
222 uint32_t sb_pool_size
;
223 enum devlink_sb_pool_type sb_pool_type
;
224 enum devlink_sb_threshold_type sb_pool_thtype
;
225 uint32_t sb_threshold
;
226 uint16_t sb_tc_index
;
227 enum devlink_eswitch_mode eswitch_mode
;
228 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
229 const char *dpipe_table_name
;
230 bool dpipe_counters_enable
;
231 bool eswitch_encap_mode
;
232 const char *resource_path
;
233 uint32_t resource_size
;
234 uint32_t resource_id
;
235 bool resource_id_valid
;
236 const char *param_name
;
237 const char *param_value
;
238 enum devlink_param_cmode cmode
;
240 uint32_t region_snapshot_id
;
241 uint64_t region_address
;
242 uint64_t region_length
;
243 const char *flash_file_name
;
244 const char *flash_component
;
245 const char *reporter_name
;
249 struct mnlg_socket
*nlg
;
250 struct list_head ifname_map_list
;
267 static int dl_argc(struct dl
*dl
)
272 static char *dl_argv(struct dl
*dl
)
274 if (dl_argc(dl
) == 0)
279 static void dl_arg_inc(struct dl
*dl
)
281 if (dl_argc(dl
) == 0)
287 static char *dl_argv_next(struct dl
*dl
)
291 if (dl_argc(dl
) == 0)
299 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
301 if (index
>= dl_argc(dl
))
303 return dl
->argv
[index
];
306 static int strcmpx(const char *str1
, const char *str2
)
308 if (strlen(str1
) > strlen(str2
))
310 return strncmp(str1
, str2
, strlen(str1
));
313 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
315 if (dl_argc(dl
) == 0)
317 return strcmpx(dl_argv(dl
), pattern
) == 0;
320 static bool dl_no_arg(struct dl
*dl
)
322 return dl_argc(dl
) == 0;
325 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
326 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
327 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
328 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
329 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
330 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
331 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
332 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
333 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
334 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
335 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
336 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
337 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
338 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
339 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
340 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
341 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
342 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
343 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
344 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
345 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
346 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
347 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
348 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
349 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
350 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
351 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
352 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
353 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
354 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
355 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
356 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
357 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
358 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
359 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
360 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
361 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
362 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
363 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
364 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
365 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
366 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
367 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
368 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
369 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
370 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
371 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
372 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
373 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
374 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
375 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
376 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
377 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
378 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
379 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
380 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
381 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
382 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
383 [DEVLINK_ATTR_PARAM
] = MNL_TYPE_NESTED
,
384 [DEVLINK_ATTR_PARAM_NAME
] = MNL_TYPE_STRING
,
385 [DEVLINK_ATTR_PARAM_TYPE
] = MNL_TYPE_U8
,
386 [DEVLINK_ATTR_PARAM_VALUES_LIST
] = MNL_TYPE_NESTED
,
387 [DEVLINK_ATTR_PARAM_VALUE
] = MNL_TYPE_NESTED
,
388 [DEVLINK_ATTR_PARAM_VALUE_CMODE
] = MNL_TYPE_U8
,
389 [DEVLINK_ATTR_REGION_NAME
] = MNL_TYPE_STRING
,
390 [DEVLINK_ATTR_REGION_SIZE
] = MNL_TYPE_U64
,
391 [DEVLINK_ATTR_REGION_SNAPSHOTS
] = MNL_TYPE_NESTED
,
392 [DEVLINK_ATTR_REGION_SNAPSHOT
] = MNL_TYPE_NESTED
,
393 [DEVLINK_ATTR_REGION_SNAPSHOT_ID
] = MNL_TYPE_U32
,
394 [DEVLINK_ATTR_REGION_CHUNKS
] = MNL_TYPE_NESTED
,
395 [DEVLINK_ATTR_REGION_CHUNK
] = MNL_TYPE_NESTED
,
396 [DEVLINK_ATTR_REGION_CHUNK_DATA
] = MNL_TYPE_BINARY
,
397 [DEVLINK_ATTR_REGION_CHUNK_ADDR
] = MNL_TYPE_U64
,
398 [DEVLINK_ATTR_REGION_CHUNK_LEN
] = MNL_TYPE_U64
,
399 [DEVLINK_ATTR_INFO_DRIVER_NAME
] = MNL_TYPE_STRING
,
400 [DEVLINK_ATTR_INFO_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
401 [DEVLINK_ATTR_INFO_VERSION_FIXED
] = MNL_TYPE_NESTED
,
402 [DEVLINK_ATTR_INFO_VERSION_RUNNING
] = MNL_TYPE_NESTED
,
403 [DEVLINK_ATTR_INFO_VERSION_STORED
] = MNL_TYPE_NESTED
,
404 [DEVLINK_ATTR_INFO_VERSION_NAME
] = MNL_TYPE_STRING
,
405 [DEVLINK_ATTR_INFO_VERSION_VALUE
] = MNL_TYPE_STRING
,
406 [DEVLINK_ATTR_HEALTH_REPORTER
] = MNL_TYPE_NESTED
,
407 [DEVLINK_ATTR_HEALTH_REPORTER_NAME
] = MNL_TYPE_STRING
,
408 [DEVLINK_ATTR_HEALTH_REPORTER_STATE
] = MNL_TYPE_U8
,
409 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] = MNL_TYPE_U64
,
410 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] = MNL_TYPE_U64
,
411 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
] = MNL_TYPE_U64
,
412 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] = MNL_TYPE_U64
,
415 static int attr_cb(const struct nlattr
*attr
, void *data
)
417 const struct nlattr
**tb
= data
;
420 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
423 type
= mnl_attr_get_type(attr
);
424 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
431 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
433 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
434 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
435 struct dl
*dl
= data
;
436 struct ifname_map
*ifname_map
;
437 const char *bus_name
;
438 const char *dev_name
;
439 uint32_t port_ifindex
;
440 const char *port_ifname
;
442 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
443 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
444 !tb
[DEVLINK_ATTR_PORT_INDEX
])
447 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
450 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
451 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
452 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
453 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
454 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
455 port_ifindex
, port_ifname
);
458 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
463 static void ifname_map_fini(struct dl
*dl
)
465 struct ifname_map
*ifname_map
, *tmp
;
467 list_for_each_entry_safe(ifname_map
, tmp
,
468 &dl
->ifname_map_list
, list
) {
469 list_del(&ifname_map
->list
);
470 ifname_map_free(ifname_map
);
474 static int ifname_map_init(struct dl
*dl
)
476 struct nlmsghdr
*nlh
;
479 INIT_LIST_HEAD(&dl
->ifname_map_list
);
481 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
482 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
484 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
492 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
493 char **p_bus_name
, char **p_dev_name
,
494 uint32_t *p_port_index
)
496 struct ifname_map
*ifname_map
;
498 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
499 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
500 *p_bus_name
= ifname_map
->bus_name
;
501 *p_dev_name
= ifname_map
->dev_name
;
502 *p_port_index
= ifname_map
->port_index
;
509 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
510 const char *dev_name
, uint32_t port_index
,
513 struct ifname_map
*ifname_map
;
515 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
516 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
517 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
518 port_index
== ifname_map
->port_index
) {
519 *p_ifname
= ifname_map
->ifname
;
526 static unsigned int strslashcount(char *str
)
528 unsigned int count
= 0;
531 while ((pos
= strchr(pos
, '/'))) {
538 static int strslashrsplit(char *str
, char **before
, char **after
)
542 slash
= strrchr(str
, '/');
551 static int strtouint64_t(const char *str
, uint64_t *p_val
)
554 unsigned long long int val
;
556 val
= strtoull(str
, &endptr
, 10);
557 if (endptr
== str
|| *endptr
!= '\0')
565 static int strtouint32_t(const char *str
, uint32_t *p_val
)
568 unsigned long int val
;
570 val
= strtoul(str
, &endptr
, 10);
571 if (endptr
== str
|| *endptr
!= '\0')
579 static int strtouint16_t(const char *str
, uint16_t *p_val
)
582 unsigned long int val
;
584 val
= strtoul(str
, &endptr
, 10);
585 if (endptr
== str
|| *endptr
!= '\0')
593 static int strtouint8_t(const char *str
, uint8_t *p_val
)
596 unsigned long int val
;
598 val
= strtoul(str
, &endptr
, 10);
599 if (endptr
== str
|| *endptr
!= '\0')
607 static int strtobool(const char *str
, bool *p_val
)
611 if (!strcmp(str
, "true") || !strcmp(str
, "1"))
613 else if (!strcmp(str
, "false") || !strcmp(str
, "0"))
621 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
623 strslashrsplit(str
, p_bus_name
, p_dev_name
);
627 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
629 char *str
= dl_argv_next(dl
);
632 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
635 if (strslashcount(str
) != 1) {
636 pr_err("Wrong devlink identification string format.\n");
637 pr_err("Expected \"bus_name/dev_name\".\n");
640 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
643 static int __dl_argv_handle_port(char *str
,
644 char **p_bus_name
, char **p_dev_name
,
645 uint32_t *p_port_index
)
651 err
= strslashrsplit(str
, &handlestr
, &portstr
);
653 pr_err("Port identification \"%s\" is invalid\n", str
);
656 err
= strtouint32_t(portstr
, p_port_index
);
658 pr_err("Port index \"%s\" is not a number or not within range\n",
662 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
664 pr_err("Port identification \"%s\" is invalid\n", str
);
670 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
671 char **p_bus_name
, char **p_dev_name
,
672 uint32_t *p_port_index
)
676 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
679 pr_err("Netdevice \"%s\" not found\n", str
);
685 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
686 char **p_dev_name
, uint32_t *p_port_index
)
688 char *str
= dl_argv_next(dl
);
689 unsigned int slash_count
;
692 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
695 slash_count
= strslashcount(str
);
696 switch (slash_count
) {
698 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
699 p_dev_name
, p_port_index
);
701 return __dl_argv_handle_port(str
, p_bus_name
,
702 p_dev_name
, p_port_index
);
704 pr_err("Wrong port identification string format.\n");
705 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
710 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
711 char **p_dev_name
, uint32_t *p_port_index
,
712 uint32_t *p_handle_bit
)
714 char *str
= dl_argv_next(dl
);
715 unsigned int slash_count
;
719 pr_err("One of following identifications expected:\n"
720 "Devlink identification (\"bus_name/dev_name\")\n"
721 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
724 slash_count
= strslashcount(str
);
725 if (slash_count
== 1) {
726 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
729 *p_handle_bit
= DL_OPT_HANDLE
;
730 } else if (slash_count
== 2) {
731 err
= __dl_argv_handle_port(str
, p_bus_name
,
732 p_dev_name
, p_port_index
);
735 *p_handle_bit
= DL_OPT_HANDLEP
;
736 } else if (slash_count
== 0) {
737 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
738 p_dev_name
, p_port_index
);
741 *p_handle_bit
= DL_OPT_HANDLEP
;
743 pr_err("Wrong port identification string format.\n");
744 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
750 static int __dl_argv_handle_region(char *str
, char **p_bus_name
,
751 char **p_dev_name
, char **p_region
)
756 err
= strslashrsplit(str
, &handlestr
, p_region
);
758 pr_err("Region identification \"%s\" is invalid\n", str
);
761 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
763 pr_err("Region identification \"%s\" is invalid\n", str
);
769 static int dl_argv_handle_region(struct dl
*dl
, char **p_bus_name
,
770 char **p_dev_name
, char **p_region
)
772 char *str
= dl_argv_next(dl
);
773 unsigned int slash_count
;
776 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
780 slash_count
= strslashcount(str
);
781 if (slash_count
!= 2) {
782 pr_err("Wrong region identification string format.\n");
783 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
787 return __dl_argv_handle_region(str
, p_bus_name
, p_dev_name
, p_region
);
790 static int dl_argv_uint64_t(struct dl
*dl
, uint64_t *p_val
)
792 char *str
= dl_argv_next(dl
);
796 pr_err("Unsigned number argument expected\n");
800 err
= strtouint64_t(str
, p_val
);
802 pr_err("\"%s\" is not a number or not within range\n", str
);
808 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
810 char *str
= dl_argv_next(dl
);
814 pr_err("Unsigned number argument expected\n");
818 err
= strtouint32_t(str
, p_val
);
820 pr_err("\"%s\" is not a number or not within range\n", str
);
826 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
828 char *str
= dl_argv_next(dl
);
832 pr_err("Unsigned number argument expected\n");
836 err
= strtouint16_t(str
, p_val
);
838 pr_err("\"%s\" is not a number or not within range\n", str
);
844 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
846 const char *str
= dl_argv_next(dl
);
849 pr_err("String parameter expected\n");
856 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
858 if (strcmp(typestr
, "auto") == 0) {
859 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
860 } else if (strcmp(typestr
, "eth") == 0) {
861 *p_type
= DEVLINK_PORT_TYPE_ETH
;
862 } else if (strcmp(typestr
, "ib") == 0) {
863 *p_type
= DEVLINK_PORT_TYPE_IB
;
865 pr_err("Unknown port type \"%s\"\n", typestr
);
871 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
873 if (strcmp(typestr
, "ingress") == 0) {
874 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
875 } else if (strcmp(typestr
, "egress") == 0) {
876 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
878 pr_err("Unknown pool type \"%s\"\n", typestr
);
884 static int threshold_type_get(const char *typestr
,
885 enum devlink_sb_threshold_type
*p_type
)
887 if (strcmp(typestr
, "static") == 0) {
888 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
889 } else if (strcmp(typestr
, "dynamic") == 0) {
890 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
892 pr_err("Unknown threshold type \"%s\"\n", typestr
);
898 static int eswitch_mode_get(const char *typestr
,
899 enum devlink_eswitch_mode
*p_mode
)
901 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
902 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
903 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
904 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
906 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
912 static int eswitch_inline_mode_get(const char *typestr
,
913 enum devlink_eswitch_inline_mode
*p_mode
)
915 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
916 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
917 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
918 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
919 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
920 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
921 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
922 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
924 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
930 static int dpipe_counters_enable_get(const char *typestr
,
931 bool *counters_enable
)
933 if (strcmp(typestr
, "enable") == 0) {
934 *counters_enable
= 1;
935 } else if (strcmp(typestr
, "disable") == 0) {
936 *counters_enable
= 0;
938 pr_err("Unknown counter_state \"%s\"\n", typestr
);
944 static int eswitch_encap_mode_get(const char *typestr
, bool *p_mode
)
946 if (strcmp(typestr
, "enable") == 0) {
948 } else if (strcmp(typestr
, "disable") == 0) {
951 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
957 static int param_cmode_get(const char *cmodestr
,
958 enum devlink_param_cmode
*cmode
)
960 if (strcmp(cmodestr
, PARAM_CMODE_RUNTIME_STR
) == 0) {
961 *cmode
= DEVLINK_PARAM_CMODE_RUNTIME
;
962 } else if (strcmp(cmodestr
, PARAM_CMODE_DRIVERINIT_STR
) == 0) {
963 *cmode
= DEVLINK_PARAM_CMODE_DRIVERINIT
;
964 } else if (strcmp(cmodestr
, PARAM_CMODE_PERMANENT_STR
) == 0) {
965 *cmode
= DEVLINK_PARAM_CMODE_PERMANENT
;
967 pr_err("Unknown configuration mode \"%s\"\n", cmodestr
);
973 struct dl_args_metadata
{
975 char err_msg
[DL_ARGS_REQUIRED_MAX_ERR_LEN
];
978 static const struct dl_args_metadata dl_args_required
[] = {
979 {DL_OPT_PORT_TYPE
, "Port type not set."},
980 {DL_OPT_PORT_COUNT
, "Port split count option expected."},
981 {DL_OPT_SB_POOL
, "Pool index option expected."},
982 {DL_OPT_SB_SIZE
, "Pool size option expected."},
983 {DL_OPT_SB_TYPE
, "Pool type option expected."},
984 {DL_OPT_SB_THTYPE
, "Pool threshold type option expected."},
985 {DL_OPT_SB_TH
, "Threshold option expected."},
986 {DL_OPT_SB_TC
, "TC index option expected."},
987 {DL_OPT_ESWITCH_MODE
, "E-Switch mode option expected."},
988 {DL_OPT_ESWITCH_INLINE_MODE
, "E-Switch inline-mode option expected."},
989 {DL_OPT_DPIPE_TABLE_NAME
, "Dpipe table name expected."},
990 {DL_OPT_DPIPE_TABLE_COUNTERS
, "Dpipe table counter state expected."},
991 {DL_OPT_ESWITCH_ENCAP_MODE
, "E-Switch encapsulation option expected."},
992 {DL_OPT_PARAM_NAME
, "Parameter name expected."},
993 {DL_OPT_PARAM_VALUE
, "Value to set expected."},
994 {DL_OPT_PARAM_CMODE
, "Configuration mode expected."},
995 {DL_OPT_REGION_SNAPSHOT_ID
, "Region snapshot id expected."},
996 {DL_OPT_REGION_ADDRESS
, "Region address value expected."},
997 {DL_OPT_REGION_LENGTH
, "Region length value expected."},
998 {DL_OPT_HEALTH_REPORTER_NAME
, "Reporter's name is expected."},
1001 static int dl_args_finding_required_validate(uint32_t o_required
,
1007 for (i
= 0; i
< ARRAY_SIZE(dl_args_required
); i
++) {
1008 o_flag
= dl_args_required
[i
].o_flag
;
1009 if ((o_required
& o_flag
) && !(o_found
& o_flag
)) {
1010 pr_err("%s\n", dl_args_required
[i
].err_msg
);
1017 static int dl_argv_parse(struct dl
*dl
, uint32_t o_required
,
1018 uint32_t o_optional
)
1020 struct dl_opts
*opts
= &dl
->opts
;
1021 uint32_t o_all
= o_required
| o_optional
;
1022 uint32_t o_found
= 0;
1025 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
1026 uint32_t handle_bit
;
1028 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
1029 &opts
->port_index
, &handle_bit
);
1032 o_found
|= handle_bit
;
1033 } else if (o_required
& DL_OPT_HANDLE
) {
1034 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
1037 o_found
|= DL_OPT_HANDLE
;
1038 } else if (o_required
& DL_OPT_HANDLEP
) {
1039 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
1043 o_found
|= DL_OPT_HANDLEP
;
1044 } else if (o_required
& DL_OPT_HANDLE_REGION
) {
1045 err
= dl_argv_handle_region(dl
, &opts
->bus_name
,
1047 &opts
->region_name
);
1050 o_found
|= DL_OPT_HANDLE_REGION
;
1053 while (dl_argc(dl
)) {
1054 if (dl_argv_match(dl
, "type") &&
1055 (o_all
& DL_OPT_PORT_TYPE
)) {
1056 const char *typestr
;
1059 err
= dl_argv_str(dl
, &typestr
);
1062 err
= port_type_get(typestr
, &opts
->port_type
);
1065 o_found
|= DL_OPT_PORT_TYPE
;
1066 } else if (dl_argv_match(dl
, "count") &&
1067 (o_all
& DL_OPT_PORT_COUNT
)) {
1069 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
1072 o_found
|= DL_OPT_PORT_COUNT
;
1073 } else if (dl_argv_match(dl
, "sb") &&
1074 (o_all
& DL_OPT_SB
)) {
1076 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
1079 o_found
|= DL_OPT_SB
;
1080 } else if (dl_argv_match(dl
, "pool") &&
1081 (o_all
& DL_OPT_SB_POOL
)) {
1083 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
1086 o_found
|= DL_OPT_SB_POOL
;
1087 } else if (dl_argv_match(dl
, "size") &&
1088 (o_all
& DL_OPT_SB_SIZE
)) {
1090 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
1093 o_found
|= DL_OPT_SB_SIZE
;
1094 } else if (dl_argv_match(dl
, "type") &&
1095 (o_all
& DL_OPT_SB_TYPE
)) {
1096 const char *typestr
;
1099 err
= dl_argv_str(dl
, &typestr
);
1102 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
1105 o_found
|= DL_OPT_SB_TYPE
;
1106 } else if (dl_argv_match(dl
, "thtype") &&
1107 (o_all
& DL_OPT_SB_THTYPE
)) {
1108 const char *typestr
;
1111 err
= dl_argv_str(dl
, &typestr
);
1114 err
= threshold_type_get(typestr
,
1115 &opts
->sb_pool_thtype
);
1118 o_found
|= DL_OPT_SB_THTYPE
;
1119 } else if (dl_argv_match(dl
, "th") &&
1120 (o_all
& DL_OPT_SB_TH
)) {
1122 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
1125 o_found
|= DL_OPT_SB_TH
;
1126 } else if (dl_argv_match(dl
, "tc") &&
1127 (o_all
& DL_OPT_SB_TC
)) {
1129 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
1132 o_found
|= DL_OPT_SB_TC
;
1133 } else if (dl_argv_match(dl
, "mode") &&
1134 (o_all
& DL_OPT_ESWITCH_MODE
)) {
1135 const char *typestr
;
1138 err
= dl_argv_str(dl
, &typestr
);
1141 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
1144 o_found
|= DL_OPT_ESWITCH_MODE
;
1145 } else if (dl_argv_match(dl
, "inline-mode") &&
1146 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1147 const char *typestr
;
1150 err
= dl_argv_str(dl
, &typestr
);
1153 err
= eswitch_inline_mode_get(
1154 typestr
, &opts
->eswitch_inline_mode
);
1157 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
1158 } else if (dl_argv_match(dl
, "name") &&
1159 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
1161 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
1164 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
1165 } else if (dl_argv_match(dl
, "counters") &&
1166 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1167 const char *typestr
;
1170 err
= dl_argv_str(dl
, &typestr
);
1173 err
= dpipe_counters_enable_get(typestr
,
1174 &opts
->dpipe_counters_enable
);
1177 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
1178 } else if (dl_argv_match(dl
, "encap") &&
1179 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1180 const char *typestr
;
1183 err
= dl_argv_str(dl
, &typestr
);
1186 err
= eswitch_encap_mode_get(typestr
,
1187 &opts
->eswitch_encap_mode
);
1190 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
1191 } else if (dl_argv_match(dl
, "path") &&
1192 (o_all
& DL_OPT_RESOURCE_PATH
)) {
1194 err
= dl_argv_str(dl
, &opts
->resource_path
);
1197 o_found
|= DL_OPT_RESOURCE_PATH
;
1198 } else if (dl_argv_match(dl
, "size") &&
1199 (o_all
& DL_OPT_RESOURCE_SIZE
)) {
1201 err
= dl_argv_uint32_t(dl
, &opts
->resource_size
);
1204 o_found
|= DL_OPT_RESOURCE_SIZE
;
1205 } else if (dl_argv_match(dl
, "name") &&
1206 (o_all
& DL_OPT_PARAM_NAME
)) {
1208 err
= dl_argv_str(dl
, &opts
->param_name
);
1211 o_found
|= DL_OPT_PARAM_NAME
;
1212 } else if (dl_argv_match(dl
, "value") &&
1213 (o_all
& DL_OPT_PARAM_VALUE
)) {
1215 err
= dl_argv_str(dl
, &opts
->param_value
);
1218 o_found
|= DL_OPT_PARAM_VALUE
;
1219 } else if (dl_argv_match(dl
, "cmode") &&
1220 (o_all
& DL_OPT_PARAM_CMODE
)) {
1221 const char *cmodestr
;
1224 err
= dl_argv_str(dl
, &cmodestr
);
1227 err
= param_cmode_get(cmodestr
, &opts
->cmode
);
1230 o_found
|= DL_OPT_PARAM_CMODE
;
1231 } else if (dl_argv_match(dl
, "snapshot") &&
1232 (o_all
& DL_OPT_REGION_SNAPSHOT_ID
)) {
1234 err
= dl_argv_uint32_t(dl
, &opts
->region_snapshot_id
);
1237 o_found
|= DL_OPT_REGION_SNAPSHOT_ID
;
1238 } else if (dl_argv_match(dl
, "address") &&
1239 (o_all
& DL_OPT_REGION_ADDRESS
)) {
1241 err
= dl_argv_uint64_t(dl
, &opts
->region_address
);
1244 o_found
|= DL_OPT_REGION_ADDRESS
;
1245 } else if (dl_argv_match(dl
, "length") &&
1246 (o_all
& DL_OPT_REGION_LENGTH
)) {
1248 err
= dl_argv_uint64_t(dl
, &opts
->region_length
);
1251 o_found
|= DL_OPT_REGION_LENGTH
;
1252 } else if (dl_argv_match(dl
, "file") &&
1253 (o_all
& DL_OPT_FLASH_FILE_NAME
)) {
1255 err
= dl_argv_str(dl
, &opts
->flash_file_name
);
1258 o_found
|= DL_OPT_FLASH_FILE_NAME
;
1259 } else if (dl_argv_match(dl
, "component") &&
1260 (o_all
& DL_OPT_FLASH_COMPONENT
)) {
1262 err
= dl_argv_str(dl
, &opts
->flash_component
);
1265 o_found
|= DL_OPT_FLASH_COMPONENT
;
1266 } else if (dl_argv_match(dl
, "reporter") &&
1267 (o_all
& DL_OPT_HEALTH_REPORTER_NAME
)) {
1269 err
= dl_argv_str(dl
, &opts
->reporter_name
);
1272 o_found
|= DL_OPT_HEALTH_REPORTER_NAME
;
1274 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
1279 opts
->present
= o_found
;
1281 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
1283 opts
->present
|= DL_OPT_SB
;
1286 return dl_args_finding_required_validate(o_required
, o_found
);
1289 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1291 struct dl_opts
*opts
= &dl
->opts
;
1293 if (opts
->present
& DL_OPT_HANDLE
) {
1294 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1295 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1296 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1297 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1298 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1299 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1301 } else if (opts
->present
& DL_OPT_HANDLE_REGION
) {
1302 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1303 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1304 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_REGION_NAME
,
1307 if (opts
->present
& DL_OPT_PORT_TYPE
)
1308 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1310 if (opts
->present
& DL_OPT_PORT_COUNT
)
1311 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1313 if (opts
->present
& DL_OPT_SB
)
1314 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1316 if (opts
->present
& DL_OPT_SB_POOL
)
1317 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1318 opts
->sb_pool_index
);
1319 if (opts
->present
& DL_OPT_SB_SIZE
)
1320 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1321 opts
->sb_pool_size
);
1322 if (opts
->present
& DL_OPT_SB_TYPE
)
1323 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1324 opts
->sb_pool_type
);
1325 if (opts
->present
& DL_OPT_SB_THTYPE
)
1326 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1327 opts
->sb_pool_thtype
);
1328 if (opts
->present
& DL_OPT_SB_TH
)
1329 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1330 opts
->sb_threshold
);
1331 if (opts
->present
& DL_OPT_SB_TC
)
1332 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1334 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1335 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1336 opts
->eswitch_mode
);
1337 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1338 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1339 opts
->eswitch_inline_mode
);
1340 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1341 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1342 opts
->dpipe_table_name
);
1343 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1344 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1345 opts
->dpipe_counters_enable
);
1346 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1347 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1348 opts
->eswitch_encap_mode
);
1349 if ((opts
->present
& DL_OPT_RESOURCE_PATH
) && opts
->resource_id_valid
)
1350 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_ID
,
1352 if (opts
->present
& DL_OPT_RESOURCE_SIZE
)
1353 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_SIZE
,
1354 opts
->resource_size
);
1355 if (opts
->present
& DL_OPT_PARAM_NAME
)
1356 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_NAME
,
1358 if (opts
->present
& DL_OPT_PARAM_CMODE
)
1359 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_CMODE
,
1361 if (opts
->present
& DL_OPT_REGION_SNAPSHOT_ID
)
1362 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_REGION_SNAPSHOT_ID
,
1363 opts
->region_snapshot_id
);
1364 if (opts
->present
& DL_OPT_REGION_ADDRESS
)
1365 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_ADDR
,
1366 opts
->region_address
);
1367 if (opts
->present
& DL_OPT_REGION_LENGTH
)
1368 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_LEN
,
1369 opts
->region_length
);
1370 if (opts
->present
& DL_OPT_FLASH_FILE_NAME
)
1371 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME
,
1372 opts
->flash_file_name
);
1373 if (opts
->present
& DL_OPT_FLASH_COMPONENT
)
1374 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
,
1375 opts
->flash_component
);
1376 if (opts
->present
& DL_OPT_HEALTH_REPORTER_NAME
)
1377 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
1378 opts
->reporter_name
);
1381 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1382 uint32_t o_required
, uint32_t o_optional
)
1386 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1389 dl_opts_put(nlh
, dl
);
1393 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1395 struct dl_opts
*opts
= &dl
->opts
;
1396 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1397 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1398 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1399 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1401 if (opts
->present
& DL_OPT_HANDLE
&&
1402 attr_bus_name
&& attr_dev_name
) {
1403 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1404 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1406 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1407 strcmp(dev_name
, opts
->dev_name
) != 0)
1410 if (opts
->present
& DL_OPT_HANDLEP
&&
1411 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1412 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1413 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1414 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1416 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1417 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1418 port_index
!= opts
->port_index
)
1421 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1422 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1424 if (sb_index
!= opts
->sb_index
)
1430 static void cmd_dev_help(void)
1432 pr_err("Usage: devlink dev show [ DEV ]\n");
1433 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1434 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1435 pr_err(" [ encap { disable | enable } ]\n");
1436 pr_err(" devlink dev eswitch show DEV\n");
1437 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1438 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1439 pr_err(" devlink dev reload DEV\n");
1440 pr_err(" devlink dev info [ DEV ]\n");
1441 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1444 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1445 const char *dev_name
)
1447 if (!dl
->arr_last
.present
)
1449 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1450 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1453 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1454 const char *dev_name
)
1456 dl
->arr_last
.present
= true;
1457 free(dl
->arr_last
.dev_name
);
1458 free(dl
->arr_last
.bus_name
);
1459 dl
->arr_last
.bus_name
= strdup(bus_name
);
1460 dl
->arr_last
.dev_name
= strdup(dev_name
);
1463 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1464 const char *dev_name
)
1466 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1469 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1470 const char *dev_name
)
1472 return dl
->arr_last
.present
&&
1473 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1476 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1477 bool content
, bool array
)
1479 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1480 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1483 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
1485 if (dl
->json_output
) {
1487 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1488 jsonw_end_array(dl
->jw
);
1489 if (should_arr_last_handle_start(dl
, bus_name
,
1491 jsonw_name(dl
->jw
, buf
);
1492 jsonw_start_array(dl
->jw
);
1493 jsonw_start_object(dl
->jw
);
1494 arr_last_handle_set(dl
, bus_name
, dev_name
);
1496 jsonw_start_object(dl
->jw
);
1499 jsonw_name(dl
->jw
, buf
);
1500 jsonw_start_object(dl
->jw
);
1504 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1505 __pr_out_indent_dec();
1506 if (should_arr_last_handle_start(dl
, bus_name
,
1508 pr_out("%s%s", buf
, content
? ":" : "");
1510 __pr_out_indent_inc();
1511 arr_last_handle_set(dl
, bus_name
, dev_name
);
1514 pr_out("%s%s", buf
, content
? ":" : "");
1519 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
1521 __pr_out_handle_start(dl
, tb
, true, true);
1524 static void pr_out_handle_end(struct dl
*dl
)
1526 if (dl
->json_output
)
1527 jsonw_end_object(dl
->jw
);
1532 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
1534 __pr_out_handle_start(dl
, tb
, false, false);
1535 pr_out_handle_end(dl
);
1538 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
1539 const char *dev_name
, uint32_t port_index
)
1541 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
1542 dl
->arr_last
.port_index
== port_index
;
1545 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
1546 const char *dev_name
, uint32_t port_index
)
1548 arr_last_handle_set(dl
, bus_name
, dev_name
);
1549 dl
->arr_last
.port_index
= port_index
;
1552 static bool should_arr_last_port_handle_start(struct dl
*dl
,
1553 const char *bus_name
,
1554 const char *dev_name
,
1555 uint32_t port_index
)
1557 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1560 static bool should_arr_last_port_handle_end(struct dl
*dl
,
1561 const char *bus_name
,
1562 const char *dev_name
,
1563 uint32_t port_index
)
1565 return dl
->arr_last
.present
&&
1566 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1569 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
1570 const char *dev_name
,
1571 uint32_t port_index
, bool try_nice
,
1574 static char buf
[32];
1575 char *ifname
= NULL
;
1577 if (dl
->no_nice_names
|| !try_nice
||
1578 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
1579 port_index
, &ifname
) != 0)
1580 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
1582 sprintf(buf
, "%s", ifname
);
1584 if (dl
->json_output
) {
1586 if (should_arr_last_port_handle_end(dl
, bus_name
,
1589 jsonw_end_array(dl
->jw
);
1590 if (should_arr_last_port_handle_start(dl
, bus_name
,
1593 jsonw_name(dl
->jw
, buf
);
1594 jsonw_start_array(dl
->jw
);
1595 jsonw_start_object(dl
->jw
);
1596 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
1599 jsonw_start_object(dl
->jw
);
1602 jsonw_name(dl
->jw
, buf
);
1603 jsonw_start_object(dl
->jw
);
1610 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1612 const char *bus_name
;
1613 const char *dev_name
;
1614 uint32_t port_index
;
1616 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1617 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1618 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1619 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
1622 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1624 const char *bus_name
;
1625 const char *dev_name
;
1626 uint32_t port_index
;
1628 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1629 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1630 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1631 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
1634 static void pr_out_port_handle_end(struct dl
*dl
)
1636 if (dl
->json_output
)
1637 jsonw_end_object(dl
->jw
);
1643 static void pr_out_str(struct dl
*dl
, const char *name
, const char *val
)
1645 if (dl
->json_output
) {
1646 jsonw_string_field(dl
->jw
, name
, val
);
1648 if (g_indent_newline
)
1649 pr_out("%s %s", name
, val
);
1651 pr_out(" %s %s", name
, val
);
1655 static void pr_out_bool(struct dl
*dl
, const char *name
, bool val
)
1657 if (dl
->json_output
)
1658 jsonw_bool_field(dl
->jw
, name
, val
);
1660 pr_out_str(dl
, name
, val
? "true" : "false");
1663 static void pr_out_uint(struct dl
*dl
, const char *name
, unsigned int val
)
1665 if (dl
->json_output
) {
1666 jsonw_uint_field(dl
->jw
, name
, val
);
1668 if (g_indent_newline
)
1669 pr_out("%s %u", name
, val
);
1671 pr_out(" %s %u", name
, val
);
1675 static void pr_out_u64(struct dl
*dl
, const char *name
, uint64_t val
)
1677 if (val
== (uint64_t) -1)
1678 return pr_out_str(dl
, name
, "unlimited");
1680 if (dl
->json_output
) {
1681 jsonw_u64_field(dl
->jw
, name
, val
);
1683 if (g_indent_newline
)
1684 pr_out("%s %lu", name
, val
);
1686 pr_out(" %s %lu", name
, val
);
1690 static void pr_out_bool_value(struct dl
*dl
, bool value
)
1692 if (dl
->json_output
)
1693 jsonw_bool(dl
->jw
, value
);
1695 pr_out(" %s", value
? "true" : "false");
1698 static void pr_out_uint_value(struct dl
*dl
, unsigned int value
)
1700 if (dl
->json_output
)
1701 jsonw_uint(dl
->jw
, value
);
1703 pr_out(" %u", value
);
1706 static void pr_out_uint64_value(struct dl
*dl
, uint64_t value
)
1708 if (dl
->json_output
)
1709 jsonw_u64(dl
->jw
, value
);
1711 pr_out(" %lu", value
);
1714 static void pr_out_binary_value(struct dl
*dl
, uint8_t *data
, uint32_t len
)
1718 if (dl
->json_output
)
1719 jsonw_start_array(dl
->jw
);
1724 if (dl
->json_output
) {
1725 jsonw_printf(dl
->jw
, "%d", data
[i
]);
1727 pr_out(" %02x", data
[i
]);
1733 if (dl
->json_output
)
1734 jsonw_end_array(dl
->jw
);
1735 else if ((i
- 1) % 16)
1739 static void pr_out_str_value(struct dl
*dl
, const char *value
)
1741 if (dl
->json_output
)
1742 jsonw_string(dl
->jw
, value
);
1744 pr_out(" %s", value
);
1747 static void pr_out_name(struct dl
*dl
, const char *name
)
1749 if (dl
->json_output
)
1750 jsonw_name(dl
->jw
, name
);
1752 pr_out(" %s:", name
);
1755 static void pr_out_region_chunk_start(struct dl
*dl
, uint64_t addr
)
1757 if (dl
->json_output
) {
1758 jsonw_name(dl
->jw
, "address");
1759 jsonw_uint(dl
->jw
, addr
);
1760 jsonw_name(dl
->jw
, "data");
1761 jsonw_start_array(dl
->jw
);
1765 static void pr_out_region_chunk_end(struct dl
*dl
)
1767 if (dl
->json_output
)
1768 jsonw_end_array(dl
->jw
);
1771 static void pr_out_region_chunk(struct dl
*dl
, uint8_t *data
, uint32_t len
,
1774 static uint64_t align_val
;
1777 pr_out_region_chunk_start(dl
, addr
);
1779 if (!dl
->json_output
)
1780 if (!(align_val
% 16))
1781 pr_out("%s%016"PRIx64
" ",
1782 align_val
? "\n" : "",
1787 if (dl
->json_output
)
1788 jsonw_printf(dl
->jw
, "%d", data
[i
]);
1790 pr_out("%02x ", data
[i
]);
1795 pr_out_region_chunk_end(dl
);
1798 static void pr_out_dev(struct dl
*dl
, struct nlattr
**tb
)
1800 pr_out_handle(dl
, tb
);
1803 static void pr_out_section_start(struct dl
*dl
, const char *name
)
1805 if (dl
->json_output
) {
1806 jsonw_start_object(dl
->jw
);
1807 jsonw_name(dl
->jw
, name
);
1808 jsonw_start_object(dl
->jw
);
1812 static void pr_out_section_end(struct dl
*dl
)
1814 if (dl
->json_output
) {
1815 if (dl
->arr_last
.present
)
1816 jsonw_end_array(dl
->jw
);
1817 jsonw_end_object(dl
->jw
);
1818 jsonw_end_object(dl
->jw
);
1822 static void pr_out_array_start(struct dl
*dl
, const char *name
)
1824 if (dl
->json_output
) {
1825 jsonw_name(dl
->jw
, name
);
1826 jsonw_start_array(dl
->jw
);
1828 __pr_out_indent_inc();
1830 pr_out("%s:", name
);
1831 __pr_out_indent_inc();
1836 static void pr_out_array_end(struct dl
*dl
)
1838 if (dl
->json_output
) {
1839 jsonw_end_array(dl
->jw
);
1841 __pr_out_indent_dec();
1842 __pr_out_indent_dec();
1846 static void pr_out_object_start(struct dl
*dl
, const char *name
)
1848 if (dl
->json_output
) {
1849 jsonw_name(dl
->jw
, name
);
1850 jsonw_start_object(dl
->jw
);
1852 __pr_out_indent_inc();
1854 pr_out("%s:", name
);
1855 __pr_out_indent_inc();
1860 static void pr_out_object_end(struct dl
*dl
)
1862 if (dl
->json_output
) {
1863 jsonw_end_object(dl
->jw
);
1865 __pr_out_indent_dec();
1866 __pr_out_indent_dec();
1870 static void pr_out_entry_start(struct dl
*dl
)
1872 if (dl
->json_output
)
1873 jsonw_start_object(dl
->jw
);
1876 static void pr_out_entry_end(struct dl
*dl
)
1878 if (dl
->json_output
)
1879 jsonw_end_object(dl
->jw
);
1884 static const char *param_cmode_name(uint8_t cmode
)
1887 case DEVLINK_PARAM_CMODE_RUNTIME
:
1888 return PARAM_CMODE_RUNTIME_STR
;
1889 case DEVLINK_PARAM_CMODE_DRIVERINIT
:
1890 return PARAM_CMODE_DRIVERINIT_STR
;
1891 case DEVLINK_PARAM_CMODE_PERMANENT
:
1892 return PARAM_CMODE_PERMANENT_STR
;
1893 default: return "<unknown type>";
1897 static const char *eswitch_mode_name(uint32_t mode
)
1900 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
1901 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
1902 default: return "<unknown mode>";
1906 static const char *eswitch_inline_mode_name(uint32_t mode
)
1909 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
1910 return ESWITCH_INLINE_MODE_NONE
;
1911 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
1912 return ESWITCH_INLINE_MODE_LINK
;
1913 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
1914 return ESWITCH_INLINE_MODE_NETWORK
;
1915 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
1916 return ESWITCH_INLINE_MODE_TRANSPORT
;
1918 return "<unknown mode>";
1922 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
1924 __pr_out_handle_start(dl
, tb
, true, false);
1926 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
])
1927 pr_out_str(dl
, "mode",
1928 eswitch_mode_name(mnl_attr_get_u16(tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
1930 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])
1931 pr_out_str(dl
, "inline-mode",
1932 eswitch_inline_mode_name(mnl_attr_get_u8(
1933 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
1935 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
1936 bool encap_mode
= !!mnl_attr_get_u8(tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]);
1938 pr_out_str(dl
, "encap", encap_mode
? "enable" : "disable");
1941 pr_out_handle_end(dl
);
1944 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1946 struct dl
*dl
= data
;
1947 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1948 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1950 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1951 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
1952 return MNL_CB_ERROR
;
1953 pr_out_eswitch(dl
, tb
);
1957 static int cmd_dev_eswitch_show(struct dl
*dl
)
1959 struct nlmsghdr
*nlh
;
1962 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
1963 NLM_F_REQUEST
| NLM_F_ACK
);
1965 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
1969 pr_out_section_start(dl
, "dev");
1970 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
1971 pr_out_section_end(dl
);
1975 static int cmd_dev_eswitch_set(struct dl
*dl
)
1977 struct nlmsghdr
*nlh
;
1980 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
1981 NLM_F_REQUEST
| NLM_F_ACK
);
1983 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
1984 DL_OPT_ESWITCH_MODE
|
1985 DL_OPT_ESWITCH_INLINE_MODE
|
1986 DL_OPT_ESWITCH_ENCAP_MODE
);
1991 if (dl
->opts
.present
== 1) {
1992 pr_err("Need to set at least one option\n");
1996 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1999 static int cmd_dev_eswitch(struct dl
*dl
)
2001 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2004 } else if (dl_argv_match(dl
, "set")) {
2006 return cmd_dev_eswitch_set(dl
);
2007 } else if (dl_argv_match(dl
, "show")) {
2009 return cmd_dev_eswitch_show(dl
);
2011 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2015 struct param_val_conv
{
2021 static bool param_val_conv_exists(const struct param_val_conv
*param_val_conv
,
2022 uint32_t len
, const char *name
)
2026 for (i
= 0; i
< len
; i
++)
2027 if (!strcmp(param_val_conv
[i
].name
, name
))
2034 param_val_conv_uint_get(const struct param_val_conv
*param_val_conv
,
2035 uint32_t len
, const char *name
, const char *vstr
,
2040 for (i
= 0; i
< len
; i
++)
2041 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2042 !strcmp(param_val_conv
[i
].vstr
, vstr
)) {
2043 *vuint
= param_val_conv
[i
].vuint
;
2051 param_val_conv_str_get(const struct param_val_conv
*param_val_conv
,
2052 uint32_t len
, const char *name
, uint32_t vuint
,
2057 for (i
= 0; i
< len
; i
++)
2058 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2059 param_val_conv
[i
].vuint
== vuint
) {
2060 *vstr
= param_val_conv
[i
].vstr
;
2067 static const struct param_val_conv param_val_conv
[] = {
2069 .name
= "fw_load_policy",
2071 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER
,
2074 .name
= "fw_load_policy",
2076 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH
,
2080 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2082 static void pr_out_param_value(struct dl
*dl
, const char *nla_name
,
2083 int nla_type
, struct nlattr
*nl
)
2085 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2086 struct nlattr
*val_attr
;
2091 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_value
);
2092 if (err
!= MNL_CB_OK
)
2095 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2096 (nla_type
!= MNL_TYPE_FLAG
&&
2097 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2100 pr_out_str(dl
, "cmode",
2101 param_cmode_name(mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
])));
2102 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2104 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2110 err
= param_val_conv_str_get(param_val_conv
,
2113 mnl_attr_get_u8(val_attr
),
2117 pr_out_str(dl
, "value", vstr
);
2119 pr_out_uint(dl
, "value", mnl_attr_get_u8(val_attr
));
2124 err
= param_val_conv_str_get(param_val_conv
,
2127 mnl_attr_get_u16(val_attr
),
2131 pr_out_str(dl
, "value", vstr
);
2133 pr_out_uint(dl
, "value", mnl_attr_get_u16(val_attr
));
2138 err
= param_val_conv_str_get(param_val_conv
,
2141 mnl_attr_get_u32(val_attr
),
2145 pr_out_str(dl
, "value", vstr
);
2147 pr_out_uint(dl
, "value", mnl_attr_get_u32(val_attr
));
2150 case MNL_TYPE_STRING
:
2151 pr_out_str(dl
, "value", mnl_attr_get_str(val_attr
));
2154 pr_out_bool(dl
, "value", val_attr
? true : false);
2159 static void pr_out_param(struct dl
*dl
, struct nlattr
**tb
, bool array
)
2161 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2162 struct nlattr
*param_value_attr
;
2163 const char *nla_name
;
2167 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2168 if (err
!= MNL_CB_OK
)
2170 if (!nla_param
[DEVLINK_ATTR_PARAM_NAME
] ||
2171 !nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2172 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2176 pr_out_handle_start_arr(dl
, tb
);
2178 __pr_out_handle_start(dl
, tb
, true, false);
2180 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2182 nla_name
= mnl_attr_get_str(nla_param
[DEVLINK_ATTR_PARAM_NAME
]);
2183 pr_out_str(dl
, "name", nla_name
);
2185 if (!nla_param
[DEVLINK_ATTR_PARAM_GENERIC
])
2186 pr_out_str(dl
, "type", "driver-specific");
2188 pr_out_str(dl
, "type", "generic");
2190 pr_out_array_start(dl
, "values");
2191 mnl_attr_for_each_nested(param_value_attr
,
2192 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2193 pr_out_entry_start(dl
);
2194 pr_out_param_value(dl
, nla_name
, nla_type
, param_value_attr
);
2195 pr_out_entry_end(dl
);
2197 pr_out_array_end(dl
);
2198 pr_out_handle_end(dl
);
2201 static int cmd_dev_param_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2203 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2204 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2205 struct dl
*dl
= data
;
2207 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2208 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2209 !tb
[DEVLINK_ATTR_PARAM
])
2210 return MNL_CB_ERROR
;
2211 pr_out_param(dl
, tb
, true);
2227 static int cmd_dev_param_set_cb(const struct nlmsghdr
*nlh
, void *data
)
2229 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2230 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2231 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2232 struct nlattr
*param_value_attr
;
2233 enum devlink_param_cmode cmode
;
2234 struct param_ctx
*ctx
= data
;
2235 struct dl
*dl
= ctx
->dl
;
2239 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2240 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2241 !tb
[DEVLINK_ATTR_PARAM
])
2242 return MNL_CB_ERROR
;
2244 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2245 if (err
!= MNL_CB_OK
)
2246 return MNL_CB_ERROR
;
2248 if (!nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2249 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2250 return MNL_CB_ERROR
;
2252 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2253 mnl_attr_for_each_nested(param_value_attr
,
2254 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2255 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2256 struct nlattr
*val_attr
;
2258 err
= mnl_attr_parse_nested(param_value_attr
,
2259 attr_cb
, nla_value
);
2260 if (err
!= MNL_CB_OK
)
2261 return MNL_CB_ERROR
;
2263 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2264 (nla_type
!= MNL_TYPE_FLAG
&&
2265 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2266 return MNL_CB_ERROR
;
2268 cmode
= mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
]);
2269 if (cmode
== dl
->opts
.cmode
) {
2270 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2273 ctx
->value
.vu8
= mnl_attr_get_u8(val_attr
);
2276 ctx
->value
.vu16
= mnl_attr_get_u16(val_attr
);
2279 ctx
->value
.vu32
= mnl_attr_get_u32(val_attr
);
2281 case MNL_TYPE_STRING
:
2282 ctx
->value
.vstr
= mnl_attr_get_str(val_attr
);
2285 ctx
->value
.vbool
= val_attr
? true : false;
2291 ctx
->nla_type
= nla_type
;
2295 static int cmd_dev_param_set(struct dl
*dl
)
2297 struct param_ctx ctx
= {};
2298 struct nlmsghdr
*nlh
;
2306 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
|
2308 DL_OPT_PARAM_VALUE
|
2309 DL_OPT_PARAM_CMODE
, 0);
2313 /* Get value type */
2314 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
,
2315 NLM_F_REQUEST
| NLM_F_ACK
);
2316 dl_opts_put(nlh
, dl
);
2319 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_set_cb
, &ctx
);
2323 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_SET
,
2324 NLM_F_REQUEST
| NLM_F_ACK
);
2325 dl_opts_put(nlh
, dl
);
2327 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2328 dl
->opts
.param_name
);
2330 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_TYPE
, ctx
.nla_type
);
2331 switch (ctx
.nla_type
) {
2334 err
= param_val_conv_uint_get(param_val_conv
,
2336 dl
->opts
.param_name
,
2337 dl
->opts
.param_value
,
2341 err
= strtouint8_t(dl
->opts
.param_value
, &val_u8
);
2344 goto err_param_value_parse
;
2345 if (val_u8
== ctx
.value
.vu8
)
2347 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u8
);
2351 err
= param_val_conv_uint_get(param_val_conv
,
2353 dl
->opts
.param_name
,
2354 dl
->opts
.param_value
,
2358 err
= strtouint16_t(dl
->opts
.param_value
, &val_u16
);
2361 goto err_param_value_parse
;
2362 if (val_u16
== ctx
.value
.vu16
)
2364 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u16
);
2368 err
= param_val_conv_uint_get(param_val_conv
,
2370 dl
->opts
.param_name
,
2371 dl
->opts
.param_value
,
2374 err
= strtouint32_t(dl
->opts
.param_value
, &val_u32
);
2376 goto err_param_value_parse
;
2377 if (val_u32
== ctx
.value
.vu32
)
2379 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u32
);
2382 err
= strtobool(dl
->opts
.param_value
, &val_bool
);
2384 goto err_param_value_parse
;
2385 if (val_bool
== ctx
.value
.vbool
)
2388 mnl_attr_put(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2391 case MNL_TYPE_STRING
:
2392 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2393 dl
->opts
.param_value
);
2394 if (!strcmp(dl
->opts
.param_value
, ctx
.value
.vstr
))
2398 printf("Value type not supported\n");
2401 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2403 err_param_value_parse
:
2404 pr_err("Value \"%s\" is not a number or not within range\n",
2405 dl
->opts
.param_value
);
2409 static int cmd_dev_param_show(struct dl
*dl
)
2411 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2412 struct nlmsghdr
*nlh
;
2415 if (dl_argc(dl
) == 0)
2416 flags
|= NLM_F_DUMP
;
2418 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
, flags
);
2420 if (dl_argc(dl
) > 0) {
2421 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
|
2422 DL_OPT_PARAM_NAME
, 0);
2427 pr_out_section_start(dl
, "param");
2428 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_show_cb
, dl
);
2429 pr_out_section_end(dl
);
2433 static int cmd_dev_param(struct dl
*dl
)
2435 if (dl_argv_match(dl
, "help")) {
2438 } else if (dl_argv_match(dl
, "show") ||
2439 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2441 return cmd_dev_param_show(dl
);
2442 } else if (dl_argv_match(dl
, "set")) {
2444 return cmd_dev_param_set(dl
);
2446 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2449 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2451 struct dl
*dl
= data
;
2452 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2453 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2455 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2456 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2457 return MNL_CB_ERROR
;
2462 static int cmd_dev_show(struct dl
*dl
)
2464 struct nlmsghdr
*nlh
;
2465 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2468 if (dl_argc(dl
) == 0)
2469 flags
|= NLM_F_DUMP
;
2471 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
2473 if (dl_argc(dl
) > 0) {
2474 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2479 pr_out_section_start(dl
, "dev");
2480 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
2481 pr_out_section_end(dl
);
2485 static void cmd_dev_reload_help(void)
2487 pr_err("Usage: devlink dev reload [ DEV ]\n");
2490 static int cmd_dev_reload(struct dl
*dl
)
2492 struct nlmsghdr
*nlh
;
2495 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2496 cmd_dev_reload_help();
2500 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RELOAD
,
2501 NLM_F_REQUEST
| NLM_F_ACK
);
2503 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2507 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2510 static void pr_out_versions_single(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2511 const char *name
, int type
)
2513 struct nlattr
*version
;
2515 mnl_attr_for_each(version
, nlh
, sizeof(struct genlmsghdr
)) {
2516 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2517 const char *ver_value
;
2518 const char *ver_name
;
2521 if (mnl_attr_get_type(version
) != type
)
2524 err
= mnl_attr_parse_nested(version
, attr_cb
, tb
);
2525 if (err
!= MNL_CB_OK
)
2528 if (!tb
[DEVLINK_ATTR_INFO_VERSION_NAME
] ||
2529 !tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
])
2533 pr_out_object_start(dl
, name
);
2537 ver_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_NAME
]);
2538 ver_value
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
]);
2540 pr_out_str(dl
, ver_name
, ver_value
);
2541 if (!dl
->json_output
)
2546 pr_out_object_end(dl
);
2549 static void pr_out_info(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2550 struct nlattr
**tb
, bool has_versions
)
2552 __pr_out_handle_start(dl
, tb
, true, false);
2554 __pr_out_indent_inc();
2555 if (tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
]) {
2556 struct nlattr
*nla_drv
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
];
2558 if (!dl
->json_output
)
2560 pr_out_str(dl
, "driver", mnl_attr_get_str(nla_drv
));
2563 if (tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
]) {
2564 struct nlattr
*nla_sn
= tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
];
2566 if (!dl
->json_output
)
2568 pr_out_str(dl
, "serial_number", mnl_attr_get_str(nla_sn
));
2570 __pr_out_indent_dec();
2573 pr_out_object_start(dl
, "versions");
2575 pr_out_versions_single(dl
, nlh
, "fixed",
2576 DEVLINK_ATTR_INFO_VERSION_FIXED
);
2577 pr_out_versions_single(dl
, nlh
, "running",
2578 DEVLINK_ATTR_INFO_VERSION_RUNNING
);
2579 pr_out_versions_single(dl
, nlh
, "stored",
2580 DEVLINK_ATTR_INFO_VERSION_STORED
);
2582 pr_out_object_end(dl
);
2585 pr_out_handle_end(dl
);
2588 static int cmd_versions_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2590 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2591 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2592 bool has_versions
, has_info
;
2593 struct dl
*dl
= data
;
2595 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2597 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2598 return MNL_CB_ERROR
;
2600 has_versions
= tb
[DEVLINK_ATTR_INFO_VERSION_FIXED
] ||
2601 tb
[DEVLINK_ATTR_INFO_VERSION_RUNNING
] ||
2602 tb
[DEVLINK_ATTR_INFO_VERSION_STORED
];
2603 has_info
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
] ||
2604 tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
] ||
2608 pr_out_info(dl
, nlh
, tb
, has_versions
);
2613 static void cmd_dev_info_help(void)
2615 pr_err("Usage: devlink dev info [ DEV ]\n");
2618 static int cmd_dev_info(struct dl
*dl
)
2620 struct nlmsghdr
*nlh
;
2621 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2624 if (dl_argv_match(dl
, "help")) {
2625 cmd_dev_info_help();
2629 if (dl_argc(dl
) == 0)
2630 flags
|= NLM_F_DUMP
;
2632 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_INFO_GET
, flags
);
2634 if (dl_argc(dl
) > 0) {
2635 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2640 pr_out_section_start(dl
, "info");
2641 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_versions_show_cb
, dl
);
2642 pr_out_section_end(dl
);
2646 static void cmd_dev_flash_help(void)
2648 pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
2651 static int cmd_dev_flash(struct dl
*dl
)
2653 struct nlmsghdr
*nlh
;
2656 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2657 cmd_dev_flash_help();
2661 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_FLASH_UPDATE
,
2662 NLM_F_REQUEST
| NLM_F_ACK
);
2664 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_FLASH_FILE_NAME
,
2665 DL_OPT_FLASH_COMPONENT
);
2669 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2672 static int cmd_dev(struct dl
*dl
)
2674 if (dl_argv_match(dl
, "help")) {
2677 } else if (dl_argv_match(dl
, "show") ||
2678 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2680 return cmd_dev_show(dl
);
2681 } else if (dl_argv_match(dl
, "eswitch")) {
2683 return cmd_dev_eswitch(dl
);
2684 } else if (dl_argv_match(dl
, "reload")) {
2686 return cmd_dev_reload(dl
);
2687 } else if (dl_argv_match(dl
, "param")) {
2689 return cmd_dev_param(dl
);
2690 } else if (dl_argv_match(dl
, "info")) {
2692 return cmd_dev_info(dl
);
2693 } else if (dl_argv_match(dl
, "flash")) {
2695 return cmd_dev_flash(dl
);
2697 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2701 static void cmd_port_help(void)
2703 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
2704 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
2705 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
2706 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
2709 static const char *port_type_name(uint32_t type
)
2712 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
2713 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
2714 case DEVLINK_PORT_TYPE_ETH
: return "eth";
2715 case DEVLINK_PORT_TYPE_IB
: return "ib";
2716 default: return "<unknown type>";
2720 static const char *port_flavour_name(uint16_t flavour
)
2723 case DEVLINK_PORT_FLAVOUR_PHYSICAL
:
2725 case DEVLINK_PORT_FLAVOUR_CPU
:
2727 case DEVLINK_PORT_FLAVOUR_DSA
:
2730 return "<unknown flavour>";
2734 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
2736 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
2737 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
2739 pr_out_port_handle_start(dl
, tb
, false);
2741 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
2743 pr_out_str(dl
, "type", port_type_name(port_type
));
2745 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
2747 if (port_type
!= des_port_type
)
2748 pr_out_str(dl
, "des_type",
2749 port_type_name(des_port_type
));
2752 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
2753 pr_out_str(dl
, "netdev",
2754 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
2755 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
])
2756 pr_out_str(dl
, "ibdev",
2757 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
2758 if (tb
[DEVLINK_ATTR_PORT_FLAVOUR
]) {
2759 uint16_t port_flavour
=
2760 mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_FLAVOUR
]);
2762 pr_out_str(dl
, "flavour", port_flavour_name(port_flavour
));
2764 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
2765 pr_out_uint(dl
, "split_group",
2766 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
2767 pr_out_port_handle_end(dl
);
2770 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2772 struct dl
*dl
= data
;
2773 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2774 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2776 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2777 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2778 !tb
[DEVLINK_ATTR_PORT_INDEX
])
2779 return MNL_CB_ERROR
;
2780 pr_out_port(dl
, tb
);
2784 static int cmd_port_show(struct dl
*dl
)
2786 struct nlmsghdr
*nlh
;
2787 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2790 if (dl_argc(dl
) == 0)
2791 flags
|= NLM_F_DUMP
;
2793 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
2795 if (dl_argc(dl
) > 0) {
2796 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
2801 pr_out_section_start(dl
, "port");
2802 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
2803 pr_out_section_end(dl
);
2807 static int cmd_port_set(struct dl
*dl
)
2809 struct nlmsghdr
*nlh
;
2812 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
2813 NLM_F_REQUEST
| NLM_F_ACK
);
2815 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
2819 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2822 static int cmd_port_split(struct dl
*dl
)
2824 struct nlmsghdr
*nlh
;
2827 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
2828 NLM_F_REQUEST
| NLM_F_ACK
);
2830 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
2834 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2837 static int cmd_port_unsplit(struct dl
*dl
)
2839 struct nlmsghdr
*nlh
;
2842 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
2843 NLM_F_REQUEST
| NLM_F_ACK
);
2845 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
2849 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2852 static int cmd_port(struct dl
*dl
)
2854 if (dl_argv_match(dl
, "help")) {
2857 } else if (dl_argv_match(dl
, "show") ||
2858 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2860 return cmd_port_show(dl
);
2861 } else if (dl_argv_match(dl
, "set")) {
2863 return cmd_port_set(dl
);
2864 } else if (dl_argv_match(dl
, "split")) {
2866 return cmd_port_split(dl
);
2867 } else if (dl_argv_match(dl
, "unsplit")) {
2869 return cmd_port_unsplit(dl
);
2871 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2875 static void cmd_sb_help(void)
2877 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
2878 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
2879 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
2880 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
2881 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
2882 pr_err(" pool POOL_INDEX ]\n");
2883 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
2884 pr_err(" pool POOL_INDEX th THRESHOLD\n");
2885 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
2886 pr_err(" type { ingress | egress } ]\n");
2887 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
2888 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
2889 pr_err(" th THRESHOLD\n");
2890 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
2891 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
2892 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
2895 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
2897 pr_out_handle_start_arr(dl
, tb
);
2898 pr_out_uint(dl
, "sb",
2899 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
2900 pr_out_uint(dl
, "size",
2901 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
2902 pr_out_uint(dl
, "ing_pools",
2903 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
2904 pr_out_uint(dl
, "eg_pools",
2905 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
2906 pr_out_uint(dl
, "ing_tcs",
2907 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
2908 pr_out_uint(dl
, "eg_tcs",
2909 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
2910 pr_out_handle_end(dl
);
2913 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2915 struct dl
*dl
= data
;
2916 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2917 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2919 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2920 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2921 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
2922 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
2923 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
2924 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
2925 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
2926 return MNL_CB_ERROR
;
2931 static int cmd_sb_show(struct dl
*dl
)
2933 struct nlmsghdr
*nlh
;
2934 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2937 if (dl_argc(dl
) == 0)
2938 flags
|= NLM_F_DUMP
;
2940 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
2942 if (dl_argc(dl
) > 0) {
2943 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
2948 pr_out_section_start(dl
, "sb");
2949 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
2950 pr_out_section_end(dl
);
2954 static const char *pool_type_name(uint8_t type
)
2957 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
2958 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
2959 default: return "<unknown type>";
2963 static const char *threshold_type_name(uint8_t type
)
2966 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
2967 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
2968 default: return "<unknown type>";
2972 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
2974 pr_out_handle_start_arr(dl
, tb
);
2975 pr_out_uint(dl
, "sb",
2976 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
2977 pr_out_uint(dl
, "pool",
2978 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
2979 pr_out_str(dl
, "type",
2980 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
2981 pr_out_uint(dl
, "size",
2982 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
2983 pr_out_str(dl
, "thtype",
2984 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
2985 if (tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
])
2986 pr_out_uint(dl
, "cell_size",
2987 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
]));
2988 pr_out_handle_end(dl
);
2991 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2993 struct dl
*dl
= data
;
2994 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2995 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2997 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2998 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2999 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3000 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
3001 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
3002 return MNL_CB_ERROR
;
3003 pr_out_sb_pool(dl
, tb
);
3007 static int cmd_sb_pool_show(struct dl
*dl
)
3009 struct nlmsghdr
*nlh
;
3010 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3013 if (dl_argc(dl
) == 0)
3014 flags
|= NLM_F_DUMP
;
3016 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
3018 if (dl_argc(dl
) > 0) {
3019 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
3025 pr_out_section_start(dl
, "pool");
3026 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
3027 pr_out_section_end(dl
);
3031 static int cmd_sb_pool_set(struct dl
*dl
)
3033 struct nlmsghdr
*nlh
;
3036 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
3037 NLM_F_REQUEST
| NLM_F_ACK
);
3039 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
3040 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
3044 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3047 static int cmd_sb_pool(struct dl
*dl
)
3049 if (dl_argv_match(dl
, "help")) {
3052 } else if (dl_argv_match(dl
, "show") ||
3053 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3055 return cmd_sb_pool_show(dl
);
3056 } else if (dl_argv_match(dl
, "set")) {
3058 return cmd_sb_pool_set(dl
);
3060 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3064 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
3066 pr_out_port_handle_start_arr(dl
, tb
, true);
3067 pr_out_uint(dl
, "sb",
3068 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3069 pr_out_uint(dl
, "pool",
3070 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3071 pr_out_uint(dl
, "threshold",
3072 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3073 pr_out_port_handle_end(dl
);
3076 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3078 struct dl
*dl
= data
;
3079 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3080 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3082 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3083 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3084 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3085 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3086 return MNL_CB_ERROR
;
3087 pr_out_sb_port_pool(dl
, tb
);
3091 static int cmd_sb_port_pool_show(struct dl
*dl
)
3093 struct nlmsghdr
*nlh
;
3094 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3097 if (dl_argc(dl
) == 0)
3098 flags
|= NLM_F_DUMP
;
3100 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3102 if (dl_argc(dl
) > 0) {
3103 err
= dl_argv_parse_put(nlh
, dl
,
3104 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
3110 pr_out_section_start(dl
, "port_pool");
3111 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
3112 pr_out_section_end(dl
);
3116 static int cmd_sb_port_pool_set(struct dl
*dl
)
3118 struct nlmsghdr
*nlh
;
3121 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
3122 NLM_F_REQUEST
| NLM_F_ACK
);
3124 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
3125 DL_OPT_SB_TH
, DL_OPT_SB
);
3129 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3132 static int cmd_sb_port_pool(struct dl
*dl
)
3134 if (dl_argv_match(dl
, "help")) {
3137 } else if (dl_argv_match(dl
, "show") ||
3138 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3140 return cmd_sb_port_pool_show(dl
);
3141 } else if (dl_argv_match(dl
, "set")) {
3143 return cmd_sb_port_pool_set(dl
);
3145 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3149 static int cmd_sb_port(struct dl
*dl
)
3151 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3154 } else if (dl_argv_match(dl
, "pool")) {
3156 return cmd_sb_port_pool(dl
);
3158 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3162 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
3164 pr_out_port_handle_start_arr(dl
, tb
, true);
3165 pr_out_uint(dl
, "sb",
3166 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3167 pr_out_uint(dl
, "tc",
3168 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
3169 pr_out_str(dl
, "type",
3170 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3171 pr_out_uint(dl
, "pool",
3172 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3173 pr_out_uint(dl
, "threshold",
3174 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3175 pr_out_port_handle_end(dl
);
3178 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3180 struct dl
*dl
= data
;
3181 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3182 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3184 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3185 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3186 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3187 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3188 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3189 return MNL_CB_ERROR
;
3190 pr_out_sb_tc_bind(dl
, tb
);
3194 static int cmd_sb_tc_bind_show(struct dl
*dl
)
3196 struct nlmsghdr
*nlh
;
3197 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3200 if (dl_argc(dl
) == 0)
3201 flags
|= NLM_F_DUMP
;
3203 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3205 if (dl_argc(dl
) > 0) {
3206 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3207 DL_OPT_SB_TYPE
, DL_OPT_SB
);
3212 pr_out_section_start(dl
, "tc_bind");
3213 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
3214 pr_out_section_end(dl
);
3218 static int cmd_sb_tc_bind_set(struct dl
*dl
)
3220 struct nlmsghdr
*nlh
;
3223 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
3224 NLM_F_REQUEST
| NLM_F_ACK
);
3226 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3227 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
3232 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3235 static int cmd_sb_tc_bind(struct dl
*dl
)
3237 if (dl_argv_match(dl
, "help")) {
3240 } else if (dl_argv_match(dl
, "show") ||
3241 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3243 return cmd_sb_tc_bind_show(dl
);
3244 } else if (dl_argv_match(dl
, "set")) {
3246 return cmd_sb_tc_bind_set(dl
);
3248 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3252 static int cmd_sb_tc(struct dl
*dl
)
3254 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3257 } else if (dl_argv_match(dl
, "bind")) {
3259 return cmd_sb_tc_bind(dl
);
3261 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3266 struct list_head list
;
3270 uint32_t bound_pool_index
;
3274 struct list_head list
;
3277 uint32_t port_index
;
3279 struct list_head pool_list
;
3280 struct list_head ing_tc_list
;
3281 struct list_head eg_tc_list
;
3287 struct list_head port_list
;
3290 static struct occ_item
*occ_item_alloc(void)
3292 return calloc(1, sizeof(struct occ_item
));
3295 static void occ_item_free(struct occ_item
*occ_item
)
3300 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
3302 struct occ_port
*occ_port
;
3304 occ_port
= calloc(1, sizeof(*occ_port
));
3307 occ_port
->port_index
= port_index
;
3308 INIT_LIST_HEAD(&occ_port
->pool_list
);
3309 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
3310 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
3314 static void occ_port_free(struct occ_port
*occ_port
)
3316 struct occ_item
*occ_item
, *tmp
;
3318 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
3319 occ_item_free(occ_item
);
3320 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
3321 occ_item_free(occ_item
);
3322 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
3323 occ_item_free(occ_item
);
3326 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
3328 struct occ_show
*occ_show
;
3330 occ_show
= calloc(1, sizeof(*occ_show
));
3334 INIT_LIST_HEAD(&occ_show
->port_list
);
3338 static void occ_show_free(struct occ_show
*occ_show
)
3340 struct occ_port
*occ_port
, *tmp
;
3342 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
3343 occ_port_free(occ_port
);
3346 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
3349 struct occ_port
*occ_port
;
3350 uint32_t port_index
;
3352 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
3354 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
3355 if (occ_port
->port_index
== port_index
)
3358 occ_port
= occ_port_alloc(port_index
);
3361 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
3365 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
3368 struct occ_item
*occ_item
;
3371 pr_out_sp(7, " %s:", label
);
3372 list_for_each_entry(occ_item
, list
, list
) {
3373 if ((i
- 1) % 4 == 0 && i
!= 1)
3376 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
3377 occ_item
->bound_pool_index
);
3379 pr_out_sp(7, "%2u:", occ_item
->index
);
3380 pr_out_sp(15, "%7u/%u", occ_item
->cur
, occ_item
->max
);
3384 if ((i
- 1) % 4 != 0)
3388 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
3389 struct list_head
*list
,
3392 struct occ_item
*occ_item
;
3395 jsonw_name(dl
->jw
, label
);
3396 jsonw_start_object(dl
->jw
);
3397 list_for_each_entry(occ_item
, list
, list
) {
3398 sprintf(buf
, "%u", occ_item
->index
);
3399 jsonw_name(dl
->jw
, buf
);
3400 jsonw_start_object(dl
->jw
);
3402 jsonw_uint_field(dl
->jw
, "bound_pool",
3403 occ_item
->bound_pool_index
);
3404 jsonw_uint_field(dl
->jw
, "current", occ_item
->cur
);
3405 jsonw_uint_field(dl
->jw
, "max", occ_item
->max
);
3406 jsonw_end_object(dl
->jw
);
3408 jsonw_end_object(dl
->jw
);
3411 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
3413 if (dl
->json_output
) {
3414 pr_out_json_occ_show_item_list(dl
, "pool",
3415 &occ_port
->pool_list
, false);
3416 pr_out_json_occ_show_item_list(dl
, "itc",
3417 &occ_port
->ing_tc_list
, true);
3418 pr_out_json_occ_show_item_list(dl
, "etc",
3419 &occ_port
->eg_tc_list
, true);
3422 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
3423 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
3424 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
3428 static void pr_out_occ_show(struct occ_show
*occ_show
)
3430 struct dl
*dl
= occ_show
->dl
;
3431 struct dl_opts
*opts
= &dl
->opts
;
3432 struct occ_port
*occ_port
;
3434 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
3435 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
3436 occ_port
->port_index
, true, false);
3437 pr_out_occ_show_port(dl
, occ_port
);
3438 pr_out_port_handle_end(dl
);
3442 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
3445 struct occ_port
*occ_port
;
3446 struct occ_item
*occ_item
;
3448 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
3451 occ_port
= occ_port_get(occ_show
, tb
);
3453 occ_show
->err
= -ENOMEM
;
3457 occ_item
= occ_item_alloc();
3459 occ_show
->err
= -ENOMEM
;
3462 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
3463 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
3464 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
3465 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
3468 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
3470 struct occ_show
*occ_show
= data
;
3471 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3472 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3474 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3475 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3476 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3477 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3478 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
3479 return MNL_CB_ERROR
;
3480 cmd_sb_occ_port_pool_process(occ_show
, tb
);
3484 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
3487 struct occ_port
*occ_port
;
3488 struct occ_item
*occ_item
;
3491 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
3494 occ_port
= occ_port_get(occ_show
, tb
);
3496 occ_show
->err
= -ENOMEM
;
3500 occ_item
= occ_item_alloc();
3502 occ_show
->err
= -ENOMEM
;
3505 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
3506 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
3507 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
3508 occ_item
->bound_pool_index
=
3509 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
3510 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
3511 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
3512 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
3513 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
3514 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
3516 occ_item_free(occ_item
);
3519 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
3521 struct occ_show
*occ_show
= data
;
3522 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3523 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3525 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3526 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3527 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3528 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3529 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3530 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
3531 return MNL_CB_ERROR
;
3532 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
3536 static int cmd_sb_occ_show(struct dl
*dl
)
3538 struct nlmsghdr
*nlh
;
3539 struct occ_show
*occ_show
;
3540 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
3543 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
3547 occ_show
= occ_show_alloc(dl
);
3551 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3553 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
3554 cmd_sb_occ_port_pool_process_cb
, occ_show
);
3558 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3560 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
3561 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
3565 pr_out_section_start(dl
, "occupancy");
3566 pr_out_occ_show(occ_show
);
3567 pr_out_section_end(dl
);
3570 occ_show_free(occ_show
);
3574 static int cmd_sb_occ_snapshot(struct dl
*dl
)
3576 struct nlmsghdr
*nlh
;
3579 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
3580 NLM_F_REQUEST
| NLM_F_ACK
);
3582 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3586 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3589 static int cmd_sb_occ_clearmax(struct dl
*dl
)
3591 struct nlmsghdr
*nlh
;
3594 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
3595 NLM_F_REQUEST
| NLM_F_ACK
);
3597 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3601 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3604 static int cmd_sb_occ(struct dl
*dl
)
3606 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3609 } else if (dl_argv_match(dl
, "show") ||
3610 dl_argv_match(dl
, "list")) {
3612 return cmd_sb_occ_show(dl
);
3613 } else if (dl_argv_match(dl
, "snapshot")) {
3615 return cmd_sb_occ_snapshot(dl
);
3616 } else if (dl_argv_match(dl
, "clearmax")) {
3618 return cmd_sb_occ_clearmax(dl
);
3620 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3624 static int cmd_sb(struct dl
*dl
)
3626 if (dl_argv_match(dl
, "help")) {
3629 } else if (dl_argv_match(dl
, "show") ||
3630 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3632 return cmd_sb_show(dl
);
3633 } else if (dl_argv_match(dl
, "pool")) {
3635 return cmd_sb_pool(dl
);
3636 } else if (dl_argv_match(dl
, "port")) {
3638 return cmd_sb_port(dl
);
3639 } else if (dl_argv_match(dl
, "tc")) {
3641 return cmd_sb_tc(dl
);
3642 } else if (dl_argv_match(dl
, "occupancy")) {
3644 return cmd_sb_occ(dl
);
3646 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3650 static const char *cmd_name(uint8_t cmd
)
3653 case DEVLINK_CMD_UNSPEC
: return "unspec";
3654 case DEVLINK_CMD_GET
: return "get";
3655 case DEVLINK_CMD_SET
: return "set";
3656 case DEVLINK_CMD_NEW
: return "new";
3657 case DEVLINK_CMD_DEL
: return "del";
3658 case DEVLINK_CMD_PORT_GET
: return "get";
3659 case DEVLINK_CMD_PORT_SET
: return "set";
3660 case DEVLINK_CMD_PORT_NEW
: return "new";
3661 case DEVLINK_CMD_PORT_DEL
: return "del";
3662 case DEVLINK_CMD_PARAM_GET
: return "get";
3663 case DEVLINK_CMD_PARAM_SET
: return "set";
3664 case DEVLINK_CMD_PARAM_NEW
: return "new";
3665 case DEVLINK_CMD_PARAM_DEL
: return "del";
3666 case DEVLINK_CMD_REGION_GET
: return "get";
3667 case DEVLINK_CMD_REGION_SET
: return "set";
3668 case DEVLINK_CMD_REGION_NEW
: return "new";
3669 case DEVLINK_CMD_REGION_DEL
: return "del";
3670 default: return "<unknown cmd>";
3674 static const char *cmd_obj(uint8_t cmd
)
3677 case DEVLINK_CMD_UNSPEC
: return "unspec";
3678 case DEVLINK_CMD_GET
:
3679 case DEVLINK_CMD_SET
:
3680 case DEVLINK_CMD_NEW
:
3681 case DEVLINK_CMD_DEL
:
3683 case DEVLINK_CMD_PORT_GET
:
3684 case DEVLINK_CMD_PORT_SET
:
3685 case DEVLINK_CMD_PORT_NEW
:
3686 case DEVLINK_CMD_PORT_DEL
:
3688 case DEVLINK_CMD_PARAM_GET
:
3689 case DEVLINK_CMD_PARAM_SET
:
3690 case DEVLINK_CMD_PARAM_NEW
:
3691 case DEVLINK_CMD_PARAM_DEL
:
3693 case DEVLINK_CMD_REGION_GET
:
3694 case DEVLINK_CMD_REGION_SET
:
3695 case DEVLINK_CMD_REGION_NEW
:
3696 case DEVLINK_CMD_REGION_DEL
:
3698 default: return "<unknown obj>";
3702 static void pr_out_mon_header(uint8_t cmd
)
3704 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
3707 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
3709 const char *obj
= cmd_obj(cmd
);
3710 unsigned int index
= 0;
3711 const char *cur_obj
;
3715 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
3716 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
3722 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
);
3724 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3726 struct dl
*dl
= data
;
3727 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3728 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3729 uint8_t cmd
= genl
->cmd
;
3731 if (!cmd_filter_check(dl
, cmd
))
3735 case DEVLINK_CMD_GET
: /* fall through */
3736 case DEVLINK_CMD_SET
: /* fall through */
3737 case DEVLINK_CMD_NEW
: /* fall through */
3738 case DEVLINK_CMD_DEL
:
3739 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3740 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
3741 return MNL_CB_ERROR
;
3742 pr_out_mon_header(genl
->cmd
);
3745 case DEVLINK_CMD_PORT_GET
: /* fall through */
3746 case DEVLINK_CMD_PORT_SET
: /* fall through */
3747 case DEVLINK_CMD_PORT_NEW
: /* fall through */
3748 case DEVLINK_CMD_PORT_DEL
:
3749 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3750 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3751 !tb
[DEVLINK_ATTR_PORT_INDEX
])
3752 return MNL_CB_ERROR
;
3753 pr_out_mon_header(genl
->cmd
);
3754 pr_out_port(dl
, tb
);
3756 case DEVLINK_CMD_PARAM_GET
: /* fall through */
3757 case DEVLINK_CMD_PARAM_SET
: /* fall through */
3758 case DEVLINK_CMD_PARAM_NEW
: /* fall through */
3759 case DEVLINK_CMD_PARAM_DEL
:
3760 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3761 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3762 !tb
[DEVLINK_ATTR_PARAM
])
3763 return MNL_CB_ERROR
;
3764 pr_out_mon_header(genl
->cmd
);
3765 pr_out_param(dl
, tb
, false);
3767 case DEVLINK_CMD_REGION_GET
: /* fall through */
3768 case DEVLINK_CMD_REGION_SET
: /* fall through */
3769 case DEVLINK_CMD_REGION_NEW
: /* fall through */
3770 case DEVLINK_CMD_REGION_DEL
:
3771 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3772 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3773 !tb
[DEVLINK_ATTR_REGION_NAME
])
3774 return MNL_CB_ERROR
;
3775 pr_out_mon_header(genl
->cmd
);
3776 pr_out_region(dl
, tb
);
3782 static int cmd_mon_show(struct dl
*dl
)
3785 unsigned int index
= 0;
3786 const char *cur_obj
;
3788 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
3789 if (strcmp(cur_obj
, "all") != 0 &&
3790 strcmp(cur_obj
, "dev") != 0 &&
3791 strcmp(cur_obj
, "port") != 0) {
3792 pr_err("Unknown object \"%s\"\n", cur_obj
);
3796 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
3799 err
= _mnlg_socket_recv_run(dl
->nlg
, cmd_mon_show_cb
, dl
);
3805 static void cmd_mon_help(void)
3807 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
3808 "where OBJECT-LIST := { dev | port }\n");
3811 static int cmd_mon(struct dl
*dl
)
3813 if (dl_argv_match(dl
, "help")) {
3816 } else if (dl_no_arg(dl
)) {
3818 return cmd_mon_show(dl
);
3820 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3824 struct dpipe_field
{
3827 unsigned int bitwidth
;
3828 enum devlink_dpipe_field_mapping_type mapping_type
;
3831 struct dpipe_header
{
3832 struct list_head list
;
3835 struct dpipe_field
*fields
;
3836 unsigned int fields_count
;
3839 struct dpipe_table
{
3840 struct list_head list
;
3842 unsigned int resource_id
;
3843 bool resource_valid
;
3846 struct dpipe_tables
{
3847 struct list_head table_list
;
3857 enum devlink_resource_unit unit
;
3862 struct list_head list
;
3863 struct list_head resource_list
;
3864 struct resource
*parent
;
3868 struct list_head resource_list
;
3871 struct resource_ctx
{
3874 struct resources
*resources
;
3875 struct dpipe_tables
*tables
;
3876 bool print_resources
;
3877 bool pending_change
;
3880 static struct resource
*resource_alloc(void)
3882 struct resource
*resource
;
3884 resource
= calloc(1, sizeof(struct resource
));
3887 INIT_LIST_HEAD(&resource
->resource_list
);
3891 static void resource_free(struct resource
*resource
)
3893 struct resource
*child_resource
, *tmp
;
3895 list_for_each_entry_safe(child_resource
, tmp
, &resource
->resource_list
,
3897 free(child_resource
->name
);
3898 resource_free(child_resource
);
3903 static struct resources
*resources_alloc(void)
3905 struct resources
*resources
;
3907 resources
= calloc(1, sizeof(struct resources
));
3910 INIT_LIST_HEAD(&resources
->resource_list
);
3914 static void resources_free(struct resources
*resources
)
3916 struct resource
*resource
, *tmp
;
3918 list_for_each_entry_safe(resource
, tmp
, &resources
->resource_list
, list
)
3919 resource_free(resource
);
3922 static int resource_ctx_init(struct resource_ctx
*ctx
, struct dl
*dl
)
3924 ctx
->resources
= resources_alloc();
3925 if (!ctx
->resources
)
3931 static void resource_ctx_fini(struct resource_ctx
*ctx
)
3933 resources_free(ctx
->resources
);
3939 struct list_head global_headers
;
3940 struct list_head local_headers
;
3941 struct dpipe_tables
*tables
;
3942 struct resources
*resources
;
3947 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
3949 struct dpipe_header
*header
;
3951 header
= calloc(1, sizeof(struct dpipe_header
));
3954 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
3955 if (!header
->fields
)
3956 goto err_fields_alloc
;
3957 header
->fields_count
= fields_count
;
3965 static void dpipe_header_free(struct dpipe_header
*header
)
3967 free(header
->fields
);
3971 static void dpipe_header_clear(struct dpipe_header
*header
)
3973 struct dpipe_field
*field
;
3976 for (i
= 0; i
< header
->fields_count
; i
++) {
3977 field
= &header
->fields
[i
];
3983 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
3984 struct dpipe_header
*header
, bool global
)
3987 list_add(&header
->list
, &ctx
->global_headers
);
3989 list_add(&header
->list
, &ctx
->local_headers
);
3992 static void dpipe_header_del(struct dpipe_header
*header
)
3994 list_del(&header
->list
);
3997 static struct dpipe_table
*dpipe_table_alloc(void)
3999 return calloc(1, sizeof(struct dpipe_table
));
4002 static void dpipe_table_free(struct dpipe_table
*table
)
4007 static struct dpipe_tables
*dpipe_tables_alloc(void)
4009 struct dpipe_tables
*tables
;
4011 tables
= calloc(1, sizeof(struct dpipe_tables
));
4014 INIT_LIST_HEAD(&tables
->table_list
);
4018 static void dpipe_tables_free(struct dpipe_tables
*tables
)
4020 struct dpipe_table
*table
, *tmp
;
4022 list_for_each_entry_safe(table
, tmp
, &tables
->table_list
, list
)
4023 dpipe_table_free(table
);
4027 static int dpipe_ctx_init(struct dpipe_ctx
*ctx
, struct dl
*dl
)
4029 ctx
->tables
= dpipe_tables_alloc();
4034 INIT_LIST_HEAD(&ctx
->global_headers
);
4035 INIT_LIST_HEAD(&ctx
->local_headers
);
4039 static void dpipe_ctx_fini(struct dpipe_ctx
*ctx
)
4041 struct dpipe_header
*header
, *tmp
;
4043 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
4045 dpipe_header_del(header
);
4046 dpipe_header_clear(header
);
4047 dpipe_header_free(header
);
4049 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
4051 dpipe_header_del(header
);
4052 dpipe_header_clear(header
);
4053 dpipe_header_free(header
);
4055 dpipe_tables_free(ctx
->tables
);
4058 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
4059 uint32_t header_id
, bool global
)
4061 struct list_head
*header_list
;
4062 struct dpipe_header
*header
;
4065 header_list
= &ctx
->global_headers
;
4067 header_list
= &ctx
->local_headers
;
4068 list_for_each_entry(header
, header_list
, list
) {
4069 if (header
->id
!= header_id
)
4071 return header
->name
;
4076 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
4078 uint32_t field_id
, bool global
)
4080 struct list_head
*header_list
;
4081 struct dpipe_header
*header
;
4084 header_list
= &ctx
->global_headers
;
4086 header_list
= &ctx
->local_headers
;
4087 list_for_each_entry(header
, header_list
, list
) {
4088 if (header
->id
!= header_id
)
4090 return header
->fields
[field_id
].name
;
4096 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
4098 switch (mapping_type
) {
4099 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
4101 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
4109 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
4110 uint32_t field_id
, bool global
)
4112 enum devlink_dpipe_field_mapping_type mapping_type
;
4113 struct list_head
*header_list
;
4114 struct dpipe_header
*header
;
4117 header_list
= &ctx
->global_headers
;
4119 header_list
= &ctx
->local_headers
;
4120 list_for_each_entry(header
, header_list
, list
) {
4121 if (header
->id
!= header_id
)
4123 mapping_type
= header
->fields
[field_id
].mapping_type
;
4124 return dpipe_field_mapping_e2s(mapping_type
);
4129 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
4130 struct dpipe_field
*fields
,
4131 unsigned int field_count
)
4133 struct dpipe_field
*field
;
4136 for (i
= 0; i
< field_count
; i
++) {
4138 pr_out_entry_start(ctx
->dl
);
4139 pr_out_str(ctx
->dl
, "name", field
->name
);
4140 if (ctx
->dl
->verbose
)
4141 pr_out_uint(ctx
->dl
, "id", field
->id
);
4142 pr_out_uint(ctx
->dl
, "bitwidth", field
->bitwidth
);
4143 if (field
->mapping_type
)
4144 pr_out_str(ctx
->dl
, "mapping_type",
4145 dpipe_field_mapping_e2s(field
->mapping_type
));
4146 pr_out_entry_end(ctx
->dl
);
4151 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
4152 struct dpipe_header
*header
, bool global
)
4154 pr_out_handle_start_arr(ctx
->dl
, tb
);
4155 pr_out_str(ctx
->dl
, "name", header
->name
);
4156 if (ctx
->dl
->verbose
) {
4157 pr_out_uint(ctx
->dl
, "id", header
->id
);
4158 pr_out_str(ctx
->dl
, "global",
4159 global
? "true" : "false");
4161 pr_out_array_start(ctx
->dl
, "field");
4162 pr_out_dpipe_fields(ctx
, header
->fields
,
4163 header
->fields_count
);
4164 pr_out_array_end(ctx
->dl
);
4165 pr_out_handle_end(ctx
->dl
);
4168 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
4171 struct dpipe_header
*header
;
4173 list_for_each_entry(header
, &ctx
->local_headers
, list
)
4174 pr_out_dpipe_header(ctx
, tb
, header
, false);
4176 list_for_each_entry(header
, &ctx
->global_headers
, list
)
4177 pr_out_dpipe_header(ctx
, tb
, header
, true);
4180 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
4182 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
4186 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
4187 if (err
!= MNL_CB_OK
)
4189 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
4190 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
4191 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
4192 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
4195 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
4196 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4197 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
4198 field
->name
= strdup(name
);
4201 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
4205 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
4206 struct dpipe_field
*fields
)
4208 struct nlattr
*nla_field
;
4212 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
4213 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
4221 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
4223 struct nlattr
*nla_field
;
4224 unsigned int count
= 0;
4226 mnl_attr_for_each_nested(nla_field
, nla_fields
)
4231 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
4233 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
4234 struct dpipe_header
*header
;
4235 unsigned int fields_count
;
4236 const char *header_name
;
4240 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
4241 if (err
!= MNL_CB_OK
)
4244 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
4245 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4246 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
4249 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
4250 header
= dpipe_header_alloc(fields_count
);
4254 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
4255 header
->name
= strdup(header_name
);
4256 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4257 header
->fields_count
= fields_count
;
4258 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4260 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
4264 dpipe_header_add(ctx
, header
, global
);
4268 dpipe_header_free(header
);
4272 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
4274 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
4275 struct nlattr
*nla_header
;
4278 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
4279 err
= dpipe_header_get(ctx
, nla_header
);
4286 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
4288 struct dpipe_ctx
*ctx
= data
;
4289 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4290 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4293 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4294 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4295 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
4296 return MNL_CB_ERROR
;
4297 err
= dpipe_headers_get(ctx
, tb
);
4300 return MNL_CB_ERROR
;
4303 if (ctx
->print_headers
)
4304 pr_out_dpipe_headers(ctx
, tb
);
4308 static int cmd_dpipe_headers_show(struct dl
*dl
)
4310 struct nlmsghdr
*nlh
;
4311 struct dpipe_ctx ctx
= {};
4312 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
4315 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
4317 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
4321 err
= dpipe_ctx_init(&ctx
, dl
);
4325 ctx
.print_headers
= true;
4327 pr_out_section_start(dl
, "header");
4328 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
4330 pr_err("error get headers %s\n", strerror(ctx
.err
));
4331 pr_out_section_end(dl
);
4333 dpipe_ctx_fini(&ctx
);
4337 static void cmd_dpipe_header_help(void)
4339 pr_err("Usage: devlink dpipe headers show DEV\n");
4342 static int cmd_dpipe_header(struct dl
*dl
)
4344 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4345 cmd_dpipe_header_help();
4347 } else if (dl_argv_match(dl
, "show")) {
4349 return cmd_dpipe_headers_show(dl
);
4351 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4356 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
4358 switch (action_type
) {
4359 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
4360 return "field_modify";
4366 struct dpipe_op_info
{
4372 struct dpipe_action
{
4373 struct dpipe_op_info info
;
4377 static void pr_out_dpipe_action(struct dpipe_action
*action
,
4378 struct dpipe_ctx
*ctx
)
4380 struct dpipe_op_info
*op_info
= &action
->info
;
4381 const char *mapping
;
4383 pr_out_str(ctx
->dl
, "type",
4384 dpipe_action_type_e2s(action
->type
));
4385 pr_out_str(ctx
->dl
, "header",
4386 dpipe_header_id2s(ctx
, op_info
->header_id
,
4387 op_info
->header_global
));
4388 pr_out_str(ctx
->dl
, "field",
4389 dpipe_field_id2s(ctx
, op_info
->header_id
,
4391 op_info
->header_global
));
4392 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
4394 op_info
->header_global
);
4396 pr_out_str(ctx
->dl
, "mapping", mapping
);
4399 static int dpipe_action_parse(struct dpipe_action
*action
, struct nlattr
*nl
)
4401 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
4404 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
4405 if (err
!= MNL_CB_OK
)
4408 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
4409 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
4410 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4411 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
4415 action
->type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
4416 action
->info
.header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4417 action
->info
.field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4418 action
->info
.header_global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4423 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
4424 struct nlattr
*nla_actions
)
4426 struct nlattr
*nla_action
;
4427 struct dpipe_action action
;
4429 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
4430 pr_out_entry_start(ctx
->dl
);
4431 if (dpipe_action_parse(&action
, nla_action
))
4432 goto err_action_parse
;
4433 pr_out_dpipe_action(&action
, ctx
);
4434 pr_out_entry_end(ctx
->dl
);
4439 pr_out_entry_end(ctx
->dl
);
4444 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
4446 switch (match_type
) {
4447 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
4448 return "field_exact";
4454 struct dpipe_match
{
4455 struct dpipe_op_info info
;
4459 static void pr_out_dpipe_match(struct dpipe_match
*match
,
4460 struct dpipe_ctx
*ctx
)
4462 struct dpipe_op_info
*op_info
= &match
->info
;
4463 const char *mapping
;
4465 pr_out_str(ctx
->dl
, "type",
4466 dpipe_match_type_e2s(match
->type
));
4467 pr_out_str(ctx
->dl
, "header",
4468 dpipe_header_id2s(ctx
, op_info
->header_id
,
4469 op_info
->header_global
));
4470 pr_out_str(ctx
->dl
, "field",
4471 dpipe_field_id2s(ctx
, op_info
->header_id
,
4473 op_info
->header_global
));
4474 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
4476 op_info
->header_global
);
4478 pr_out_str(ctx
->dl
, "mapping", mapping
);
4481 static int dpipe_match_parse(struct dpipe_match
*match
,
4485 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
4488 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
4489 if (err
!= MNL_CB_OK
)
4492 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
4493 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
4494 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4495 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
4499 match
->type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
4500 match
->info
.header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4501 match
->info
.field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4502 match
->info
.header_global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4507 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
4508 struct nlattr
*nla_matches
)
4510 struct nlattr
*nla_match
;
4511 struct dpipe_match match
;
4513 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
4514 pr_out_entry_start(ctx
->dl
);
4515 if (dpipe_match_parse(&match
, nla_match
))
4516 goto err_match_parse
;
4517 pr_out_dpipe_match(&match
, ctx
);
4518 pr_out_entry_end(ctx
->dl
);
4523 pr_out_entry_end(ctx
->dl
);
4527 static struct resource
*
4528 resource_find(struct resources
*resources
, struct resource
*resource
,
4529 uint64_t resource_id
)
4531 struct list_head
*list_head
;
4534 list_head
= &resources
->resource_list
;
4536 list_head
= &resource
->resource_list
;
4538 list_for_each_entry(resource
, list_head
, list
) {
4539 struct resource
*child_resource
;
4541 if (resource
->id
== resource_id
)
4544 child_resource
= resource_find(resources
, resource
,
4547 return child_resource
;
4553 resource_path_print(struct dl
*dl
, struct resources
*resources
,
4554 uint64_t resource_id
)
4556 struct resource
*resource
, *parent_resource
;
4557 const char del
[] = "/";
4561 resource
= resource_find(resources
, NULL
, resource_id
);
4565 for (parent_resource
= resource
; parent_resource
;
4566 parent_resource
= parent_resource
->parent
)
4567 path_len
+= strlen(parent_resource
->name
) + 1;
4570 path
= calloc(1, path_len
);
4574 path
+= path_len
- 1;
4575 for (parent_resource
= resource
; parent_resource
;
4576 parent_resource
= parent_resource
->parent
) {
4577 path
-= strlen(parent_resource
->name
);
4578 memcpy(path
, parent_resource
->name
,
4579 strlen(parent_resource
->name
));
4580 path
-= strlen(del
);
4581 memcpy(path
, del
, strlen(del
));
4583 pr_out_str(dl
, "resource_path", path
);
4587 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
4589 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
4590 struct dpipe_table
*table
;
4591 uint32_t resource_units
;
4592 bool counters_enabled
;
4593 bool resource_valid
;
4597 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
4598 if (err
!= MNL_CB_OK
)
4601 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
4602 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
4603 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
4604 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
4605 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
4609 table
= dpipe_table_alloc();
4613 table
->name
= strdup(mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]));
4614 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
4615 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
4617 resource_valid
= nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
] &&
4619 if (resource_valid
) {
4620 table
->resource_id
= mnl_attr_get_u64(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
]);
4621 table
->resource_valid
= true;
4624 list_add_tail(&table
->list
, &ctx
->tables
->table_list
);
4625 if (!ctx
->print_tables
)
4628 pr_out_str(ctx
->dl
, "name", table
->name
);
4629 pr_out_uint(ctx
->dl
, "size", size
);
4630 pr_out_str(ctx
->dl
, "counters_enabled",
4631 counters_enabled
? "true" : "false");
4633 if (resource_valid
) {
4634 resource_units
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS
]);
4635 resource_path_print(ctx
->dl
, ctx
->resources
,
4636 table
->resource_id
);
4637 pr_out_uint(ctx
->dl
, "resource_units", resource_units
);
4640 pr_out_array_start(ctx
->dl
, "match");
4641 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
4642 goto err_matches_show
;
4643 pr_out_array_end(ctx
->dl
);
4645 pr_out_array_start(ctx
->dl
, "action");
4646 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
4647 goto err_actions_show
;
4648 pr_out_array_end(ctx
->dl
);
4654 pr_out_array_end(ctx
->dl
);
4658 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
4660 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
4661 struct nlattr
*nla_table
;
4663 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
4664 if (ctx
->print_tables
)
4665 pr_out_handle_start_arr(ctx
->dl
, tb
);
4666 if (dpipe_table_show(ctx
, nla_table
))
4667 goto err_table_show
;
4668 if (ctx
->print_tables
)
4669 pr_out_handle_end(ctx
->dl
);
4674 if (ctx
->print_tables
)
4675 pr_out_handle_end(ctx
->dl
);
4679 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
4681 struct dpipe_ctx
*ctx
= data
;
4682 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4683 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4685 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4686 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4687 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
4688 return MNL_CB_ERROR
;
4690 if (dpipe_tables_show(ctx
, tb
))
4691 return MNL_CB_ERROR
;
4695 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
);
4697 static int cmd_dpipe_table_show(struct dl
*dl
)
4699 struct nlmsghdr
*nlh
;
4700 struct dpipe_ctx dpipe_ctx
= {};
4701 struct resource_ctx resource_ctx
= {};
4702 uint16_t flags
= NLM_F_REQUEST
;
4705 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
4709 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
4711 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
4715 dpipe_ctx
.print_tables
= true;
4717 dl_opts_put(nlh
, dl
);
4718 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
,
4721 pr_err("error get headers %s\n", strerror(dpipe_ctx
.err
));
4722 goto err_headers_get
;
4725 err
= resource_ctx_init(&resource_ctx
, dl
);
4727 goto err_resource_ctx_init
;
4729 resource_ctx
.print_resources
= false;
4730 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
, flags
);
4731 dl_opts_put(nlh
, dl
);
4732 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
4735 dpipe_ctx
.resources
= resource_ctx
.resources
;
4737 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
4738 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
4739 dl_opts_put(nlh
, dl
);
4741 pr_out_section_start(dl
, "table");
4742 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, &dpipe_ctx
);
4743 pr_out_section_end(dl
);
4745 resource_ctx_fini(&resource_ctx
);
4746 dpipe_ctx_fini(&dpipe_ctx
);
4749 err_resource_ctx_init
:
4751 dpipe_ctx_fini(&dpipe_ctx
);
4755 static int cmd_dpipe_table_set(struct dl
*dl
)
4757 struct nlmsghdr
*nlh
;
4760 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
4761 NLM_F_REQUEST
| NLM_F_ACK
);
4763 err
= dl_argv_parse_put(nlh
, dl
,
4764 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
4765 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
4769 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4772 enum dpipe_value_type
{
4773 DPIPE_VALUE_TYPE_VALUE
,
4774 DPIPE_VALUE_TYPE_MASK
,
4778 dpipe_value_type_e2s(enum dpipe_value_type type
)
4781 case DPIPE_VALUE_TYPE_VALUE
:
4783 case DPIPE_VALUE_TYPE_MASK
:
4784 return "value_mask";
4790 struct dpipe_field_printer
{
4791 unsigned int field_id
;
4792 void (*printer
)(struct dpipe_ctx
*, enum dpipe_value_type
, void *);
4795 struct dpipe_header_printer
{
4796 struct dpipe_field_printer
*printers
;
4797 unsigned int printers_count
;
4798 unsigned int header_id
;
4801 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx
*ctx
,
4802 enum dpipe_value_type type
,
4805 struct in_addr ip_addr
;
4807 ip_addr
.s_addr
= htonl(*(uint32_t *)value
);
4808 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
), inet_ntoa(ip_addr
));
4812 dpipe_field_printer_ethernet_addr(struct dpipe_ctx
*ctx
,
4813 enum dpipe_value_type type
,
4816 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
),
4817 ether_ntoa((struct ether_addr
*)value
));
4820 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx
*ctx
,
4821 enum dpipe_value_type type
,
4824 char str
[INET6_ADDRSTRLEN
];
4826 inet_ntop(AF_INET6
, value
, str
, INET6_ADDRSTRLEN
);
4827 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
), str
);
4830 static struct dpipe_field_printer dpipe_field_printers_ipv4
[] = {
4832 .printer
= dpipe_field_printer_ipv4_addr
,
4833 .field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
,
4837 static struct dpipe_header_printer dpipe_header_printer_ipv4
= {
4838 .printers
= dpipe_field_printers_ipv4
,
4839 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv4
),
4840 .header_id
= DEVLINK_DPIPE_HEADER_IPV4
,
4843 static struct dpipe_field_printer dpipe_field_printers_ethernet
[] = {
4845 .printer
= dpipe_field_printer_ethernet_addr
,
4846 .field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
,
4850 static struct dpipe_header_printer dpipe_header_printer_ethernet
= {
4851 .printers
= dpipe_field_printers_ethernet
,
4852 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ethernet
),
4853 .header_id
= DEVLINK_DPIPE_HEADER_ETHERNET
,
4856 static struct dpipe_field_printer dpipe_field_printers_ipv6
[] = {
4858 .printer
= dpipe_field_printer_ipv6_addr
,
4859 .field_id
= DEVLINK_DPIPE_FIELD_IPV6_DST_IP
,
4863 static struct dpipe_header_printer dpipe_header_printer_ipv6
= {
4864 .printers
= dpipe_field_printers_ipv6
,
4865 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv6
),
4866 .header_id
= DEVLINK_DPIPE_HEADER_IPV6
,
4869 static struct dpipe_header_printer
*dpipe_header_printers
[] = {
4870 &dpipe_header_printer_ipv4
,
4871 &dpipe_header_printer_ethernet
,
4872 &dpipe_header_printer_ipv6
,
4875 static int dpipe_print_prot_header(struct dpipe_ctx
*ctx
,
4876 struct dpipe_op_info
*info
,
4877 enum dpipe_value_type type
,
4880 unsigned int header_printers_count
= ARRAY_SIZE(dpipe_header_printers
);
4881 struct dpipe_header_printer
*header_printer
;
4882 struct dpipe_field_printer
*field_printer
;
4883 unsigned int field_printers_count
;
4887 for (i
= 0; i
< header_printers_count
; i
++) {
4888 header_printer
= dpipe_header_printers
[i
];
4889 if (header_printer
->header_id
!= info
->header_id
)
4891 field_printers_count
= header_printer
->printers_count
;
4892 for (j
= 0; j
< field_printers_count
; j
++) {
4893 field_printer
= &header_printer
->printers
[j
];
4894 if (field_printer
->field_id
!= info
->field_id
)
4896 field_printer
->printer(ctx
, type
, value
);
4904 static void __pr_out_entry_value(struct dpipe_ctx
*ctx
,
4906 unsigned int value_len
,
4907 struct dpipe_op_info
*info
,
4908 enum dpipe_value_type type
)
4910 if (info
->header_global
&&
4911 !dpipe_print_prot_header(ctx
, info
, type
, value
))
4914 if (value_len
== sizeof(uint32_t)) {
4915 uint32_t *value_32
= value
;
4917 pr_out_uint(ctx
->dl
, dpipe_value_type_e2s(type
), *value_32
);
4921 static void pr_out_dpipe_entry_value(struct dpipe_ctx
*ctx
,
4922 struct nlattr
**nla_match_value
,
4923 struct dpipe_op_info
*info
)
4925 void *value
, *value_mask
;
4926 uint32_t value_mapping
;
4930 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
4931 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
4933 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
4934 value
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
4937 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
4938 pr_out_uint(ctx
->dl
, "mapping_value", value_mapping
);
4942 value_mask
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
4943 __pr_out_entry_value(ctx
, value_mask
, value_len
, info
,
4944 DPIPE_VALUE_TYPE_MASK
);
4947 __pr_out_entry_value(ctx
, value
, value_len
, info
, DPIPE_VALUE_TYPE_VALUE
);
4950 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
4953 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
4954 struct dpipe_match match
;
4957 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
4958 if (err
!= MNL_CB_OK
)
4961 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
4962 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
4966 pr_out_entry_start(ctx
->dl
);
4967 if (dpipe_match_parse(&match
,
4968 nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
4969 goto err_match_parse
;
4970 pr_out_dpipe_match(&match
, ctx
);
4971 pr_out_dpipe_entry_value(ctx
, nla_match_value
, &match
.info
);
4972 pr_out_entry_end(ctx
->dl
);
4977 pr_out_entry_end(ctx
->dl
);
4981 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
4984 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
4985 struct dpipe_action action
;
4988 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
4989 if (err
!= MNL_CB_OK
)
4992 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
4993 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
4997 pr_out_entry_start(ctx
->dl
);
4998 if (dpipe_action_parse(&action
,
4999 nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
5000 goto err_action_parse
;
5001 pr_out_dpipe_action(&action
, ctx
);
5002 pr_out_dpipe_entry_value(ctx
, nla_action_value
, &action
.info
);
5003 pr_out_entry_end(ctx
->dl
);
5008 pr_out_entry_end(ctx
->dl
);
5013 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
5014 struct nlattr
*nla_action_values
)
5016 struct nlattr
*nla_action_value
;
5018 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
5019 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
5026 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
5027 struct nlattr
*nla_match_values
)
5029 struct nlattr
*nla_match_value
;
5031 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
5032 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
5038 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5040 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
5041 uint32_t entry_index
;
5045 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
5046 if (err
!= MNL_CB_OK
)
5049 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
5050 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
5051 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
5055 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
5056 pr_out_uint(ctx
->dl
, "index", entry_index
);
5058 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
5059 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
5060 pr_out_uint(ctx
->dl
, "counter", counter
);
5063 pr_out_array_start(ctx
->dl
, "match_value");
5064 if (dpipe_tables_match_values_show(ctx
,
5065 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
5066 goto err_match_values_show
;
5067 pr_out_array_end(ctx
->dl
);
5069 pr_out_array_start(ctx
->dl
, "action_value");
5070 if (dpipe_tables_action_values_show(ctx
,
5071 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
5072 goto err_action_values_show
;
5073 pr_out_array_end(ctx
->dl
);
5076 err_action_values_show
:
5077 err_match_values_show
:
5078 pr_out_array_end(ctx
->dl
);
5082 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5084 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
5085 struct nlattr
*nla_entry
;
5087 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
5088 pr_out_handle_start_arr(ctx
->dl
, tb
);
5089 if (dpipe_entry_show(ctx
, nla_entry
))
5090 goto err_entry_show
;
5091 pr_out_handle_end(ctx
->dl
);
5096 pr_out_handle_end(ctx
->dl
);
5100 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5102 struct dpipe_ctx
*ctx
= data
;
5103 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5104 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5106 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5107 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5108 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
5109 return MNL_CB_ERROR
;
5111 if (dpipe_table_entries_show(ctx
, tb
))
5112 return MNL_CB_ERROR
;
5116 static int cmd_dpipe_table_dump(struct dl
*dl
)
5118 struct nlmsghdr
*nlh
;
5119 struct dpipe_ctx ctx
= {};
5120 uint16_t flags
= NLM_F_REQUEST
;
5123 err
= dpipe_ctx_init(&ctx
, dl
);
5127 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
5131 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5132 dl_opts_put(nlh
, dl
);
5133 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5135 pr_err("error get headers %s\n", strerror(ctx
.err
));
5139 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5140 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
5141 dl_opts_put(nlh
, dl
);
5143 pr_out_section_start(dl
, "table_entry");
5144 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, &ctx
);
5145 pr_out_section_end(dl
);
5147 dpipe_ctx_fini(&ctx
);
5151 static void cmd_dpipe_table_help(void)
5153 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
5154 "where OBJECT-LIST := { show | set | dump }\n");
5157 static int cmd_dpipe_table(struct dl
*dl
)
5159 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5160 cmd_dpipe_table_help();
5162 } else if (dl_argv_match(dl
, "show")) {
5164 return cmd_dpipe_table_show(dl
);
5165 } else if (dl_argv_match(dl
, "set")) {
5167 return cmd_dpipe_table_set(dl
);
5168 } else if (dl_argv_match(dl
, "dump")) {
5170 return cmd_dpipe_table_dump(dl
);
5172 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5176 static void cmd_dpipe_help(void)
5178 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
5179 "where OBJECT-LIST := { header | table }\n");
5182 static int cmd_dpipe(struct dl
*dl
)
5184 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5187 } else if (dl_argv_match(dl
, "header")) {
5189 return cmd_dpipe_header(dl
);
5190 } else if (dl_argv_match(dl
, "table")) {
5192 return cmd_dpipe_table(dl
);
5194 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5199 resource_parse(struct resource_ctx
*ctx
, struct resource
*resource
,
5200 struct nlattr
**nla_resource
)
5202 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
] ||
5203 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
] ||
5204 !nla_resource
[DEVLINK_ATTR_RESOURCE_ID
] ||
5205 !nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
] ||
5206 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
] ||
5207 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
] ||
5208 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]) {
5212 resource
->name
= strdup(mnl_attr_get_str(nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
]));
5213 resource
->size
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
]);
5214 resource
->id
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_ID
]);
5215 resource
->unit
= mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
]);
5216 resource
->size_min
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
]);
5217 resource
->size_max
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
]);
5218 resource
->size_gran
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]);
5220 if (nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
])
5221 resource
->size_new
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
]);
5223 resource
->size_new
= resource
->size
;
5225 if (nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]) {
5226 resource
->size_occ
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]);
5227 resource
->occ_valid
= true;
5230 if (resource
->size_new
!= resource
->size
)
5231 ctx
->pending_change
= true;
5237 resource_get(struct resource_ctx
*ctx
, struct resource
*resource
,
5238 struct resource
*parent_resource
, struct nlattr
*nl
)
5240 struct nlattr
*nla_resource
[DEVLINK_ATTR_MAX
+ 1] = {};
5241 struct nlattr
*nla_child_resource
;
5242 struct nlattr
*nla_resources
;
5252 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_resource
);
5253 if (err
!= MNL_CB_OK
)
5256 err
= resource_parse(ctx
, resource
, nla_resource
);
5260 resource
->parent
= parent_resource
;
5261 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
])
5264 resource
->size_valid
= !!mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_VALID
]);
5265 nla_resources
= nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
];
5267 mnl_attr_for_each_nested(nla_child_resource
, nla_resources
) {
5268 struct resource
*child_resource
;
5269 struct list_head
*list
;
5271 child_resource
= resource_alloc();
5272 if (!child_resource
)
5276 list
= &ctx
->resources
->resource_list
;
5278 list
= &resource
->resource_list
;
5280 list_add_tail(&child_resource
->list
, list
);
5281 err
= resource_get(ctx
, child_resource
, resource
,
5282 nla_child_resource
);
5290 static const char *resource_unit_str_get(enum devlink_resource_unit unit
)
5293 case DEVLINK_RESOURCE_UNIT_ENTRY
: return "entry";
5294 default: return "<unknown unit>";
5298 static void resource_show(struct resource
*resource
,
5299 struct resource_ctx
*ctx
)
5301 struct resource
*child_resource
;
5302 struct dpipe_table
*table
;
5303 struct dl
*dl
= ctx
->dl
;
5306 pr_out_str(dl
, "name", resource
->name
);
5308 resource_path_print(dl
, ctx
->resources
, resource
->id
);
5309 pr_out_u64(dl
, "size", resource
->size
);
5310 if (resource
->size
!= resource
->size_new
)
5311 pr_out_u64(dl
, "size_new", resource
->size_new
);
5312 if (resource
->occ_valid
)
5313 pr_out_uint(dl
, "occ", resource
->size_occ
);
5314 pr_out_str(dl
, "unit", resource_unit_str_get(resource
->unit
));
5316 if (resource
->size_min
!= resource
->size_max
) {
5317 pr_out_uint(dl
, "size_min", resource
->size_min
);
5318 pr_out_u64(dl
, "size_max", resource
->size_max
);
5319 pr_out_uint(dl
, "size_gran", resource
->size_gran
);
5322 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
)
5323 if (table
->resource_id
== resource
->id
&&
5324 table
->resource_valid
)
5328 pr_out_array_start(dl
, "dpipe_tables");
5330 pr_out_str(dl
, "dpipe_tables", "none");
5332 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
) {
5333 if (table
->resource_id
!= resource
->id
||
5334 !table
->resource_valid
)
5336 pr_out_entry_start(dl
);
5337 pr_out_str(dl
, "table_name", table
->name
);
5338 pr_out_entry_end(dl
);
5341 pr_out_array_end(dl
);
5343 if (list_empty(&resource
->resource_list
))
5346 if (ctx
->pending_change
)
5347 pr_out_str(dl
, "size_valid", resource
->size_valid
?
5349 pr_out_array_start(dl
, "resources");
5350 list_for_each_entry(child_resource
, &resource
->resource_list
, list
) {
5351 pr_out_entry_start(dl
);
5352 resource_show(child_resource
, ctx
);
5353 pr_out_entry_end(dl
);
5355 pr_out_array_end(dl
);
5359 resources_show(struct resource_ctx
*ctx
, struct nlattr
**tb
)
5361 struct resources
*resources
= ctx
->resources
;
5362 struct resource
*resource
;
5364 list_for_each_entry(resource
, &resources
->resource_list
, list
) {
5365 pr_out_handle_start_arr(ctx
->dl
, tb
);
5366 resource_show(resource
, ctx
);
5367 pr_out_handle_end(ctx
->dl
);
5371 static int resources_get(struct resource_ctx
*ctx
, struct nlattr
**tb
)
5373 return resource_get(ctx
, NULL
, NULL
, tb
[DEVLINK_ATTR_RESOURCE_LIST
]);
5376 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5378 struct resource_ctx
*ctx
= data
;
5379 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5380 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5383 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5384 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5385 !tb
[DEVLINK_ATTR_RESOURCE_LIST
])
5386 return MNL_CB_ERROR
;
5388 err
= resources_get(ctx
, tb
);
5391 return MNL_CB_ERROR
;
5394 if (ctx
->print_resources
)
5395 resources_show(ctx
, tb
);
5400 static int cmd_resource_show(struct dl
*dl
)
5402 struct nlmsghdr
*nlh
;
5403 struct dpipe_ctx dpipe_ctx
= {};
5404 struct resource_ctx resource_ctx
= {};
5407 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, 0);
5411 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
,
5413 dl_opts_put(nlh
, dl
);
5415 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5419 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
,
5422 pr_err("error get tables %s\n", strerror(dpipe_ctx
.err
));
5426 err
= resource_ctx_init(&resource_ctx
, dl
);
5430 resource_ctx
.print_resources
= true;
5431 resource_ctx
.tables
= dpipe_ctx
.tables
;
5432 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
5433 NLM_F_REQUEST
| NLM_F_ACK
);
5434 dl_opts_put(nlh
, dl
);
5435 pr_out_section_start(dl
, "resources");
5436 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
5438 pr_out_section_end(dl
);
5439 resource_ctx_fini(&resource_ctx
);
5441 dpipe_ctx_fini(&dpipe_ctx
);
5445 static void cmd_resource_help(void)
5447 pr_err("Usage: devlink resource show DEV\n"
5448 " devlink resource set DEV path PATH size SIZE\n");
5451 static struct resource
*
5452 resource_find_by_name(struct list_head
*list
, char *name
)
5454 struct resource
*resource
;
5456 list_for_each_entry(resource
, list
, list
) {
5457 if (!strcmp(resource
->name
, name
))
5464 resource_path_parse(struct resource_ctx
*ctx
, const char *resource_path
,
5465 uint32_t *p_resource_id
, bool *p_resource_valid
)
5467 struct resource
*resource
;
5468 uint32_t resource_id
= 0;
5469 char *resource_path_dup
;
5470 struct list_head
*list
;
5471 const char del
[] = "/";
5472 char *resource_name
;
5474 resource_path_dup
= strdup(resource_path
);
5475 list
= &ctx
->resources
->resource_list
;
5476 resource_name
= strtok(resource_path_dup
, del
);
5477 while (resource_name
!= NULL
) {
5478 resource
= resource_find_by_name(list
, resource_name
);
5480 goto err_resource_lookup
;
5482 list
= &resource
->resource_list
;
5483 resource_name
= strtok(NULL
, del
);
5484 resource_id
= resource
->id
;
5486 free(resource_path_dup
);
5487 *p_resource_valid
= true;
5488 *p_resource_id
= resource_id
;
5491 err_resource_lookup
:
5492 free(resource_path_dup
);
5496 static int cmd_resource_set(struct dl
*dl
)
5498 struct nlmsghdr
*nlh
;
5499 struct resource_ctx ctx
= {};
5502 err
= resource_ctx_init(&ctx
, dl
);
5506 ctx
.print_resources
= false;
5507 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_RESOURCE_PATH
|
5508 DL_OPT_RESOURCE_SIZE
, 0);
5512 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
5514 dl_opts_put(nlh
, dl
);
5515 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
, &ctx
);
5517 pr_err("error getting resources %s\n", strerror(ctx
.err
));
5521 err
= resource_path_parse(&ctx
, dl
->opts
.resource_path
,
5522 &dl
->opts
.resource_id
,
5523 &dl
->opts
.resource_id_valid
);
5525 pr_err("error parsing resource path %s\n", strerror(-err
));
5529 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_SET
,
5530 NLM_F_REQUEST
| NLM_F_ACK
);
5532 dl_opts_put(nlh
, dl
);
5533 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5535 resource_ctx_fini(&ctx
);
5539 static int cmd_resource(struct dl
*dl
)
5541 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5542 cmd_resource_help();
5544 } else if (dl_argv_match(dl
, "show")) {
5546 return cmd_resource_show(dl
);
5547 } else if (dl_argv_match(dl
, "set")) {
5549 return cmd_resource_set(dl
);
5551 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5555 static void pr_out_region_handle_start(struct dl
*dl
, struct nlattr
**tb
)
5557 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
5558 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
5559 const char *region_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_REGION_NAME
]);
5562 sprintf(buf
, "%s/%s/%s", bus_name
, dev_name
, region_name
);
5563 if (dl
->json_output
) {
5564 jsonw_name(dl
->jw
, buf
);
5565 jsonw_start_object(dl
->jw
);
5571 static void pr_out_region_handle_end(struct dl
*dl
)
5573 if (dl
->json_output
)
5574 jsonw_end_object(dl
->jw
);
5579 static void pr_out_region_snapshots_start(struct dl
*dl
, bool array
)
5581 if (dl
->json_output
) {
5582 jsonw_name(dl
->jw
, "snapshot");
5583 jsonw_start_array(dl
->jw
);
5585 if (g_indent_newline
)
5586 pr_out("snapshot %s", array
? "[" : "");
5588 pr_out(" snapshot %s", array
? "[" : "");
5592 static void pr_out_region_snapshots_end(struct dl
*dl
, bool array
)
5594 if (dl
->json_output
)
5595 jsonw_end_array(dl
->jw
);
5600 static void pr_out_region_snapshots_id(struct dl
*dl
, struct nlattr
**tb
, int index
)
5602 uint32_t snapshot_id
;
5604 if (!tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
5607 snapshot_id
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
]);
5609 if (dl
->json_output
)
5610 jsonw_uint(dl
->jw
, snapshot_id
);
5612 pr_out("%s%u", index
? " " : "", snapshot_id
);
5615 static void pr_out_snapshots(struct dl
*dl
, struct nlattr
**tb
)
5617 struct nlattr
*tb_snapshot
[DEVLINK_ATTR_MAX
+ 1] = {};
5618 struct nlattr
*nla_sanpshot
;
5621 pr_out_region_snapshots_start(dl
, true);
5622 mnl_attr_for_each_nested(nla_sanpshot
, tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
]) {
5623 err
= mnl_attr_parse_nested(nla_sanpshot
, attr_cb
, tb_snapshot
);
5624 if (err
!= MNL_CB_OK
)
5626 pr_out_region_snapshots_id(dl
, tb_snapshot
, index
++);
5628 pr_out_region_snapshots_end(dl
, true);
5631 static void pr_out_snapshot(struct dl
*dl
, struct nlattr
**tb
)
5633 pr_out_region_snapshots_start(dl
, false);
5634 pr_out_region_snapshots_id(dl
, tb
, 0);
5635 pr_out_region_snapshots_end(dl
, false);
5638 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
)
5640 pr_out_region_handle_start(dl
, tb
);
5642 if (tb
[DEVLINK_ATTR_REGION_SIZE
])
5643 pr_out_u64(dl
, "size",
5644 mnl_attr_get_u64(tb
[DEVLINK_ATTR_REGION_SIZE
]));
5646 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
])
5647 pr_out_snapshots(dl
, tb
);
5649 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
5650 pr_out_snapshot(dl
, tb
);
5652 pr_out_region_handle_end(dl
);
5655 static int cmd_region_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5657 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5658 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5659 struct dl
*dl
= data
;
5661 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5662 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5663 !tb
[DEVLINK_ATTR_REGION_NAME
] || !tb
[DEVLINK_ATTR_REGION_SIZE
])
5664 return MNL_CB_ERROR
;
5666 pr_out_region(dl
, tb
);
5671 static int cmd_region_show(struct dl
*dl
)
5673 struct nlmsghdr
*nlh
;
5674 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5677 if (dl_argc(dl
) == 0)
5678 flags
|= NLM_F_DUMP
;
5680 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_GET
, flags
);
5682 if (dl_argc(dl
) > 0) {
5683 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
, 0);
5688 pr_out_section_start(dl
, "regions");
5689 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_show_cb
, dl
);
5690 pr_out_section_end(dl
);
5694 static int cmd_region_snapshot_del(struct dl
*dl
)
5696 struct nlmsghdr
*nlh
;
5699 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_DEL
,
5700 NLM_F_REQUEST
| NLM_F_ACK
);
5702 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
5703 DL_OPT_REGION_SNAPSHOT_ID
, 0);
5707 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5710 static int cmd_region_read_cb(const struct nlmsghdr
*nlh
, void *data
)
5712 struct nlattr
*nla_entry
, *nla_chunk_data
, *nla_chunk_addr
;
5713 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5714 struct nlattr
*tb_field
[DEVLINK_ATTR_MAX
+ 1] = {};
5715 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5716 struct dl
*dl
= data
;
5719 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5720 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5721 !tb
[DEVLINK_ATTR_REGION_CHUNKS
])
5722 return MNL_CB_ERROR
;
5724 mnl_attr_for_each_nested(nla_entry
, tb
[DEVLINK_ATTR_REGION_CHUNKS
]) {
5725 err
= mnl_attr_parse_nested(nla_entry
, attr_cb
, tb_field
);
5726 if (err
!= MNL_CB_OK
)
5727 return MNL_CB_ERROR
;
5729 nla_chunk_data
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_DATA
];
5730 if (!nla_chunk_data
)
5733 nla_chunk_addr
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_ADDR
];
5734 if (!nla_chunk_addr
)
5737 pr_out_region_chunk(dl
, mnl_attr_get_payload(nla_chunk_data
),
5738 mnl_attr_get_payload_len(nla_chunk_data
),
5739 mnl_attr_get_u64(nla_chunk_addr
));
5744 static int cmd_region_dump(struct dl
*dl
)
5746 struct nlmsghdr
*nlh
;
5749 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
5750 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
5752 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
5753 DL_OPT_REGION_SNAPSHOT_ID
, 0);
5757 pr_out_section_start(dl
, "dump");
5758 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
5759 pr_out_section_end(dl
);
5760 if (!dl
->json_output
)
5765 static int cmd_region_read(struct dl
*dl
)
5767 struct nlmsghdr
*nlh
;
5770 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
5771 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
5773 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
5774 DL_OPT_REGION_ADDRESS
| DL_OPT_REGION_LENGTH
|
5775 DL_OPT_REGION_SNAPSHOT_ID
, 0);
5779 pr_out_section_start(dl
, "read");
5780 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
5781 pr_out_section_end(dl
);
5782 if (!dl
->json_output
)
5787 static void cmd_region_help(void)
5789 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
5790 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
5791 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
5792 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
5795 static int cmd_region(struct dl
*dl
)
5797 if (dl_no_arg(dl
)) {
5798 return cmd_region_show(dl
);
5799 } else if (dl_argv_match(dl
, "help")) {
5802 } else if (dl_argv_match(dl
, "show")) {
5804 return cmd_region_show(dl
);
5805 } else if (dl_argv_match(dl
, "del")) {
5807 return cmd_region_snapshot_del(dl
);
5808 } else if (dl_argv_match(dl
, "dump")) {
5810 return cmd_region_dump(dl
);
5811 } else if (dl_argv_match(dl
, "read")) {
5813 return cmd_region_read(dl
);
5815 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5819 static int cmd_health_dump_clear(struct dl
*dl
)
5821 struct nlmsghdr
*nlh
;
5824 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR
,
5825 NLM_F_REQUEST
| NLM_F_ACK
);
5827 err
= dl_argv_parse_put(nlh
, dl
,
5828 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
5832 dl_opts_put(nlh
, dl
);
5833 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5836 static int fmsg_value_show(struct dl
*dl
, int type
, struct nlattr
*nl_data
)
5843 pr_out_bool_value(dl
, mnl_attr_get_u8(nl_data
));
5846 pr_out_uint_value(dl
, mnl_attr_get_u8(nl_data
));
5849 pr_out_uint_value(dl
, mnl_attr_get_u16(nl_data
));
5852 pr_out_uint_value(dl
, mnl_attr_get_u32(nl_data
));
5855 pr_out_uint64_value(dl
, mnl_attr_get_u64(nl_data
));
5857 case MNL_TYPE_NUL_STRING
:
5858 pr_out_str_value(dl
, mnl_attr_get_str(nl_data
));
5860 case MNL_TYPE_BINARY
:
5861 len
= mnl_attr_get_payload_len(nl_data
);
5862 data
= mnl_attr_get_payload(nl_data
);
5863 pr_out_binary_value(dl
, data
, len
);
5871 struct nest_qentry
{
5873 TAILQ_ENTRY(nest_qentry
) nest_entries
;
5876 struct fmsg_cb_data
{
5879 TAILQ_HEAD(, nest_qentry
) qhead
;
5882 static int cmd_fmsg_nest_queue(struct fmsg_cb_data
*fmsg_data
,
5883 uint8_t *attr_value
, bool insert
)
5885 struct nest_qentry
*entry
= NULL
;
5888 entry
= malloc(sizeof(struct nest_qentry
));
5892 entry
->attr_type
= *attr_value
;
5893 TAILQ_INSERT_HEAD(&fmsg_data
->qhead
, entry
, nest_entries
);
5895 if (TAILQ_EMPTY(&fmsg_data
->qhead
))
5896 return MNL_CB_ERROR
;
5897 entry
= TAILQ_FIRST(&fmsg_data
->qhead
);
5898 *attr_value
= entry
->attr_type
;
5899 TAILQ_REMOVE(&fmsg_data
->qhead
, entry
, nest_entries
);
5905 static int cmd_fmsg_nest(struct fmsg_cb_data
*fmsg_data
, uint8_t nest_value
,
5908 struct dl
*dl
= fmsg_data
->dl
;
5909 uint8_t value
= nest_value
;
5912 err
= cmd_fmsg_nest_queue(fmsg_data
, &value
, start
);
5913 if (err
!= MNL_CB_OK
)
5917 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
5919 pr_out_entry_start(dl
);
5921 pr_out_entry_end(dl
);
5923 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
5925 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
5926 if (dl
->json_output
) {
5928 jsonw_start_array(dl
->jw
);
5930 jsonw_end_array(dl
->jw
);
5934 __pr_out_indent_inc();
5936 __pr_out_indent_dec();
5946 static int cmd_fmsg_object_cb(const struct nlmsghdr
*nlh
, void *data
)
5948 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5949 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5950 struct fmsg_cb_data
*fmsg_data
= data
;
5951 struct dl
*dl
= fmsg_data
->dl
;
5952 struct nlattr
*nla_object
;
5956 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5957 if (!tb
[DEVLINK_ATTR_FMSG
])
5958 return MNL_CB_ERROR
;
5960 mnl_attr_for_each_nested(nla_object
, tb
[DEVLINK_ATTR_FMSG
]) {
5961 attr_type
= mnl_attr_get_type(nla_object
);
5962 switch (attr_type
) {
5963 case DEVLINK_ATTR_FMSG_OBJ_NEST_START
:
5964 case DEVLINK_ATTR_FMSG_PAIR_NEST_START
:
5965 case DEVLINK_ATTR_FMSG_ARR_NEST_START
:
5966 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, true);
5967 if (err
!= MNL_CB_OK
)
5970 case DEVLINK_ATTR_FMSG_NEST_END
:
5971 err
= cmd_fmsg_nest(fmsg_data
, attr_type
, false);
5972 if (err
!= MNL_CB_OK
)
5975 case DEVLINK_ATTR_FMSG_OBJ_NAME
:
5976 pr_out_name(dl
, mnl_attr_get_str(nla_object
));
5978 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE
:
5979 fmsg_data
->value_type
= mnl_attr_get_u8(nla_object
);
5981 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA
:
5982 err
= fmsg_value_show(dl
, fmsg_data
->value_type
,
5984 if (err
!= MNL_CB_OK
)
5994 static int cmd_health_object_common(struct dl
*dl
, uint8_t cmd
)
5996 struct fmsg_cb_data data
;
5997 struct nlmsghdr
*nlh
;
6000 nlh
= mnlg_msg_prepare(dl
->nlg
, cmd
, NLM_F_REQUEST
| NLM_F_ACK
);
6002 err
= dl_argv_parse_put(nlh
, dl
,
6003 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6008 TAILQ_INIT(&data
.qhead
);
6009 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_fmsg_object_cb
, &data
);
6013 static int cmd_health_dump_show(struct dl
*dl
)
6015 return cmd_health_object_common(dl
, DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET
);
6018 static int cmd_health_diagnose(struct dl
*dl
)
6020 return cmd_health_object_common(dl
, DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE
);
6023 static int cmd_health_recover(struct dl
*dl
)
6025 struct nlmsghdr
*nlh
;
6028 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
,
6029 NLM_F_REQUEST
| NLM_F_ACK
);
6031 err
= dl_argv_parse_put(nlh
, dl
,
6032 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
6036 dl_opts_put(nlh
, dl
);
6037 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
6040 enum devlink_health_reporter_state
{
6041 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
,
6042 DEVLINK_HEALTH_REPORTER_STATE_ERROR
,
6045 static const char *health_state_name(uint8_t state
)
6048 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
:
6049 return HEALTH_REPORTER_STATE_HEALTHY_STR
;
6050 case DEVLINK_HEALTH_REPORTER_STATE_ERROR
:
6051 return HEALTH_REPORTER_STATE_ERROR_STR
;
6053 return "<unknown state>";
6057 static void format_logtime(uint64_t time_ms
, char *ts_date
, char *ts_time
)
6059 struct sysinfo s_info
;
6065 info
= localtime(&now
);
6066 err
= sysinfo(&s_info
);
6069 /* Subtract uptime in sec from now yields the time of system
6070 * uptime. To this, add time_ms which is the amount of
6071 * milliseconds elapsed between uptime and the dump taken.
6073 sec
= now
- s_info
.uptime
+ time_ms
/ 1000;
6074 info
= localtime(&sec
);
6076 strftime(ts_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", info
);
6077 strftime(ts_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", info
);
6080 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
)
6082 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6083 enum devlink_health_reporter_state state
;
6084 const struct nlattr
*attr
;
6088 err
= mnl_attr_parse_nested(tb_health
[DEVLINK_ATTR_HEALTH_REPORTER
],
6090 if (err
!= MNL_CB_OK
)
6093 if (!tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
] ||
6094 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] ||
6095 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] ||
6096 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
])
6099 pr_out_handle_start_arr(dl
, tb_health
);
6101 pr_out_str(dl
, "name",
6102 mnl_attr_get_str(tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]));
6103 if (!dl
->json_output
) {
6105 __pr_out_indent_inc();
6107 state
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
]);
6108 pr_out_str(dl
, "state", health_state_name(state
));
6109 pr_out_u64(dl
, "error",
6110 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
]));
6111 pr_out_u64(dl
, "recover",
6112 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
]));
6113 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
]) {
6114 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6115 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
6117 attr
= tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
];
6118 time_ms
= mnl_attr_get_u64(attr
);
6119 format_logtime(time_ms
, dump_date
, dump_time
);
6121 pr_out_str(dl
, "last_dump_date", dump_date
);
6122 pr_out_str(dl
, "last_dump_time", dump_time
);
6124 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
6125 pr_out_u64(dl
, "grace_period",
6126 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]));
6127 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
6128 pr_out_bool(dl
, "auto_recover",
6129 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]));
6131 __pr_out_indent_dec();
6132 pr_out_handle_end(dl
);
6135 static int cmd_health_show_cb(const struct nlmsghdr
*nlh
, void *data
)
6137 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
6138 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
6139 struct dl
*dl
= data
;
6141 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
6142 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
6143 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
6144 return MNL_CB_ERROR
;
6146 pr_out_health(dl
, tb
);
6151 static int cmd_health_show(struct dl
*dl
)
6153 struct nlmsghdr
*nlh
;
6154 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
6157 if (dl_argc(dl
) == 0)
6158 flags
|= NLM_F_DUMP
;
6159 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_GET
,
6162 if (dl_argc(dl
) > 0) {
6163 err
= dl_argv_parse_put(nlh
, dl
,
6165 DL_OPT_HEALTH_REPORTER_NAME
, 0);
6169 pr_out_section_start(dl
, "health");
6171 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_health_show_cb
, dl
);
6172 pr_out_section_end(dl
);
6176 static void cmd_health_help(void)
6178 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
6179 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
6180 pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n");
6181 pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n");
6182 pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n");
6185 static int cmd_health(struct dl
*dl
)
6187 if (dl_argv_match(dl
, "help")) {
6190 } else if (dl_argv_match(dl
, "show") ||
6191 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
6193 return cmd_health_show(dl
);
6194 } else if (dl_argv_match(dl
, "recover")) {
6196 return cmd_health_recover(dl
);
6197 } else if (dl_argv_match(dl
, "diagnose")) {
6199 return cmd_health_diagnose(dl
);
6200 } else if (dl_argv_match(dl
, "dump")) {
6202 if (dl_argv_match(dl
, "show")) {
6204 return cmd_health_dump_show(dl
);
6205 } else if (dl_argv_match(dl
, "clear")) {
6207 return cmd_health_dump_clear(dl
);
6210 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
6214 static void help(void)
6216 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
6217 " devlink [ -f[orce] ] -b[atch] filename\n"
6218 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health }\n"
6219 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] }\n");
6222 static int dl_cmd(struct dl
*dl
, int argc
, char **argv
)
6227 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6230 } else if (dl_argv_match(dl
, "dev")) {
6233 } else if (dl_argv_match(dl
, "port")) {
6235 return cmd_port(dl
);
6236 } else if (dl_argv_match(dl
, "sb")) {
6239 } else if (dl_argv_match(dl
, "monitor")) {
6242 } else if (dl_argv_match(dl
, "dpipe")) {
6244 return cmd_dpipe(dl
);
6245 } else if (dl_argv_match(dl
, "resource")) {
6247 return cmd_resource(dl
);
6248 } else if (dl_argv_match(dl
, "region")) {
6250 return cmd_region(dl
);
6251 } else if (dl_argv_match(dl
, "health")) {
6253 return cmd_health(dl
);
6255 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
6259 static int dl_init(struct dl
*dl
)
6263 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
6265 pr_err("Failed to connect to devlink Netlink\n");
6269 err
= ifname_map_init(dl
);
6271 pr_err("Failed to create index map\n");
6272 goto err_ifname_map_create
;
6274 if (dl
->json_output
) {
6275 dl
->jw
= jsonw_new(stdout
);
6277 pr_err("Failed to create JSON writer\n");
6280 jsonw_pretty(dl
->jw
, dl
->pretty_output
);
6285 ifname_map_fini(dl
);
6286 err_ifname_map_create
:
6287 mnlg_socket_close(dl
->nlg
);
6291 static void dl_fini(struct dl
*dl
)
6293 if (dl
->json_output
)
6294 jsonw_destroy(&dl
->jw
);
6295 ifname_map_fini(dl
);
6296 mnlg_socket_close(dl
->nlg
);
6299 static struct dl
*dl_alloc(void)
6303 dl
= calloc(1, sizeof(*dl
));
6309 static void dl_free(struct dl
*dl
)
6314 static int dl_batch(struct dl
*dl
, const char *name
, bool force
)
6318 int ret
= EXIT_SUCCESS
;
6320 if (name
&& strcmp(name
, "-") != 0) {
6321 if (freopen(name
, "r", stdin
) == NULL
) {
6323 "Cannot open file \"%s\" for reading: %s\n",
6324 name
, strerror(errno
));
6325 return EXIT_FAILURE
;
6330 while (getcmdline(&line
, &len
, stdin
) != -1) {
6334 largc
= makeargs(line
, largv
, 100);
6336 continue; /* blank line */
6338 if (dl_cmd(dl
, largc
, largv
)) {
6339 fprintf(stderr
, "Command failed %s:%d\n",
6353 int main(int argc
, char **argv
)
6355 static const struct option long_options
[] = {
6356 { "Version", no_argument
, NULL
, 'V' },
6357 { "force", no_argument
, NULL
, 'f' },
6358 { "batch", required_argument
, NULL
, 'b' },
6359 { "no-nice-names", no_argument
, NULL
, 'n' },
6360 { "json", no_argument
, NULL
, 'j' },
6361 { "pretty", no_argument
, NULL
, 'p' },
6362 { "verbose", no_argument
, NULL
, 'v' },
6363 { NULL
, 0, NULL
, 0 }
6365 const char *batch_file
= NULL
;
6374 pr_err("Failed to allocate memory for devlink\n");
6375 return EXIT_FAILURE
;
6378 while ((opt
= getopt_long(argc
, argv
, "Vfb:njpv",
6379 long_options
, NULL
)) >= 0) {
6383 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
6390 batch_file
= optarg
;
6393 dl
->no_nice_names
= true;
6396 dl
->json_output
= true;
6399 dl
->pretty_output
= true;
6405 pr_err("Unknown option.\n");
6422 err
= dl_batch(dl
, batch_file
, force
);
6424 err
= dl_cmd(dl
, argc
, argv
);