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>
30 #include "json_writer.h"
33 #define ESWITCH_MODE_LEGACY "legacy"
34 #define ESWITCH_MODE_SWITCHDEV "switchdev"
35 #define ESWITCH_INLINE_MODE_NONE "none"
36 #define ESWITCH_INLINE_MODE_LINK "link"
37 #define ESWITCH_INLINE_MODE_NETWORK "network"
38 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
40 #define PARAM_CMODE_RUNTIME_STR "runtime"
41 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
42 #define PARAM_CMODE_PERMANENT_STR "permanent"
43 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
45 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
46 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
47 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
49 static int g_new_line_count
;
51 #define pr_err(args...) fprintf(stderr, ##args)
52 #define pr_out(args...) \
54 if (g_indent_newline) { \
55 fprintf(stdout, "%s", g_indent_str); \
56 g_indent_newline = false; \
58 fprintf(stdout, ##args); \
59 g_new_line_count = 0; \
62 #define pr_out_sp(num, args...) \
64 int ret = fprintf(stdout, ##args); \
66 fprintf(stdout, "%*s", num - ret, ""); \
67 g_new_line_count = 0; \
70 static int g_indent_level
;
71 static bool g_indent_newline
;
72 #define INDENT_STR_STEP 2
73 #define INDENT_STR_MAXLEN 32
74 static char g_indent_str
[INDENT_STR_MAXLEN
+ 1] = "";
76 static void __pr_out_indent_inc(void)
78 if (g_indent_level
+ INDENT_STR_STEP
> INDENT_STR_MAXLEN
)
80 g_indent_level
+= INDENT_STR_STEP
;
81 memset(g_indent_str
, ' ', sizeof(g_indent_str
));
82 g_indent_str
[g_indent_level
] = '\0';
85 static void __pr_out_indent_dec(void)
87 if (g_indent_level
- INDENT_STR_STEP
< 0)
89 g_indent_level
-= INDENT_STR_STEP
;
90 g_indent_str
[g_indent_level
] = '\0';
93 static void __pr_out_newline(void)
95 if (g_new_line_count
< 1) {
97 g_indent_newline
= true;
102 static int _mnlg_socket_recv_run(struct mnlg_socket
*nlg
,
103 mnl_cb_t data_cb
, void *data
)
107 err
= mnlg_socket_recv_run(nlg
, data_cb
, data
);
109 pr_err("devlink answers: %s\n", strerror(errno
));
115 static int _mnlg_socket_sndrcv(struct mnlg_socket
*nlg
,
116 const struct nlmsghdr
*nlh
,
117 mnl_cb_t data_cb
, void *data
)
121 err
= mnlg_socket_send(nlg
, nlh
);
123 pr_err("Failed to call mnlg_socket_send\n");
126 return _mnlg_socket_recv_run(nlg
, data_cb
, data
);
129 static int _mnlg_socket_group_add(struct mnlg_socket
*nlg
,
130 const char *group_name
)
134 err
= mnlg_socket_group_add(nlg
, group_name
);
136 pr_err("Failed to call mnlg_socket_group_add\n");
143 struct list_head list
;
150 static struct ifname_map
*ifname_map_alloc(const char *bus_name
,
151 const char *dev_name
,
155 struct ifname_map
*ifname_map
;
157 ifname_map
= calloc(1, sizeof(*ifname_map
));
160 ifname_map
->bus_name
= strdup(bus_name
);
161 ifname_map
->dev_name
= strdup(dev_name
);
162 ifname_map
->port_index
= port_index
;
163 ifname_map
->ifname
= strdup(ifname
);
164 if (!ifname_map
->bus_name
|| !ifname_map
->dev_name
||
165 !ifname_map
->ifname
) {
166 free(ifname_map
->ifname
);
167 free(ifname_map
->dev_name
);
168 free(ifname_map
->bus_name
);
175 static void ifname_map_free(struct ifname_map
*ifname_map
)
177 free(ifname_map
->ifname
);
178 free(ifname_map
->dev_name
);
179 free(ifname_map
->bus_name
);
183 #define DL_OPT_HANDLE BIT(0)
184 #define DL_OPT_HANDLEP BIT(1)
185 #define DL_OPT_PORT_TYPE BIT(2)
186 #define DL_OPT_PORT_COUNT BIT(3)
187 #define DL_OPT_SB BIT(4)
188 #define DL_OPT_SB_POOL BIT(5)
189 #define DL_OPT_SB_SIZE BIT(6)
190 #define DL_OPT_SB_TYPE BIT(7)
191 #define DL_OPT_SB_THTYPE BIT(8)
192 #define DL_OPT_SB_TH BIT(9)
193 #define DL_OPT_SB_TC BIT(10)
194 #define DL_OPT_ESWITCH_MODE BIT(11)
195 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
196 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
197 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
198 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
199 #define DL_OPT_RESOURCE_PATH BIT(16)
200 #define DL_OPT_RESOURCE_SIZE BIT(17)
201 #define DL_OPT_PARAM_NAME BIT(18)
202 #define DL_OPT_PARAM_VALUE BIT(19)
203 #define DL_OPT_PARAM_CMODE BIT(20)
204 #define DL_OPT_HANDLE_REGION BIT(21)
205 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
206 #define DL_OPT_REGION_ADDRESS BIT(23)
207 #define DL_OPT_REGION_LENGTH BIT(24)
208 #define DL_OPT_FLASH_FILE_NAME BIT(25)
209 #define DL_OPT_FLASH_COMPONENT BIT(26)
210 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
213 uint32_t present
; /* flags of present items */
217 enum devlink_port_type port_type
;
220 uint16_t sb_pool_index
;
221 uint32_t sb_pool_size
;
222 enum devlink_sb_pool_type sb_pool_type
;
223 enum devlink_sb_threshold_type sb_pool_thtype
;
224 uint32_t sb_threshold
;
225 uint16_t sb_tc_index
;
226 enum devlink_eswitch_mode eswitch_mode
;
227 enum devlink_eswitch_inline_mode eswitch_inline_mode
;
228 const char *dpipe_table_name
;
229 bool dpipe_counters_enable
;
230 bool eswitch_encap_mode
;
231 const char *resource_path
;
232 uint32_t resource_size
;
233 uint32_t resource_id
;
234 bool resource_id_valid
;
235 const char *param_name
;
236 const char *param_value
;
237 enum devlink_param_cmode cmode
;
239 uint32_t region_snapshot_id
;
240 uint64_t region_address
;
241 uint64_t region_length
;
242 const char *flash_file_name
;
243 const char *flash_component
;
244 const char *reporter_name
;
248 struct mnlg_socket
*nlg
;
249 struct list_head ifname_map_list
;
266 static int dl_argc(struct dl
*dl
)
271 static char *dl_argv(struct dl
*dl
)
273 if (dl_argc(dl
) == 0)
278 static void dl_arg_inc(struct dl
*dl
)
280 if (dl_argc(dl
) == 0)
286 static char *dl_argv_next(struct dl
*dl
)
290 if (dl_argc(dl
) == 0)
298 static char *dl_argv_index(struct dl
*dl
, unsigned int index
)
300 if (index
>= dl_argc(dl
))
302 return dl
->argv
[index
];
305 static int strcmpx(const char *str1
, const char *str2
)
307 if (strlen(str1
) > strlen(str2
))
309 return strncmp(str1
, str2
, strlen(str1
));
312 static bool dl_argv_match(struct dl
*dl
, const char *pattern
)
314 if (dl_argc(dl
) == 0)
316 return strcmpx(dl_argv(dl
), pattern
) == 0;
319 static bool dl_no_arg(struct dl
*dl
)
321 return dl_argc(dl
) == 0;
324 static const enum mnl_attr_data_type devlink_policy
[DEVLINK_ATTR_MAX
+ 1] = {
325 [DEVLINK_ATTR_BUS_NAME
] = MNL_TYPE_NUL_STRING
,
326 [DEVLINK_ATTR_DEV_NAME
] = MNL_TYPE_NUL_STRING
,
327 [DEVLINK_ATTR_PORT_INDEX
] = MNL_TYPE_U32
,
328 [DEVLINK_ATTR_PORT_TYPE
] = MNL_TYPE_U16
,
329 [DEVLINK_ATTR_PORT_DESIRED_TYPE
] = MNL_TYPE_U16
,
330 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX
] = MNL_TYPE_U32
,
331 [DEVLINK_ATTR_PORT_NETDEV_NAME
] = MNL_TYPE_NUL_STRING
,
332 [DEVLINK_ATTR_PORT_IBDEV_NAME
] = MNL_TYPE_NUL_STRING
,
333 [DEVLINK_ATTR_SB_INDEX
] = MNL_TYPE_U32
,
334 [DEVLINK_ATTR_SB_SIZE
] = MNL_TYPE_U32
,
335 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
336 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] = MNL_TYPE_U16
,
337 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] = MNL_TYPE_U16
,
338 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT
] = MNL_TYPE_U16
,
339 [DEVLINK_ATTR_SB_POOL_INDEX
] = MNL_TYPE_U16
,
340 [DEVLINK_ATTR_SB_POOL_TYPE
] = MNL_TYPE_U8
,
341 [DEVLINK_ATTR_SB_POOL_SIZE
] = MNL_TYPE_U32
,
342 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
] = MNL_TYPE_U8
,
343 [DEVLINK_ATTR_SB_THRESHOLD
] = MNL_TYPE_U32
,
344 [DEVLINK_ATTR_SB_TC_INDEX
] = MNL_TYPE_U16
,
345 [DEVLINK_ATTR_SB_OCC_CUR
] = MNL_TYPE_U32
,
346 [DEVLINK_ATTR_SB_OCC_MAX
] = MNL_TYPE_U32
,
347 [DEVLINK_ATTR_ESWITCH_MODE
] = MNL_TYPE_U16
,
348 [DEVLINK_ATTR_ESWITCH_INLINE_MODE
] = MNL_TYPE_U8
,
349 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE
] = MNL_TYPE_U8
,
350 [DEVLINK_ATTR_DPIPE_TABLES
] = MNL_TYPE_NESTED
,
351 [DEVLINK_ATTR_DPIPE_TABLE
] = MNL_TYPE_NESTED
,
352 [DEVLINK_ATTR_DPIPE_TABLE_NAME
] = MNL_TYPE_STRING
,
353 [DEVLINK_ATTR_DPIPE_TABLE_SIZE
] = MNL_TYPE_U64
,
354 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] = MNL_TYPE_NESTED
,
355 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] = MNL_TYPE_NESTED
,
356 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
] = MNL_TYPE_U8
,
357 [DEVLINK_ATTR_DPIPE_ENTRIES
] = MNL_TYPE_NESTED
,
358 [DEVLINK_ATTR_DPIPE_ENTRY
] = MNL_TYPE_NESTED
,
359 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] = MNL_TYPE_U64
,
360 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] = MNL_TYPE_NESTED
,
361 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
] = MNL_TYPE_NESTED
,
362 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
] = MNL_TYPE_U64
,
363 [DEVLINK_ATTR_DPIPE_MATCH
] = MNL_TYPE_NESTED
,
364 [DEVLINK_ATTR_DPIPE_MATCH_VALUE
] = MNL_TYPE_NESTED
,
365 [DEVLINK_ATTR_DPIPE_MATCH_TYPE
] = MNL_TYPE_U32
,
366 [DEVLINK_ATTR_DPIPE_ACTION
] = MNL_TYPE_NESTED
,
367 [DEVLINK_ATTR_DPIPE_ACTION_VALUE
] = MNL_TYPE_NESTED
,
368 [DEVLINK_ATTR_DPIPE_ACTION_TYPE
] = MNL_TYPE_U32
,
369 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING
] = MNL_TYPE_U32
,
370 [DEVLINK_ATTR_DPIPE_HEADERS
] = MNL_TYPE_NESTED
,
371 [DEVLINK_ATTR_DPIPE_HEADER
] = MNL_TYPE_NESTED
,
372 [DEVLINK_ATTR_DPIPE_HEADER_NAME
] = MNL_TYPE_STRING
,
373 [DEVLINK_ATTR_DPIPE_HEADER_ID
] = MNL_TYPE_U32
,
374 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS
] = MNL_TYPE_NESTED
,
375 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
] = MNL_TYPE_U8
,
376 [DEVLINK_ATTR_DPIPE_HEADER_INDEX
] = MNL_TYPE_U32
,
377 [DEVLINK_ATTR_DPIPE_FIELD
] = MNL_TYPE_NESTED
,
378 [DEVLINK_ATTR_DPIPE_FIELD_NAME
] = MNL_TYPE_STRING
,
379 [DEVLINK_ATTR_DPIPE_FIELD_ID
] = MNL_TYPE_U32
,
380 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] = MNL_TYPE_U32
,
381 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
] = MNL_TYPE_U32
,
382 [DEVLINK_ATTR_PARAM
] = MNL_TYPE_NESTED
,
383 [DEVLINK_ATTR_PARAM_NAME
] = MNL_TYPE_STRING
,
384 [DEVLINK_ATTR_PARAM_TYPE
] = MNL_TYPE_U8
,
385 [DEVLINK_ATTR_PARAM_VALUES_LIST
] = MNL_TYPE_NESTED
,
386 [DEVLINK_ATTR_PARAM_VALUE
] = MNL_TYPE_NESTED
,
387 [DEVLINK_ATTR_PARAM_VALUE_CMODE
] = MNL_TYPE_U8
,
388 [DEVLINK_ATTR_REGION_NAME
] = MNL_TYPE_STRING
,
389 [DEVLINK_ATTR_REGION_SIZE
] = MNL_TYPE_U64
,
390 [DEVLINK_ATTR_REGION_SNAPSHOTS
] = MNL_TYPE_NESTED
,
391 [DEVLINK_ATTR_REGION_SNAPSHOT
] = MNL_TYPE_NESTED
,
392 [DEVLINK_ATTR_REGION_SNAPSHOT_ID
] = MNL_TYPE_U32
,
393 [DEVLINK_ATTR_REGION_CHUNKS
] = MNL_TYPE_NESTED
,
394 [DEVLINK_ATTR_REGION_CHUNK
] = MNL_TYPE_NESTED
,
395 [DEVLINK_ATTR_REGION_CHUNK_DATA
] = MNL_TYPE_BINARY
,
396 [DEVLINK_ATTR_REGION_CHUNK_ADDR
] = MNL_TYPE_U64
,
397 [DEVLINK_ATTR_REGION_CHUNK_LEN
] = MNL_TYPE_U64
,
398 [DEVLINK_ATTR_INFO_DRIVER_NAME
] = MNL_TYPE_STRING
,
399 [DEVLINK_ATTR_INFO_SERIAL_NUMBER
] = MNL_TYPE_STRING
,
400 [DEVLINK_ATTR_INFO_VERSION_FIXED
] = MNL_TYPE_NESTED
,
401 [DEVLINK_ATTR_INFO_VERSION_RUNNING
] = MNL_TYPE_NESTED
,
402 [DEVLINK_ATTR_INFO_VERSION_STORED
] = MNL_TYPE_NESTED
,
403 [DEVLINK_ATTR_INFO_VERSION_NAME
] = MNL_TYPE_STRING
,
404 [DEVLINK_ATTR_INFO_VERSION_VALUE
] = MNL_TYPE_STRING
,
405 [DEVLINK_ATTR_HEALTH_REPORTER
] = MNL_TYPE_NESTED
,
406 [DEVLINK_ATTR_HEALTH_REPORTER_NAME
] = MNL_TYPE_STRING
,
407 [DEVLINK_ATTR_HEALTH_REPORTER_STATE
] = MNL_TYPE_U8
,
408 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] = MNL_TYPE_U64
,
409 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] = MNL_TYPE_U64
,
410 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
] = MNL_TYPE_U64
,
411 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
] = MNL_TYPE_U64
,
414 static int attr_cb(const struct nlattr
*attr
, void *data
)
416 const struct nlattr
**tb
= data
;
419 if (mnl_attr_type_valid(attr
, DEVLINK_ATTR_MAX
) < 0)
422 type
= mnl_attr_get_type(attr
);
423 if (mnl_attr_validate(attr
, devlink_policy
[type
]) < 0)
430 static int ifname_map_cb(const struct nlmsghdr
*nlh
, void *data
)
432 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
433 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
434 struct dl
*dl
= data
;
435 struct ifname_map
*ifname_map
;
436 const char *bus_name
;
437 const char *dev_name
;
438 uint32_t port_ifindex
;
439 const char *port_ifname
;
441 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
442 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
443 !tb
[DEVLINK_ATTR_PORT_INDEX
])
446 if (!tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
449 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
450 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
451 port_ifindex
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
452 port_ifname
= mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]);
453 ifname_map
= ifname_map_alloc(bus_name
, dev_name
,
454 port_ifindex
, port_ifname
);
457 list_add(&ifname_map
->list
, &dl
->ifname_map_list
);
462 static void ifname_map_fini(struct dl
*dl
)
464 struct ifname_map
*ifname_map
, *tmp
;
466 list_for_each_entry_safe(ifname_map
, tmp
,
467 &dl
->ifname_map_list
, list
) {
468 list_del(&ifname_map
->list
);
469 ifname_map_free(ifname_map
);
473 static int ifname_map_init(struct dl
*dl
)
475 struct nlmsghdr
*nlh
;
478 INIT_LIST_HEAD(&dl
->ifname_map_list
);
480 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
,
481 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
483 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, ifname_map_cb
, dl
);
491 static int ifname_map_lookup(struct dl
*dl
, const char *ifname
,
492 char **p_bus_name
, char **p_dev_name
,
493 uint32_t *p_port_index
)
495 struct ifname_map
*ifname_map
;
497 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
498 if (strcmp(ifname
, ifname_map
->ifname
) == 0) {
499 *p_bus_name
= ifname_map
->bus_name
;
500 *p_dev_name
= ifname_map
->dev_name
;
501 *p_port_index
= ifname_map
->port_index
;
508 static int ifname_map_rev_lookup(struct dl
*dl
, const char *bus_name
,
509 const char *dev_name
, uint32_t port_index
,
512 struct ifname_map
*ifname_map
;
514 list_for_each_entry(ifname_map
, &dl
->ifname_map_list
, list
) {
515 if (strcmp(bus_name
, ifname_map
->bus_name
) == 0 &&
516 strcmp(dev_name
, ifname_map
->dev_name
) == 0 &&
517 port_index
== ifname_map
->port_index
) {
518 *p_ifname
= ifname_map
->ifname
;
525 static unsigned int strslashcount(char *str
)
527 unsigned int count
= 0;
530 while ((pos
= strchr(pos
, '/'))) {
537 static int strslashrsplit(char *str
, char **before
, char **after
)
541 slash
= strrchr(str
, '/');
550 static int strtouint64_t(const char *str
, uint64_t *p_val
)
553 unsigned long long int val
;
555 val
= strtoull(str
, &endptr
, 10);
556 if (endptr
== str
|| *endptr
!= '\0')
564 static int strtouint32_t(const char *str
, uint32_t *p_val
)
567 unsigned long int val
;
569 val
= strtoul(str
, &endptr
, 10);
570 if (endptr
== str
|| *endptr
!= '\0')
578 static int strtouint16_t(const char *str
, uint16_t *p_val
)
581 unsigned long int val
;
583 val
= strtoul(str
, &endptr
, 10);
584 if (endptr
== str
|| *endptr
!= '\0')
592 static int strtouint8_t(const char *str
, uint8_t *p_val
)
595 unsigned long int val
;
597 val
= strtoul(str
, &endptr
, 10);
598 if (endptr
== str
|| *endptr
!= '\0')
606 static int strtobool(const char *str
, bool *p_val
)
610 if (!strcmp(str
, "true") || !strcmp(str
, "1"))
612 else if (!strcmp(str
, "false") || !strcmp(str
, "0"))
620 static int __dl_argv_handle(char *str
, char **p_bus_name
, char **p_dev_name
)
622 strslashrsplit(str
, p_bus_name
, p_dev_name
);
626 static int dl_argv_handle(struct dl
*dl
, char **p_bus_name
, char **p_dev_name
)
628 char *str
= dl_argv_next(dl
);
631 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
634 if (strslashcount(str
) != 1) {
635 pr_err("Wrong devlink identification string format.\n");
636 pr_err("Expected \"bus_name/dev_name\".\n");
639 return __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
642 static int __dl_argv_handle_port(char *str
,
643 char **p_bus_name
, char **p_dev_name
,
644 uint32_t *p_port_index
)
650 err
= strslashrsplit(str
, &handlestr
, &portstr
);
652 pr_err("Port identification \"%s\" is invalid\n", str
);
655 err
= strtouint32_t(portstr
, p_port_index
);
657 pr_err("Port index \"%s\" is not a number or not within range\n",
661 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
663 pr_err("Port identification \"%s\" is invalid\n", str
);
669 static int __dl_argv_handle_port_ifname(struct dl
*dl
, char *str
,
670 char **p_bus_name
, char **p_dev_name
,
671 uint32_t *p_port_index
)
675 err
= ifname_map_lookup(dl
, str
, p_bus_name
, p_dev_name
,
678 pr_err("Netdevice \"%s\" not found\n", str
);
684 static int dl_argv_handle_port(struct dl
*dl
, char **p_bus_name
,
685 char **p_dev_name
, uint32_t *p_port_index
)
687 char *str
= dl_argv_next(dl
);
688 unsigned int slash_count
;
691 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
694 slash_count
= strslashcount(str
);
695 switch (slash_count
) {
697 return __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
698 p_dev_name
, p_port_index
);
700 return __dl_argv_handle_port(str
, p_bus_name
,
701 p_dev_name
, p_port_index
);
703 pr_err("Wrong port identification string format.\n");
704 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
709 static int dl_argv_handle_both(struct dl
*dl
, char **p_bus_name
,
710 char **p_dev_name
, uint32_t *p_port_index
,
711 uint32_t *p_handle_bit
)
713 char *str
= dl_argv_next(dl
);
714 unsigned int slash_count
;
718 pr_err("One of following identifications expected:\n"
719 "Devlink identification (\"bus_name/dev_name\")\n"
720 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
723 slash_count
= strslashcount(str
);
724 if (slash_count
== 1) {
725 err
= __dl_argv_handle(str
, p_bus_name
, p_dev_name
);
728 *p_handle_bit
= DL_OPT_HANDLE
;
729 } else if (slash_count
== 2) {
730 err
= __dl_argv_handle_port(str
, p_bus_name
,
731 p_dev_name
, p_port_index
);
734 *p_handle_bit
= DL_OPT_HANDLEP
;
735 } else if (slash_count
== 0) {
736 err
= __dl_argv_handle_port_ifname(dl
, str
, p_bus_name
,
737 p_dev_name
, p_port_index
);
740 *p_handle_bit
= DL_OPT_HANDLEP
;
742 pr_err("Wrong port identification string format.\n");
743 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
749 static int __dl_argv_handle_region(char *str
, char **p_bus_name
,
750 char **p_dev_name
, char **p_region
)
755 err
= strslashrsplit(str
, &handlestr
, p_region
);
757 pr_err("Region identification \"%s\" is invalid\n", str
);
760 err
= strslashrsplit(handlestr
, p_bus_name
, p_dev_name
);
762 pr_err("Region identification \"%s\" is invalid\n", str
);
768 static int dl_argv_handle_region(struct dl
*dl
, char **p_bus_name
,
769 char **p_dev_name
, char **p_region
)
771 char *str
= dl_argv_next(dl
);
772 unsigned int slash_count
;
775 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
779 slash_count
= strslashcount(str
);
780 if (slash_count
!= 2) {
781 pr_err("Wrong region identification string format.\n");
782 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
786 return __dl_argv_handle_region(str
, p_bus_name
, p_dev_name
, p_region
);
789 static int dl_argv_uint64_t(struct dl
*dl
, uint64_t *p_val
)
791 char *str
= dl_argv_next(dl
);
795 pr_err("Unsigned number argument expected\n");
799 err
= strtouint64_t(str
, p_val
);
801 pr_err("\"%s\" is not a number or not within range\n", str
);
807 static int dl_argv_uint32_t(struct dl
*dl
, uint32_t *p_val
)
809 char *str
= dl_argv_next(dl
);
813 pr_err("Unsigned number argument expected\n");
817 err
= strtouint32_t(str
, p_val
);
819 pr_err("\"%s\" is not a number or not within range\n", str
);
825 static int dl_argv_uint16_t(struct dl
*dl
, uint16_t *p_val
)
827 char *str
= dl_argv_next(dl
);
831 pr_err("Unsigned number argument expected\n");
835 err
= strtouint16_t(str
, p_val
);
837 pr_err("\"%s\" is not a number or not within range\n", str
);
843 static int dl_argv_str(struct dl
*dl
, const char **p_str
)
845 const char *str
= dl_argv_next(dl
);
848 pr_err("String parameter expected\n");
855 static int port_type_get(const char *typestr
, enum devlink_port_type
*p_type
)
857 if (strcmp(typestr
, "auto") == 0) {
858 *p_type
= DEVLINK_PORT_TYPE_AUTO
;
859 } else if (strcmp(typestr
, "eth") == 0) {
860 *p_type
= DEVLINK_PORT_TYPE_ETH
;
861 } else if (strcmp(typestr
, "ib") == 0) {
862 *p_type
= DEVLINK_PORT_TYPE_IB
;
864 pr_err("Unknown port type \"%s\"\n", typestr
);
870 static int pool_type_get(const char *typestr
, enum devlink_sb_pool_type
*p_type
)
872 if (strcmp(typestr
, "ingress") == 0) {
873 *p_type
= DEVLINK_SB_POOL_TYPE_INGRESS
;
874 } else if (strcmp(typestr
, "egress") == 0) {
875 *p_type
= DEVLINK_SB_POOL_TYPE_EGRESS
;
877 pr_err("Unknown pool type \"%s\"\n", typestr
);
883 static int threshold_type_get(const char *typestr
,
884 enum devlink_sb_threshold_type
*p_type
)
886 if (strcmp(typestr
, "static") == 0) {
887 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_STATIC
;
888 } else if (strcmp(typestr
, "dynamic") == 0) {
889 *p_type
= DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
;
891 pr_err("Unknown threshold type \"%s\"\n", typestr
);
897 static int eswitch_mode_get(const char *typestr
,
898 enum devlink_eswitch_mode
*p_mode
)
900 if (strcmp(typestr
, ESWITCH_MODE_LEGACY
) == 0) {
901 *p_mode
= DEVLINK_ESWITCH_MODE_LEGACY
;
902 } else if (strcmp(typestr
, ESWITCH_MODE_SWITCHDEV
) == 0) {
903 *p_mode
= DEVLINK_ESWITCH_MODE_SWITCHDEV
;
905 pr_err("Unknown eswitch mode \"%s\"\n", typestr
);
911 static int eswitch_inline_mode_get(const char *typestr
,
912 enum devlink_eswitch_inline_mode
*p_mode
)
914 if (strcmp(typestr
, ESWITCH_INLINE_MODE_NONE
) == 0) {
915 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NONE
;
916 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_LINK
) == 0) {
917 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_LINK
;
918 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_NETWORK
) == 0) {
919 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_NETWORK
;
920 } else if (strcmp(typestr
, ESWITCH_INLINE_MODE_TRANSPORT
) == 0) {
921 *p_mode
= DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
;
923 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr
);
929 static int dpipe_counters_enable_get(const char *typestr
,
930 bool *counters_enable
)
932 if (strcmp(typestr
, "enable") == 0) {
933 *counters_enable
= 1;
934 } else if (strcmp(typestr
, "disable") == 0) {
935 *counters_enable
= 0;
937 pr_err("Unknown counter_state \"%s\"\n", typestr
);
943 static int eswitch_encap_mode_get(const char *typestr
, bool *p_mode
)
945 if (strcmp(typestr
, "enable") == 0) {
947 } else if (strcmp(typestr
, "disable") == 0) {
950 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr
);
956 static int param_cmode_get(const char *cmodestr
,
957 enum devlink_param_cmode
*cmode
)
959 if (strcmp(cmodestr
, PARAM_CMODE_RUNTIME_STR
) == 0) {
960 *cmode
= DEVLINK_PARAM_CMODE_RUNTIME
;
961 } else if (strcmp(cmodestr
, PARAM_CMODE_DRIVERINIT_STR
) == 0) {
962 *cmode
= DEVLINK_PARAM_CMODE_DRIVERINIT
;
963 } else if (strcmp(cmodestr
, PARAM_CMODE_PERMANENT_STR
) == 0) {
964 *cmode
= DEVLINK_PARAM_CMODE_PERMANENT
;
966 pr_err("Unknown configuration mode \"%s\"\n", cmodestr
);
972 struct dl_args_metadata
{
974 char err_msg
[DL_ARGS_REQUIRED_MAX_ERR_LEN
];
977 static const struct dl_args_metadata dl_args_required
[] = {
978 {DL_OPT_PORT_TYPE
, "Port type not set."},
979 {DL_OPT_PORT_COUNT
, "Port split count option expected."},
980 {DL_OPT_SB_POOL
, "Pool index option expected."},
981 {DL_OPT_SB_SIZE
, "Pool size option expected."},
982 {DL_OPT_SB_TYPE
, "Pool type option expected."},
983 {DL_OPT_SB_THTYPE
, "Pool threshold type option expected."},
984 {DL_OPT_SB_TH
, "Threshold option expected."},
985 {DL_OPT_SB_TC
, "TC index option expected."},
986 {DL_OPT_ESWITCH_MODE
, "E-Switch mode option expected."},
987 {DL_OPT_ESWITCH_INLINE_MODE
, "E-Switch inline-mode option expected."},
988 {DL_OPT_DPIPE_TABLE_NAME
, "Dpipe table name expected."},
989 {DL_OPT_DPIPE_TABLE_COUNTERS
, "Dpipe table counter state expected."},
990 {DL_OPT_ESWITCH_ENCAP_MODE
, "E-Switch encapsulation option expected."},
991 {DL_OPT_PARAM_NAME
, "Parameter name expected."},
992 {DL_OPT_PARAM_VALUE
, "Value to set expected."},
993 {DL_OPT_PARAM_CMODE
, "Configuration mode expected."},
994 {DL_OPT_REGION_SNAPSHOT_ID
, "Region snapshot id expected."},
995 {DL_OPT_REGION_ADDRESS
, "Region address value expected."},
996 {DL_OPT_REGION_LENGTH
, "Region length value expected."},
997 {DL_OPT_HEALTH_REPORTER_NAME
, "Reporter's name is expected."},
1000 static int dl_args_finding_required_validate(uint32_t o_required
,
1006 for (i
= 0; i
< ARRAY_SIZE(dl_args_required
); i
++) {
1007 o_flag
= dl_args_required
[i
].o_flag
;
1008 if ((o_required
& o_flag
) && !(o_found
& o_flag
)) {
1009 pr_err("%s\n", dl_args_required
[i
].err_msg
);
1016 static int dl_argv_parse(struct dl
*dl
, uint32_t o_required
,
1017 uint32_t o_optional
)
1019 struct dl_opts
*opts
= &dl
->opts
;
1020 uint32_t o_all
= o_required
| o_optional
;
1021 uint32_t o_found
= 0;
1024 if (o_required
& DL_OPT_HANDLE
&& o_required
& DL_OPT_HANDLEP
) {
1025 uint32_t handle_bit
;
1027 err
= dl_argv_handle_both(dl
, &opts
->bus_name
, &opts
->dev_name
,
1028 &opts
->port_index
, &handle_bit
);
1031 o_found
|= handle_bit
;
1032 } else if (o_required
& DL_OPT_HANDLE
) {
1033 err
= dl_argv_handle(dl
, &opts
->bus_name
, &opts
->dev_name
);
1036 o_found
|= DL_OPT_HANDLE
;
1037 } else if (o_required
& DL_OPT_HANDLEP
) {
1038 err
= dl_argv_handle_port(dl
, &opts
->bus_name
, &opts
->dev_name
,
1042 o_found
|= DL_OPT_HANDLEP
;
1043 } else if (o_required
& DL_OPT_HANDLE_REGION
) {
1044 err
= dl_argv_handle_region(dl
, &opts
->bus_name
,
1046 &opts
->region_name
);
1049 o_found
|= DL_OPT_HANDLE_REGION
;
1052 while (dl_argc(dl
)) {
1053 if (dl_argv_match(dl
, "type") &&
1054 (o_all
& DL_OPT_PORT_TYPE
)) {
1055 const char *typestr
;
1058 err
= dl_argv_str(dl
, &typestr
);
1061 err
= port_type_get(typestr
, &opts
->port_type
);
1064 o_found
|= DL_OPT_PORT_TYPE
;
1065 } else if (dl_argv_match(dl
, "count") &&
1066 (o_all
& DL_OPT_PORT_COUNT
)) {
1068 err
= dl_argv_uint32_t(dl
, &opts
->port_count
);
1071 o_found
|= DL_OPT_PORT_COUNT
;
1072 } else if (dl_argv_match(dl
, "sb") &&
1073 (o_all
& DL_OPT_SB
)) {
1075 err
= dl_argv_uint32_t(dl
, &opts
->sb_index
);
1078 o_found
|= DL_OPT_SB
;
1079 } else if (dl_argv_match(dl
, "pool") &&
1080 (o_all
& DL_OPT_SB_POOL
)) {
1082 err
= dl_argv_uint16_t(dl
, &opts
->sb_pool_index
);
1085 o_found
|= DL_OPT_SB_POOL
;
1086 } else if (dl_argv_match(dl
, "size") &&
1087 (o_all
& DL_OPT_SB_SIZE
)) {
1089 err
= dl_argv_uint32_t(dl
, &opts
->sb_pool_size
);
1092 o_found
|= DL_OPT_SB_SIZE
;
1093 } else if (dl_argv_match(dl
, "type") &&
1094 (o_all
& DL_OPT_SB_TYPE
)) {
1095 const char *typestr
;
1098 err
= dl_argv_str(dl
, &typestr
);
1101 err
= pool_type_get(typestr
, &opts
->sb_pool_type
);
1104 o_found
|= DL_OPT_SB_TYPE
;
1105 } else if (dl_argv_match(dl
, "thtype") &&
1106 (o_all
& DL_OPT_SB_THTYPE
)) {
1107 const char *typestr
;
1110 err
= dl_argv_str(dl
, &typestr
);
1113 err
= threshold_type_get(typestr
,
1114 &opts
->sb_pool_thtype
);
1117 o_found
|= DL_OPT_SB_THTYPE
;
1118 } else if (dl_argv_match(dl
, "th") &&
1119 (o_all
& DL_OPT_SB_TH
)) {
1121 err
= dl_argv_uint32_t(dl
, &opts
->sb_threshold
);
1124 o_found
|= DL_OPT_SB_TH
;
1125 } else if (dl_argv_match(dl
, "tc") &&
1126 (o_all
& DL_OPT_SB_TC
)) {
1128 err
= dl_argv_uint16_t(dl
, &opts
->sb_tc_index
);
1131 o_found
|= DL_OPT_SB_TC
;
1132 } else if (dl_argv_match(dl
, "mode") &&
1133 (o_all
& DL_OPT_ESWITCH_MODE
)) {
1134 const char *typestr
;
1137 err
= dl_argv_str(dl
, &typestr
);
1140 err
= eswitch_mode_get(typestr
, &opts
->eswitch_mode
);
1143 o_found
|= DL_OPT_ESWITCH_MODE
;
1144 } else if (dl_argv_match(dl
, "inline-mode") &&
1145 (o_all
& DL_OPT_ESWITCH_INLINE_MODE
)) {
1146 const char *typestr
;
1149 err
= dl_argv_str(dl
, &typestr
);
1152 err
= eswitch_inline_mode_get(
1153 typestr
, &opts
->eswitch_inline_mode
);
1156 o_found
|= DL_OPT_ESWITCH_INLINE_MODE
;
1157 } else if (dl_argv_match(dl
, "name") &&
1158 (o_all
& DL_OPT_DPIPE_TABLE_NAME
)) {
1160 err
= dl_argv_str(dl
, &opts
->dpipe_table_name
);
1163 o_found
|= DL_OPT_DPIPE_TABLE_NAME
;
1164 } else if (dl_argv_match(dl
, "counters") &&
1165 (o_all
& DL_OPT_DPIPE_TABLE_COUNTERS
)) {
1166 const char *typestr
;
1169 err
= dl_argv_str(dl
, &typestr
);
1172 err
= dpipe_counters_enable_get(typestr
,
1173 &opts
->dpipe_counters_enable
);
1176 o_found
|= DL_OPT_DPIPE_TABLE_COUNTERS
;
1177 } else if (dl_argv_match(dl
, "encap") &&
1178 (o_all
& DL_OPT_ESWITCH_ENCAP_MODE
)) {
1179 const char *typestr
;
1182 err
= dl_argv_str(dl
, &typestr
);
1185 err
= eswitch_encap_mode_get(typestr
,
1186 &opts
->eswitch_encap_mode
);
1189 o_found
|= DL_OPT_ESWITCH_ENCAP_MODE
;
1190 } else if (dl_argv_match(dl
, "path") &&
1191 (o_all
& DL_OPT_RESOURCE_PATH
)) {
1193 err
= dl_argv_str(dl
, &opts
->resource_path
);
1196 o_found
|= DL_OPT_RESOURCE_PATH
;
1197 } else if (dl_argv_match(dl
, "size") &&
1198 (o_all
& DL_OPT_RESOURCE_SIZE
)) {
1200 err
= dl_argv_uint32_t(dl
, &opts
->resource_size
);
1203 o_found
|= DL_OPT_RESOURCE_SIZE
;
1204 } else if (dl_argv_match(dl
, "name") &&
1205 (o_all
& DL_OPT_PARAM_NAME
)) {
1207 err
= dl_argv_str(dl
, &opts
->param_name
);
1210 o_found
|= DL_OPT_PARAM_NAME
;
1211 } else if (dl_argv_match(dl
, "value") &&
1212 (o_all
& DL_OPT_PARAM_VALUE
)) {
1214 err
= dl_argv_str(dl
, &opts
->param_value
);
1217 o_found
|= DL_OPT_PARAM_VALUE
;
1218 } else if (dl_argv_match(dl
, "cmode") &&
1219 (o_all
& DL_OPT_PARAM_CMODE
)) {
1220 const char *cmodestr
;
1223 err
= dl_argv_str(dl
, &cmodestr
);
1226 err
= param_cmode_get(cmodestr
, &opts
->cmode
);
1229 o_found
|= DL_OPT_PARAM_CMODE
;
1230 } else if (dl_argv_match(dl
, "snapshot") &&
1231 (o_all
& DL_OPT_REGION_SNAPSHOT_ID
)) {
1233 err
= dl_argv_uint32_t(dl
, &opts
->region_snapshot_id
);
1236 o_found
|= DL_OPT_REGION_SNAPSHOT_ID
;
1237 } else if (dl_argv_match(dl
, "address") &&
1238 (o_all
& DL_OPT_REGION_ADDRESS
)) {
1240 err
= dl_argv_uint64_t(dl
, &opts
->region_address
);
1243 o_found
|= DL_OPT_REGION_ADDRESS
;
1244 } else if (dl_argv_match(dl
, "length") &&
1245 (o_all
& DL_OPT_REGION_LENGTH
)) {
1247 err
= dl_argv_uint64_t(dl
, &opts
->region_length
);
1250 o_found
|= DL_OPT_REGION_LENGTH
;
1251 } else if (dl_argv_match(dl
, "file") &&
1252 (o_all
& DL_OPT_FLASH_FILE_NAME
)) {
1254 err
= dl_argv_str(dl
, &opts
->flash_file_name
);
1257 o_found
|= DL_OPT_FLASH_FILE_NAME
;
1258 } else if (dl_argv_match(dl
, "component") &&
1259 (o_all
& DL_OPT_FLASH_COMPONENT
)) {
1261 err
= dl_argv_str(dl
, &opts
->flash_component
);
1264 o_found
|= DL_OPT_FLASH_COMPONENT
;
1265 } else if (dl_argv_match(dl
, "reporter") &&
1266 (o_all
& DL_OPT_HEALTH_REPORTER_NAME
)) {
1268 err
= dl_argv_str(dl
, &opts
->reporter_name
);
1271 o_found
|= DL_OPT_HEALTH_REPORTER_NAME
;
1273 pr_err("Unknown option \"%s\"\n", dl_argv(dl
));
1278 opts
->present
= o_found
;
1280 if ((o_optional
& DL_OPT_SB
) && !(o_found
& DL_OPT_SB
)) {
1282 opts
->present
|= DL_OPT_SB
;
1285 return dl_args_finding_required_validate(o_required
, o_found
);
1288 static void dl_opts_put(struct nlmsghdr
*nlh
, struct dl
*dl
)
1290 struct dl_opts
*opts
= &dl
->opts
;
1292 if (opts
->present
& DL_OPT_HANDLE
) {
1293 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1294 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1295 } else if (opts
->present
& DL_OPT_HANDLEP
) {
1296 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1297 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1298 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_INDEX
,
1300 } else if (opts
->present
& DL_OPT_HANDLE_REGION
) {
1301 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_BUS_NAME
, opts
->bus_name
);
1302 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DEV_NAME
, opts
->dev_name
);
1303 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_REGION_NAME
,
1306 if (opts
->present
& DL_OPT_PORT_TYPE
)
1307 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PORT_TYPE
,
1309 if (opts
->present
& DL_OPT_PORT_COUNT
)
1310 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PORT_SPLIT_COUNT
,
1312 if (opts
->present
& DL_OPT_SB
)
1313 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_INDEX
,
1315 if (opts
->present
& DL_OPT_SB_POOL
)
1316 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_POOL_INDEX
,
1317 opts
->sb_pool_index
);
1318 if (opts
->present
& DL_OPT_SB_SIZE
)
1319 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_POOL_SIZE
,
1320 opts
->sb_pool_size
);
1321 if (opts
->present
& DL_OPT_SB_TYPE
)
1322 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_TYPE
,
1323 opts
->sb_pool_type
);
1324 if (opts
->present
& DL_OPT_SB_THTYPE
)
1325 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
,
1326 opts
->sb_pool_thtype
);
1327 if (opts
->present
& DL_OPT_SB_TH
)
1328 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_SB_THRESHOLD
,
1329 opts
->sb_threshold
);
1330 if (opts
->present
& DL_OPT_SB_TC
)
1331 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_SB_TC_INDEX
,
1333 if (opts
->present
& DL_OPT_ESWITCH_MODE
)
1334 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_ESWITCH_MODE
,
1335 opts
->eswitch_mode
);
1336 if (opts
->present
& DL_OPT_ESWITCH_INLINE_MODE
)
1337 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_INLINE_MODE
,
1338 opts
->eswitch_inline_mode
);
1339 if (opts
->present
& DL_OPT_DPIPE_TABLE_NAME
)
1340 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_DPIPE_TABLE_NAME
,
1341 opts
->dpipe_table_name
);
1342 if (opts
->present
& DL_OPT_DPIPE_TABLE_COUNTERS
)
1343 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
,
1344 opts
->dpipe_counters_enable
);
1345 if (opts
->present
& DL_OPT_ESWITCH_ENCAP_MODE
)
1346 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_ESWITCH_ENCAP_MODE
,
1347 opts
->eswitch_encap_mode
);
1348 if ((opts
->present
& DL_OPT_RESOURCE_PATH
) && opts
->resource_id_valid
)
1349 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_ID
,
1351 if (opts
->present
& DL_OPT_RESOURCE_SIZE
)
1352 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_RESOURCE_SIZE
,
1353 opts
->resource_size
);
1354 if (opts
->present
& DL_OPT_PARAM_NAME
)
1355 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_NAME
,
1357 if (opts
->present
& DL_OPT_PARAM_CMODE
)
1358 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_CMODE
,
1360 if (opts
->present
& DL_OPT_REGION_SNAPSHOT_ID
)
1361 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_REGION_SNAPSHOT_ID
,
1362 opts
->region_snapshot_id
);
1363 if (opts
->present
& DL_OPT_REGION_ADDRESS
)
1364 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_ADDR
,
1365 opts
->region_address
);
1366 if (opts
->present
& DL_OPT_REGION_LENGTH
)
1367 mnl_attr_put_u64(nlh
, DEVLINK_ATTR_REGION_CHUNK_LEN
,
1368 opts
->region_length
);
1369 if (opts
->present
& DL_OPT_FLASH_FILE_NAME
)
1370 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME
,
1371 opts
->flash_file_name
);
1372 if (opts
->present
& DL_OPT_FLASH_COMPONENT
)
1373 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT
,
1374 opts
->flash_component
);
1375 if (opts
->present
& DL_OPT_HEALTH_REPORTER_NAME
)
1376 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_HEALTH_REPORTER_NAME
,
1377 opts
->reporter_name
);
1380 static int dl_argv_parse_put(struct nlmsghdr
*nlh
, struct dl
*dl
,
1381 uint32_t o_required
, uint32_t o_optional
)
1385 err
= dl_argv_parse(dl
, o_required
, o_optional
);
1388 dl_opts_put(nlh
, dl
);
1392 static bool dl_dump_filter(struct dl
*dl
, struct nlattr
**tb
)
1394 struct dl_opts
*opts
= &dl
->opts
;
1395 struct nlattr
*attr_bus_name
= tb
[DEVLINK_ATTR_BUS_NAME
];
1396 struct nlattr
*attr_dev_name
= tb
[DEVLINK_ATTR_DEV_NAME
];
1397 struct nlattr
*attr_port_index
= tb
[DEVLINK_ATTR_PORT_INDEX
];
1398 struct nlattr
*attr_sb_index
= tb
[DEVLINK_ATTR_SB_INDEX
];
1400 if (opts
->present
& DL_OPT_HANDLE
&&
1401 attr_bus_name
&& attr_dev_name
) {
1402 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1403 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1405 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1406 strcmp(dev_name
, opts
->dev_name
) != 0)
1409 if (opts
->present
& DL_OPT_HANDLEP
&&
1410 attr_bus_name
&& attr_dev_name
&& attr_port_index
) {
1411 const char *bus_name
= mnl_attr_get_str(attr_bus_name
);
1412 const char *dev_name
= mnl_attr_get_str(attr_dev_name
);
1413 uint32_t port_index
= mnl_attr_get_u32(attr_port_index
);
1415 if (strcmp(bus_name
, opts
->bus_name
) != 0 ||
1416 strcmp(dev_name
, opts
->dev_name
) != 0 ||
1417 port_index
!= opts
->port_index
)
1420 if (opts
->present
& DL_OPT_SB
&& attr_sb_index
) {
1421 uint32_t sb_index
= mnl_attr_get_u32(attr_sb_index
);
1423 if (sb_index
!= opts
->sb_index
)
1429 static void cmd_dev_help(void)
1431 pr_err("Usage: devlink dev show [ DEV ]\n");
1432 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1433 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1434 pr_err(" [ encap { disable | enable } ]\n");
1435 pr_err(" devlink dev eswitch show DEV\n");
1436 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1437 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1438 pr_err(" devlink dev reload DEV\n");
1439 pr_err(" devlink dev info [ DEV ]\n");
1440 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1443 static bool cmp_arr_last_handle(struct dl
*dl
, const char *bus_name
,
1444 const char *dev_name
)
1446 if (!dl
->arr_last
.present
)
1448 return strcmp(dl
->arr_last
.bus_name
, bus_name
) == 0 &&
1449 strcmp(dl
->arr_last
.dev_name
, dev_name
) == 0;
1452 static void arr_last_handle_set(struct dl
*dl
, const char *bus_name
,
1453 const char *dev_name
)
1455 dl
->arr_last
.present
= true;
1456 free(dl
->arr_last
.dev_name
);
1457 free(dl
->arr_last
.bus_name
);
1458 dl
->arr_last
.bus_name
= strdup(bus_name
);
1459 dl
->arr_last
.dev_name
= strdup(dev_name
);
1462 static bool should_arr_last_handle_start(struct dl
*dl
, const char *bus_name
,
1463 const char *dev_name
)
1465 return !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1468 static bool should_arr_last_handle_end(struct dl
*dl
, const char *bus_name
,
1469 const char *dev_name
)
1471 return dl
->arr_last
.present
&&
1472 !cmp_arr_last_handle(dl
, bus_name
, dev_name
);
1475 static void __pr_out_handle_start(struct dl
*dl
, struct nlattr
**tb
,
1476 bool content
, bool array
)
1478 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1479 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1482 sprintf(buf
, "%s/%s", bus_name
, dev_name
);
1484 if (dl
->json_output
) {
1486 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1487 jsonw_end_array(dl
->jw
);
1488 if (should_arr_last_handle_start(dl
, bus_name
,
1490 jsonw_name(dl
->jw
, buf
);
1491 jsonw_start_array(dl
->jw
);
1492 jsonw_start_object(dl
->jw
);
1493 arr_last_handle_set(dl
, bus_name
, dev_name
);
1495 jsonw_start_object(dl
->jw
);
1498 jsonw_name(dl
->jw
, buf
);
1499 jsonw_start_object(dl
->jw
);
1503 if (should_arr_last_handle_end(dl
, bus_name
, dev_name
))
1504 __pr_out_indent_dec();
1505 if (should_arr_last_handle_start(dl
, bus_name
,
1507 pr_out("%s%s", buf
, content
? ":" : "");
1509 __pr_out_indent_inc();
1510 arr_last_handle_set(dl
, bus_name
, dev_name
);
1513 pr_out("%s%s", buf
, content
? ":" : "");
1518 static void pr_out_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
)
1520 __pr_out_handle_start(dl
, tb
, true, true);
1523 static void pr_out_handle_end(struct dl
*dl
)
1525 if (dl
->json_output
)
1526 jsonw_end_object(dl
->jw
);
1531 static void pr_out_handle(struct dl
*dl
, struct nlattr
**tb
)
1533 __pr_out_handle_start(dl
, tb
, false, false);
1534 pr_out_handle_end(dl
);
1537 static bool cmp_arr_last_port_handle(struct dl
*dl
, const char *bus_name
,
1538 const char *dev_name
, uint32_t port_index
)
1540 return cmp_arr_last_handle(dl
, bus_name
, dev_name
) &&
1541 dl
->arr_last
.port_index
== port_index
;
1544 static void arr_last_port_handle_set(struct dl
*dl
, const char *bus_name
,
1545 const char *dev_name
, uint32_t port_index
)
1547 arr_last_handle_set(dl
, bus_name
, dev_name
);
1548 dl
->arr_last
.port_index
= port_index
;
1551 static bool should_arr_last_port_handle_start(struct dl
*dl
,
1552 const char *bus_name
,
1553 const char *dev_name
,
1554 uint32_t port_index
)
1556 return !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1559 static bool should_arr_last_port_handle_end(struct dl
*dl
,
1560 const char *bus_name
,
1561 const char *dev_name
,
1562 uint32_t port_index
)
1564 return dl
->arr_last
.present
&&
1565 !cmp_arr_last_port_handle(dl
, bus_name
, dev_name
, port_index
);
1568 static void __pr_out_port_handle_start(struct dl
*dl
, const char *bus_name
,
1569 const char *dev_name
,
1570 uint32_t port_index
, bool try_nice
,
1573 static char buf
[32];
1574 char *ifname
= NULL
;
1576 if (dl
->no_nice_names
|| !try_nice
||
1577 ifname_map_rev_lookup(dl
, bus_name
, dev_name
,
1578 port_index
, &ifname
) != 0)
1579 sprintf(buf
, "%s/%s/%d", bus_name
, dev_name
, port_index
);
1581 sprintf(buf
, "%s", ifname
);
1583 if (dl
->json_output
) {
1585 if (should_arr_last_port_handle_end(dl
, bus_name
,
1588 jsonw_end_array(dl
->jw
);
1589 if (should_arr_last_port_handle_start(dl
, bus_name
,
1592 jsonw_name(dl
->jw
, buf
);
1593 jsonw_start_array(dl
->jw
);
1594 jsonw_start_object(dl
->jw
);
1595 arr_last_port_handle_set(dl
, bus_name
, dev_name
,
1598 jsonw_start_object(dl
->jw
);
1601 jsonw_name(dl
->jw
, buf
);
1602 jsonw_start_object(dl
->jw
);
1609 static void pr_out_port_handle_start(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1611 const char *bus_name
;
1612 const char *dev_name
;
1613 uint32_t port_index
;
1615 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1616 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1617 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1618 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, false);
1621 static void pr_out_port_handle_start_arr(struct dl
*dl
, struct nlattr
**tb
, bool try_nice
)
1623 const char *bus_name
;
1624 const char *dev_name
;
1625 uint32_t port_index
;
1627 bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
1628 dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
1629 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
1630 __pr_out_port_handle_start(dl
, bus_name
, dev_name
, port_index
, try_nice
, true);
1633 static void pr_out_port_handle_end(struct dl
*dl
)
1635 if (dl
->json_output
)
1636 jsonw_end_object(dl
->jw
);
1642 static void pr_out_str(struct dl
*dl
, const char *name
, const char *val
)
1644 if (dl
->json_output
) {
1645 jsonw_string_field(dl
->jw
, name
, val
);
1647 if (g_indent_newline
)
1648 pr_out("%s %s", name
, val
);
1650 pr_out(" %s %s", name
, val
);
1654 static void pr_out_bool(struct dl
*dl
, const char *name
, bool val
)
1656 if (dl
->json_output
)
1657 jsonw_bool_field(dl
->jw
, name
, val
);
1659 pr_out_str(dl
, name
, val
? "true" : "false");
1662 static void pr_out_uint(struct dl
*dl
, const char *name
, unsigned int val
)
1664 if (dl
->json_output
) {
1665 jsonw_uint_field(dl
->jw
, name
, val
);
1667 if (g_indent_newline
)
1668 pr_out("%s %u", name
, val
);
1670 pr_out(" %s %u", name
, val
);
1674 static void pr_out_u64(struct dl
*dl
, const char *name
, uint64_t val
)
1676 if (val
== (uint64_t) -1)
1677 return pr_out_str(dl
, name
, "unlimited");
1679 if (dl
->json_output
) {
1680 jsonw_u64_field(dl
->jw
, name
, val
);
1682 if (g_indent_newline
)
1683 pr_out("%s %lu", name
, val
);
1685 pr_out(" %s %lu", name
, val
);
1689 static void pr_out_bool_value(struct dl
*dl
, bool value
)
1691 if (dl
->json_output
)
1692 jsonw_bool(dl
->jw
, value
);
1694 pr_out(" %s", value
? "true" : "false");
1697 static void pr_out_uint_value(struct dl
*dl
, unsigned int value
)
1699 if (dl
->json_output
)
1700 jsonw_uint(dl
->jw
, value
);
1702 pr_out(" %u", value
);
1705 static void pr_out_uint64_value(struct dl
*dl
, uint64_t value
)
1707 if (dl
->json_output
)
1708 jsonw_u64(dl
->jw
, value
);
1710 pr_out(" %lu", value
);
1713 static void pr_out_binary_value(struct dl
*dl
, uint8_t *data
, uint32_t len
)
1717 if (dl
->json_output
)
1718 jsonw_start_array(dl
->jw
);
1723 if (dl
->json_output
) {
1724 jsonw_printf(dl
->jw
, "%d", data
[i
]);
1726 pr_out(" %02x", data
[i
]);
1732 if (dl
->json_output
)
1733 jsonw_end_array(dl
->jw
);
1734 else if ((i
- 1) % 16)
1738 static void pr_out_str_value(struct dl
*dl
, const char *value
)
1740 if (dl
->json_output
)
1741 jsonw_string(dl
->jw
, value
);
1743 pr_out(" %s", value
);
1746 static void pr_out_name(struct dl
*dl
, const char *name
)
1748 if (dl
->json_output
)
1749 jsonw_name(dl
->jw
, name
);
1751 pr_out(" %s:", name
);
1754 static void pr_out_region_chunk_start(struct dl
*dl
, uint64_t addr
)
1756 if (dl
->json_output
) {
1757 jsonw_name(dl
->jw
, "address");
1758 jsonw_uint(dl
->jw
, addr
);
1759 jsonw_name(dl
->jw
, "data");
1760 jsonw_start_array(dl
->jw
);
1764 static void pr_out_region_chunk_end(struct dl
*dl
)
1766 if (dl
->json_output
)
1767 jsonw_end_array(dl
->jw
);
1770 static void pr_out_region_chunk(struct dl
*dl
, uint8_t *data
, uint32_t len
,
1773 static uint64_t align_val
;
1776 pr_out_region_chunk_start(dl
, addr
);
1778 if (!dl
->json_output
)
1779 if (!(align_val
% 16))
1780 pr_out("%s%016"PRIx64
" ",
1781 align_val
? "\n" : "",
1786 if (dl
->json_output
)
1787 jsonw_printf(dl
->jw
, "%d", data
[i
]);
1789 pr_out("%02x ", data
[i
]);
1794 pr_out_region_chunk_end(dl
);
1797 static void pr_out_dev(struct dl
*dl
, struct nlattr
**tb
)
1799 pr_out_handle(dl
, tb
);
1802 static void pr_out_section_start(struct dl
*dl
, const char *name
)
1804 if (dl
->json_output
) {
1805 jsonw_start_object(dl
->jw
);
1806 jsonw_name(dl
->jw
, name
);
1807 jsonw_start_object(dl
->jw
);
1811 static void pr_out_section_end(struct dl
*dl
)
1813 if (dl
->json_output
) {
1814 if (dl
->arr_last
.present
)
1815 jsonw_end_array(dl
->jw
);
1816 jsonw_end_object(dl
->jw
);
1817 jsonw_end_object(dl
->jw
);
1821 static void pr_out_array_start(struct dl
*dl
, const char *name
)
1823 if (dl
->json_output
) {
1824 jsonw_name(dl
->jw
, name
);
1825 jsonw_start_array(dl
->jw
);
1827 __pr_out_indent_inc();
1829 pr_out("%s:", name
);
1830 __pr_out_indent_inc();
1835 static void pr_out_array_end(struct dl
*dl
)
1837 if (dl
->json_output
) {
1838 jsonw_end_array(dl
->jw
);
1840 __pr_out_indent_dec();
1841 __pr_out_indent_dec();
1845 static void pr_out_object_start(struct dl
*dl
, const char *name
)
1847 if (dl
->json_output
) {
1848 jsonw_name(dl
->jw
, name
);
1849 jsonw_start_object(dl
->jw
);
1851 __pr_out_indent_inc();
1853 pr_out("%s:", name
);
1854 __pr_out_indent_inc();
1859 static void pr_out_object_end(struct dl
*dl
)
1861 if (dl
->json_output
) {
1862 jsonw_end_object(dl
->jw
);
1864 __pr_out_indent_dec();
1865 __pr_out_indent_dec();
1869 static void pr_out_entry_start(struct dl
*dl
)
1871 if (dl
->json_output
)
1872 jsonw_start_object(dl
->jw
);
1875 static void pr_out_entry_end(struct dl
*dl
)
1877 if (dl
->json_output
)
1878 jsonw_end_object(dl
->jw
);
1883 static const char *param_cmode_name(uint8_t cmode
)
1886 case DEVLINK_PARAM_CMODE_RUNTIME
:
1887 return PARAM_CMODE_RUNTIME_STR
;
1888 case DEVLINK_PARAM_CMODE_DRIVERINIT
:
1889 return PARAM_CMODE_DRIVERINIT_STR
;
1890 case DEVLINK_PARAM_CMODE_PERMANENT
:
1891 return PARAM_CMODE_PERMANENT_STR
;
1892 default: return "<unknown type>";
1896 static const char *eswitch_mode_name(uint32_t mode
)
1899 case DEVLINK_ESWITCH_MODE_LEGACY
: return ESWITCH_MODE_LEGACY
;
1900 case DEVLINK_ESWITCH_MODE_SWITCHDEV
: return ESWITCH_MODE_SWITCHDEV
;
1901 default: return "<unknown mode>";
1905 static const char *eswitch_inline_mode_name(uint32_t mode
)
1908 case DEVLINK_ESWITCH_INLINE_MODE_NONE
:
1909 return ESWITCH_INLINE_MODE_NONE
;
1910 case DEVLINK_ESWITCH_INLINE_MODE_LINK
:
1911 return ESWITCH_INLINE_MODE_LINK
;
1912 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK
:
1913 return ESWITCH_INLINE_MODE_NETWORK
;
1914 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT
:
1915 return ESWITCH_INLINE_MODE_TRANSPORT
;
1917 return "<unknown mode>";
1921 static void pr_out_eswitch(struct dl
*dl
, struct nlattr
**tb
)
1923 __pr_out_handle_start(dl
, tb
, true, false);
1925 if (tb
[DEVLINK_ATTR_ESWITCH_MODE
])
1926 pr_out_str(dl
, "mode",
1927 eswitch_mode_name(mnl_attr_get_u16(tb
[DEVLINK_ATTR_ESWITCH_MODE
])));
1929 if (tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])
1930 pr_out_str(dl
, "inline-mode",
1931 eswitch_inline_mode_name(mnl_attr_get_u8(
1932 tb
[DEVLINK_ATTR_ESWITCH_INLINE_MODE
])));
1934 if (tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]) {
1935 bool encap_mode
= !!mnl_attr_get_u8(tb
[DEVLINK_ATTR_ESWITCH_ENCAP_MODE
]);
1937 pr_out_str(dl
, "encap", encap_mode
? "enable" : "disable");
1940 pr_out_handle_end(dl
);
1943 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr
*nlh
, void *data
)
1945 struct dl
*dl
= data
;
1946 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
1947 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
1949 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
1950 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
1951 return MNL_CB_ERROR
;
1952 pr_out_eswitch(dl
, tb
);
1956 static int cmd_dev_eswitch_show(struct dl
*dl
)
1958 struct nlmsghdr
*nlh
;
1961 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_GET
,
1962 NLM_F_REQUEST
| NLM_F_ACK
);
1964 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
1968 pr_out_section_start(dl
, "dev");
1969 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_eswitch_show_cb
, dl
);
1970 pr_out_section_end(dl
);
1974 static int cmd_dev_eswitch_set(struct dl
*dl
)
1976 struct nlmsghdr
*nlh
;
1979 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_ESWITCH_SET
,
1980 NLM_F_REQUEST
| NLM_F_ACK
);
1982 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
,
1983 DL_OPT_ESWITCH_MODE
|
1984 DL_OPT_ESWITCH_INLINE_MODE
|
1985 DL_OPT_ESWITCH_ENCAP_MODE
);
1990 if (dl
->opts
.present
== 1) {
1991 pr_err("Need to set at least one option\n");
1995 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
1998 static int cmd_dev_eswitch(struct dl
*dl
)
2000 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2003 } else if (dl_argv_match(dl
, "set")) {
2005 return cmd_dev_eswitch_set(dl
);
2006 } else if (dl_argv_match(dl
, "show")) {
2008 return cmd_dev_eswitch_show(dl
);
2010 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2014 struct param_val_conv
{
2020 static bool param_val_conv_exists(const struct param_val_conv
*param_val_conv
,
2021 uint32_t len
, const char *name
)
2025 for (i
= 0; i
< len
; i
++)
2026 if (!strcmp(param_val_conv
[i
].name
, name
))
2033 param_val_conv_uint_get(const struct param_val_conv
*param_val_conv
,
2034 uint32_t len
, const char *name
, const char *vstr
,
2039 for (i
= 0; i
< len
; i
++)
2040 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2041 !strcmp(param_val_conv
[i
].vstr
, vstr
)) {
2042 *vuint
= param_val_conv
[i
].vuint
;
2050 param_val_conv_str_get(const struct param_val_conv
*param_val_conv
,
2051 uint32_t len
, const char *name
, uint32_t vuint
,
2056 for (i
= 0; i
< len
; i
++)
2057 if (!strcmp(param_val_conv
[i
].name
, name
) &&
2058 param_val_conv
[i
].vuint
== vuint
) {
2059 *vstr
= param_val_conv
[i
].vstr
;
2066 static const struct param_val_conv param_val_conv
[] = {
2068 .name
= "fw_load_policy",
2070 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER
,
2073 .name
= "fw_load_policy",
2075 .vuint
= DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH
,
2079 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2081 static void pr_out_param_value(struct dl
*dl
, const char *nla_name
,
2082 int nla_type
, struct nlattr
*nl
)
2084 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2085 struct nlattr
*val_attr
;
2090 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_value
);
2091 if (err
!= MNL_CB_OK
)
2094 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2095 (nla_type
!= MNL_TYPE_FLAG
&&
2096 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2099 pr_out_str(dl
, "cmode",
2100 param_cmode_name(mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
])));
2101 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2103 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2109 err
= param_val_conv_str_get(param_val_conv
,
2112 mnl_attr_get_u8(val_attr
),
2116 pr_out_str(dl
, "value", vstr
);
2118 pr_out_uint(dl
, "value", mnl_attr_get_u8(val_attr
));
2123 err
= param_val_conv_str_get(param_val_conv
,
2126 mnl_attr_get_u16(val_attr
),
2130 pr_out_str(dl
, "value", vstr
);
2132 pr_out_uint(dl
, "value", mnl_attr_get_u16(val_attr
));
2137 err
= param_val_conv_str_get(param_val_conv
,
2140 mnl_attr_get_u32(val_attr
),
2144 pr_out_str(dl
, "value", vstr
);
2146 pr_out_uint(dl
, "value", mnl_attr_get_u32(val_attr
));
2149 case MNL_TYPE_STRING
:
2150 pr_out_str(dl
, "value", mnl_attr_get_str(val_attr
));
2153 pr_out_bool(dl
, "value", val_attr
? true : false);
2158 static void pr_out_param(struct dl
*dl
, struct nlattr
**tb
, bool array
)
2160 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2161 struct nlattr
*param_value_attr
;
2162 const char *nla_name
;
2166 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2167 if (err
!= MNL_CB_OK
)
2169 if (!nla_param
[DEVLINK_ATTR_PARAM_NAME
] ||
2170 !nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2171 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2175 pr_out_handle_start_arr(dl
, tb
);
2177 __pr_out_handle_start(dl
, tb
, true, false);
2179 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2181 nla_name
= mnl_attr_get_str(nla_param
[DEVLINK_ATTR_PARAM_NAME
]);
2182 pr_out_str(dl
, "name", nla_name
);
2184 if (!nla_param
[DEVLINK_ATTR_PARAM_GENERIC
])
2185 pr_out_str(dl
, "type", "driver-specific");
2187 pr_out_str(dl
, "type", "generic");
2189 pr_out_array_start(dl
, "values");
2190 mnl_attr_for_each_nested(param_value_attr
,
2191 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2192 pr_out_entry_start(dl
);
2193 pr_out_param_value(dl
, nla_name
, nla_type
, param_value_attr
);
2194 pr_out_entry_end(dl
);
2196 pr_out_array_end(dl
);
2197 pr_out_handle_end(dl
);
2200 static int cmd_dev_param_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2202 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2203 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2204 struct dl
*dl
= data
;
2206 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2207 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2208 !tb
[DEVLINK_ATTR_PARAM
])
2209 return MNL_CB_ERROR
;
2210 pr_out_param(dl
, tb
, true);
2226 static int cmd_dev_param_set_cb(const struct nlmsghdr
*nlh
, void *data
)
2228 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2229 struct nlattr
*nla_param
[DEVLINK_ATTR_MAX
+ 1] = {};
2230 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2231 struct nlattr
*param_value_attr
;
2232 enum devlink_param_cmode cmode
;
2233 struct param_ctx
*ctx
= data
;
2234 struct dl
*dl
= ctx
->dl
;
2238 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2239 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2240 !tb
[DEVLINK_ATTR_PARAM
])
2241 return MNL_CB_ERROR
;
2243 err
= mnl_attr_parse_nested(tb
[DEVLINK_ATTR_PARAM
], attr_cb
, nla_param
);
2244 if (err
!= MNL_CB_OK
)
2245 return MNL_CB_ERROR
;
2247 if (!nla_param
[DEVLINK_ATTR_PARAM_TYPE
] ||
2248 !nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
])
2249 return MNL_CB_ERROR
;
2251 nla_type
= mnl_attr_get_u8(nla_param
[DEVLINK_ATTR_PARAM_TYPE
]);
2252 mnl_attr_for_each_nested(param_value_attr
,
2253 nla_param
[DEVLINK_ATTR_PARAM_VALUES_LIST
]) {
2254 struct nlattr
*nla_value
[DEVLINK_ATTR_MAX
+ 1] = {};
2255 struct nlattr
*val_attr
;
2257 err
= mnl_attr_parse_nested(param_value_attr
,
2258 attr_cb
, nla_value
);
2259 if (err
!= MNL_CB_OK
)
2260 return MNL_CB_ERROR
;
2262 if (!nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
] ||
2263 (nla_type
!= MNL_TYPE_FLAG
&&
2264 !nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
]))
2265 return MNL_CB_ERROR
;
2267 cmode
= mnl_attr_get_u8(nla_value
[DEVLINK_ATTR_PARAM_VALUE_CMODE
]);
2268 if (cmode
== dl
->opts
.cmode
) {
2269 val_attr
= nla_value
[DEVLINK_ATTR_PARAM_VALUE_DATA
];
2272 ctx
->value
.vu8
= mnl_attr_get_u8(val_attr
);
2275 ctx
->value
.vu16
= mnl_attr_get_u16(val_attr
);
2278 ctx
->value
.vu32
= mnl_attr_get_u32(val_attr
);
2280 case MNL_TYPE_STRING
:
2281 ctx
->value
.vstr
= mnl_attr_get_str(val_attr
);
2284 ctx
->value
.vbool
= val_attr
? true : false;
2290 ctx
->nla_type
= nla_type
;
2294 static int cmd_dev_param_set(struct dl
*dl
)
2296 struct param_ctx ctx
= {};
2297 struct nlmsghdr
*nlh
;
2305 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
|
2307 DL_OPT_PARAM_VALUE
|
2308 DL_OPT_PARAM_CMODE
, 0);
2312 /* Get value type */
2313 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
,
2314 NLM_F_REQUEST
| NLM_F_ACK
);
2315 dl_opts_put(nlh
, dl
);
2318 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_set_cb
, &ctx
);
2322 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_SET
,
2323 NLM_F_REQUEST
| NLM_F_ACK
);
2324 dl_opts_put(nlh
, dl
);
2326 conv_exists
= param_val_conv_exists(param_val_conv
, PARAM_VAL_CONV_LEN
,
2327 dl
->opts
.param_name
);
2329 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_TYPE
, ctx
.nla_type
);
2330 switch (ctx
.nla_type
) {
2333 err
= param_val_conv_uint_get(param_val_conv
,
2335 dl
->opts
.param_name
,
2336 dl
->opts
.param_value
,
2340 err
= strtouint8_t(dl
->opts
.param_value
, &val_u8
);
2343 goto err_param_value_parse
;
2344 if (val_u8
== ctx
.value
.vu8
)
2346 mnl_attr_put_u8(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u8
);
2350 err
= param_val_conv_uint_get(param_val_conv
,
2352 dl
->opts
.param_name
,
2353 dl
->opts
.param_value
,
2357 err
= strtouint16_t(dl
->opts
.param_value
, &val_u16
);
2360 goto err_param_value_parse
;
2361 if (val_u16
== ctx
.value
.vu16
)
2363 mnl_attr_put_u16(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u16
);
2367 err
= param_val_conv_uint_get(param_val_conv
,
2369 dl
->opts
.param_name
,
2370 dl
->opts
.param_value
,
2373 err
= strtouint32_t(dl
->opts
.param_value
, &val_u32
);
2375 goto err_param_value_parse
;
2376 if (val_u32
== ctx
.value
.vu32
)
2378 mnl_attr_put_u32(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
, val_u32
);
2381 err
= strtobool(dl
->opts
.param_value
, &val_bool
);
2383 goto err_param_value_parse
;
2384 if (val_bool
== ctx
.value
.vbool
)
2387 mnl_attr_put(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2390 case MNL_TYPE_STRING
:
2391 mnl_attr_put_strz(nlh
, DEVLINK_ATTR_PARAM_VALUE_DATA
,
2392 dl
->opts
.param_value
);
2393 if (!strcmp(dl
->opts
.param_value
, ctx
.value
.vstr
))
2397 printf("Value type not supported\n");
2400 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2402 err_param_value_parse
:
2403 pr_err("Value \"%s\" is not a number or not within range\n",
2404 dl
->opts
.param_value
);
2408 static int cmd_dev_param_show(struct dl
*dl
)
2410 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2411 struct nlmsghdr
*nlh
;
2414 if (dl_argc(dl
) == 0)
2415 flags
|= NLM_F_DUMP
;
2417 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PARAM_GET
, flags
);
2419 if (dl_argc(dl
) > 0) {
2420 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
|
2421 DL_OPT_PARAM_NAME
, 0);
2426 pr_out_section_start(dl
, "param");
2427 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_param_show_cb
, dl
);
2428 pr_out_section_end(dl
);
2432 static int cmd_dev_param(struct dl
*dl
)
2434 if (dl_argv_match(dl
, "help")) {
2437 } else if (dl_argv_match(dl
, "show") ||
2438 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2440 return cmd_dev_param_show(dl
);
2441 } else if (dl_argv_match(dl
, "set")) {
2443 return cmd_dev_param_set(dl
);
2445 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2448 static int cmd_dev_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2450 struct dl
*dl
= data
;
2451 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2452 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2454 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2455 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2456 return MNL_CB_ERROR
;
2461 static int cmd_dev_show(struct dl
*dl
)
2463 struct nlmsghdr
*nlh
;
2464 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2467 if (dl_argc(dl
) == 0)
2468 flags
|= NLM_F_DUMP
;
2470 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_GET
, flags
);
2472 if (dl_argc(dl
) > 0) {
2473 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2478 pr_out_section_start(dl
, "dev");
2479 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dev_show_cb
, dl
);
2480 pr_out_section_end(dl
);
2484 static void cmd_dev_reload_help(void)
2486 pr_err("Usage: devlink dev reload [ DEV ]\n");
2489 static int cmd_dev_reload(struct dl
*dl
)
2491 struct nlmsghdr
*nlh
;
2494 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2495 cmd_dev_reload_help();
2499 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RELOAD
,
2500 NLM_F_REQUEST
| NLM_F_ACK
);
2502 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2506 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2509 static void pr_out_versions_single(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2510 const char *name
, int type
)
2512 struct nlattr
*version
;
2514 mnl_attr_for_each(version
, nlh
, sizeof(struct genlmsghdr
)) {
2515 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2516 const char *ver_value
;
2517 const char *ver_name
;
2520 if (mnl_attr_get_type(version
) != type
)
2523 err
= mnl_attr_parse_nested(version
, attr_cb
, tb
);
2524 if (err
!= MNL_CB_OK
)
2527 if (!tb
[DEVLINK_ATTR_INFO_VERSION_NAME
] ||
2528 !tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
])
2532 pr_out_object_start(dl
, name
);
2536 ver_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_NAME
]);
2537 ver_value
= mnl_attr_get_str(tb
[DEVLINK_ATTR_INFO_VERSION_VALUE
]);
2539 pr_out_str(dl
, ver_name
, ver_value
);
2540 if (!dl
->json_output
)
2545 pr_out_object_end(dl
);
2548 static void pr_out_info(struct dl
*dl
, const struct nlmsghdr
*nlh
,
2549 struct nlattr
**tb
, bool has_versions
)
2551 __pr_out_handle_start(dl
, tb
, true, false);
2553 __pr_out_indent_inc();
2554 if (tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
]) {
2555 struct nlattr
*nla_drv
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
];
2557 if (!dl
->json_output
)
2559 pr_out_str(dl
, "driver", mnl_attr_get_str(nla_drv
));
2562 if (tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
]) {
2563 struct nlattr
*nla_sn
= tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
];
2565 if (!dl
->json_output
)
2567 pr_out_str(dl
, "serial_number", mnl_attr_get_str(nla_sn
));
2569 __pr_out_indent_dec();
2572 pr_out_object_start(dl
, "versions");
2574 pr_out_versions_single(dl
, nlh
, "fixed",
2575 DEVLINK_ATTR_INFO_VERSION_FIXED
);
2576 pr_out_versions_single(dl
, nlh
, "running",
2577 DEVLINK_ATTR_INFO_VERSION_RUNNING
);
2578 pr_out_versions_single(dl
, nlh
, "stored",
2579 DEVLINK_ATTR_INFO_VERSION_STORED
);
2581 pr_out_object_end(dl
);
2584 pr_out_handle_end(dl
);
2587 static int cmd_versions_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2589 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2590 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2591 bool has_versions
, has_info
;
2592 struct dl
*dl
= data
;
2594 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2596 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
2597 return MNL_CB_ERROR
;
2599 has_versions
= tb
[DEVLINK_ATTR_INFO_VERSION_FIXED
] ||
2600 tb
[DEVLINK_ATTR_INFO_VERSION_RUNNING
] ||
2601 tb
[DEVLINK_ATTR_INFO_VERSION_STORED
];
2602 has_info
= tb
[DEVLINK_ATTR_INFO_DRIVER_NAME
] ||
2603 tb
[DEVLINK_ATTR_INFO_SERIAL_NUMBER
] ||
2607 pr_out_info(dl
, nlh
, tb
, has_versions
);
2612 static void cmd_dev_info_help(void)
2614 pr_err("Usage: devlink dev info [ DEV ]\n");
2617 static int cmd_dev_info(struct dl
*dl
)
2619 struct nlmsghdr
*nlh
;
2620 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2623 if (dl_argv_match(dl
, "help")) {
2624 cmd_dev_info_help();
2628 if (dl_argc(dl
) == 0)
2629 flags
|= NLM_F_DUMP
;
2631 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_INFO_GET
, flags
);
2633 if (dl_argc(dl
) > 0) {
2634 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
2639 pr_out_section_start(dl
, "info");
2640 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_versions_show_cb
, dl
);
2641 pr_out_section_end(dl
);
2645 static void cmd_dev_flash_help(void)
2647 pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
2650 static int cmd_dev_flash(struct dl
*dl
)
2652 struct nlmsghdr
*nlh
;
2655 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
2656 cmd_dev_flash_help();
2660 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_FLASH_UPDATE
,
2661 NLM_F_REQUEST
| NLM_F_ACK
);
2663 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_FLASH_FILE_NAME
,
2664 DL_OPT_FLASH_COMPONENT
);
2668 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2671 static int cmd_dev(struct dl
*dl
)
2673 if (dl_argv_match(dl
, "help")) {
2676 } else if (dl_argv_match(dl
, "show") ||
2677 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2679 return cmd_dev_show(dl
);
2680 } else if (dl_argv_match(dl
, "eswitch")) {
2682 return cmd_dev_eswitch(dl
);
2683 } else if (dl_argv_match(dl
, "reload")) {
2685 return cmd_dev_reload(dl
);
2686 } else if (dl_argv_match(dl
, "param")) {
2688 return cmd_dev_param(dl
);
2689 } else if (dl_argv_match(dl
, "info")) {
2691 return cmd_dev_info(dl
);
2692 } else if (dl_argv_match(dl
, "flash")) {
2694 return cmd_dev_flash(dl
);
2696 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2700 static void cmd_port_help(void)
2702 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
2703 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
2704 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
2705 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
2708 static const char *port_type_name(uint32_t type
)
2711 case DEVLINK_PORT_TYPE_NOTSET
: return "notset";
2712 case DEVLINK_PORT_TYPE_AUTO
: return "auto";
2713 case DEVLINK_PORT_TYPE_ETH
: return "eth";
2714 case DEVLINK_PORT_TYPE_IB
: return "ib";
2715 default: return "<unknown type>";
2719 static const char *port_flavour_name(uint16_t flavour
)
2722 case DEVLINK_PORT_FLAVOUR_PHYSICAL
:
2724 case DEVLINK_PORT_FLAVOUR_CPU
:
2726 case DEVLINK_PORT_FLAVOUR_DSA
:
2729 return "<unknown flavour>";
2733 static void pr_out_port(struct dl
*dl
, struct nlattr
**tb
)
2735 struct nlattr
*pt_attr
= tb
[DEVLINK_ATTR_PORT_TYPE
];
2736 struct nlattr
*dpt_attr
= tb
[DEVLINK_ATTR_PORT_DESIRED_TYPE
];
2738 pr_out_port_handle_start(dl
, tb
, false);
2740 uint16_t port_type
= mnl_attr_get_u16(pt_attr
);
2742 pr_out_str(dl
, "type", port_type_name(port_type
));
2744 uint16_t des_port_type
= mnl_attr_get_u16(dpt_attr
);
2746 if (port_type
!= des_port_type
)
2747 pr_out_str(dl
, "des_type",
2748 port_type_name(des_port_type
));
2751 if (tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
])
2752 pr_out_str(dl
, "netdev",
2753 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_NETDEV_NAME
]));
2754 if (tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
])
2755 pr_out_str(dl
, "ibdev",
2756 mnl_attr_get_str(tb
[DEVLINK_ATTR_PORT_IBDEV_NAME
]));
2757 if (tb
[DEVLINK_ATTR_PORT_FLAVOUR
]) {
2758 uint16_t port_flavour
=
2759 mnl_attr_get_u16(tb
[DEVLINK_ATTR_PORT_FLAVOUR
]);
2761 pr_out_str(dl
, "flavour", port_flavour_name(port_flavour
));
2763 if (tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
])
2764 pr_out_uint(dl
, "split_group",
2765 mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_SPLIT_GROUP
]));
2766 pr_out_port_handle_end(dl
);
2769 static int cmd_port_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2771 struct dl
*dl
= data
;
2772 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2773 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2775 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2776 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2777 !tb
[DEVLINK_ATTR_PORT_INDEX
])
2778 return MNL_CB_ERROR
;
2779 pr_out_port(dl
, tb
);
2783 static int cmd_port_show(struct dl
*dl
)
2785 struct nlmsghdr
*nlh
;
2786 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2789 if (dl_argc(dl
) == 0)
2790 flags
|= NLM_F_DUMP
;
2792 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_GET
, flags
);
2794 if (dl_argc(dl
) > 0) {
2795 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
2800 pr_out_section_start(dl
, "port");
2801 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_port_show_cb
, dl
);
2802 pr_out_section_end(dl
);
2806 static int cmd_port_set(struct dl
*dl
)
2808 struct nlmsghdr
*nlh
;
2811 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SET
,
2812 NLM_F_REQUEST
| NLM_F_ACK
);
2814 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_TYPE
, 0);
2818 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2821 static int cmd_port_split(struct dl
*dl
)
2823 struct nlmsghdr
*nlh
;
2826 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_SPLIT
,
2827 NLM_F_REQUEST
| NLM_F_ACK
);
2829 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_PORT_COUNT
, 0);
2833 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2836 static int cmd_port_unsplit(struct dl
*dl
)
2838 struct nlmsghdr
*nlh
;
2841 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_PORT_UNSPLIT
,
2842 NLM_F_REQUEST
| NLM_F_ACK
);
2844 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
, 0);
2848 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
2851 static int cmd_port(struct dl
*dl
)
2853 if (dl_argv_match(dl
, "help")) {
2856 } else if (dl_argv_match(dl
, "show") ||
2857 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
2859 return cmd_port_show(dl
);
2860 } else if (dl_argv_match(dl
, "set")) {
2862 return cmd_port_set(dl
);
2863 } else if (dl_argv_match(dl
, "split")) {
2865 return cmd_port_split(dl
);
2866 } else if (dl_argv_match(dl
, "unsplit")) {
2868 return cmd_port_unsplit(dl
);
2870 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
2874 static void cmd_sb_help(void)
2876 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
2877 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
2878 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
2879 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
2880 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
2881 pr_err(" pool POOL_INDEX ]\n");
2882 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
2883 pr_err(" pool POOL_INDEX th THRESHOLD\n");
2884 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
2885 pr_err(" type { ingress | egress } ]\n");
2886 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
2887 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
2888 pr_err(" th THRESHOLD\n");
2889 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
2890 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
2891 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
2894 static void pr_out_sb(struct dl
*dl
, struct nlattr
**tb
)
2896 pr_out_handle_start_arr(dl
, tb
);
2897 pr_out_uint(dl
, "sb",
2898 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
2899 pr_out_uint(dl
, "size",
2900 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_SIZE
]));
2901 pr_out_uint(dl
, "ing_pools",
2902 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
]));
2903 pr_out_uint(dl
, "eg_pools",
2904 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
]));
2905 pr_out_uint(dl
, "ing_tcs",
2906 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
]));
2907 pr_out_uint(dl
, "eg_tcs",
2908 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
]));
2909 pr_out_handle_end(dl
);
2912 static int cmd_sb_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2914 struct dl
*dl
= data
;
2915 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2916 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2918 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2919 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2920 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_SIZE
] ||
2921 !tb
[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT
] ||
2922 !tb
[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT
] ||
2923 !tb
[DEVLINK_ATTR_SB_INGRESS_TC_COUNT
] ||
2924 !tb
[DEVLINK_ATTR_SB_EGRESS_TC_COUNT
])
2925 return MNL_CB_ERROR
;
2930 static int cmd_sb_show(struct dl
*dl
)
2932 struct nlmsghdr
*nlh
;
2933 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
2936 if (dl_argc(dl
) == 0)
2937 flags
|= NLM_F_DUMP
;
2939 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_GET
, flags
);
2941 if (dl_argc(dl
) > 0) {
2942 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
2947 pr_out_section_start(dl
, "sb");
2948 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_show_cb
, dl
);
2949 pr_out_section_end(dl
);
2953 static const char *pool_type_name(uint8_t type
)
2956 case DEVLINK_SB_POOL_TYPE_INGRESS
: return "ingress";
2957 case DEVLINK_SB_POOL_TYPE_EGRESS
: return "egress";
2958 default: return "<unknown type>";
2962 static const char *threshold_type_name(uint8_t type
)
2965 case DEVLINK_SB_THRESHOLD_TYPE_STATIC
: return "static";
2966 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC
: return "dynamic";
2967 default: return "<unknown type>";
2971 static void pr_out_sb_pool(struct dl
*dl
, struct nlattr
**tb
)
2973 pr_out_handle_start_arr(dl
, tb
);
2974 pr_out_uint(dl
, "sb",
2975 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
2976 pr_out_uint(dl
, "pool",
2977 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
2978 pr_out_str(dl
, "type",
2979 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
2980 pr_out_uint(dl
, "size",
2981 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_SIZE
]));
2982 pr_out_str(dl
, "thtype",
2983 threshold_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])));
2984 if (tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
])
2985 pr_out_uint(dl
, "cell_size",
2986 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_POOL_CELL_SIZE
]));
2987 pr_out_handle_end(dl
);
2990 static int cmd_sb_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
2992 struct dl
*dl
= data
;
2993 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
2994 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
2996 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
2997 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
2998 !tb
[DEVLINK_ATTR_SB_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
2999 !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] || !tb
[DEVLINK_ATTR_SB_POOL_SIZE
] ||
3000 !tb
[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE
])
3001 return MNL_CB_ERROR
;
3002 pr_out_sb_pool(dl
, tb
);
3006 static int cmd_sb_pool_show(struct dl
*dl
)
3008 struct nlmsghdr
*nlh
;
3009 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3012 if (dl_argc(dl
) == 0)
3013 flags
|= NLM_F_DUMP
;
3015 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_GET
, flags
);
3017 if (dl_argc(dl
) > 0) {
3018 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
,
3024 pr_out_section_start(dl
, "pool");
3025 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_pool_show_cb
, dl
);
3026 pr_out_section_end(dl
);
3030 static int cmd_sb_pool_set(struct dl
*dl
)
3032 struct nlmsghdr
*nlh
;
3035 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_POOL_SET
,
3036 NLM_F_REQUEST
| NLM_F_ACK
);
3038 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
| DL_OPT_SB_POOL
|
3039 DL_OPT_SB_SIZE
| DL_OPT_SB_THTYPE
, DL_OPT_SB
);
3043 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3046 static int cmd_sb_pool(struct dl
*dl
)
3048 if (dl_argv_match(dl
, "help")) {
3051 } else if (dl_argv_match(dl
, "show") ||
3052 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3054 return cmd_sb_pool_show(dl
);
3055 } else if (dl_argv_match(dl
, "set")) {
3057 return cmd_sb_pool_set(dl
);
3059 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3063 static void pr_out_sb_port_pool(struct dl
*dl
, struct nlattr
**tb
)
3065 pr_out_port_handle_start_arr(dl
, tb
, true);
3066 pr_out_uint(dl
, "sb",
3067 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3068 pr_out_uint(dl
, "pool",
3069 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3070 pr_out_uint(dl
, "threshold",
3071 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3072 pr_out_port_handle_end(dl
);
3075 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3077 struct dl
*dl
= data
;
3078 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3079 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3081 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3082 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3083 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3084 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3085 return MNL_CB_ERROR
;
3086 pr_out_sb_port_pool(dl
, tb
);
3090 static int cmd_sb_port_pool_show(struct dl
*dl
)
3092 struct nlmsghdr
*nlh
;
3093 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3096 if (dl_argc(dl
) == 0)
3097 flags
|= NLM_F_DUMP
;
3099 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3101 if (dl_argc(dl
) > 0) {
3102 err
= dl_argv_parse_put(nlh
, dl
,
3103 DL_OPT_HANDLEP
| DL_OPT_SB_POOL
,
3109 pr_out_section_start(dl
, "port_pool");
3110 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_port_pool_show_cb
, dl
);
3111 pr_out_section_end(dl
);
3115 static int cmd_sb_port_pool_set(struct dl
*dl
)
3117 struct nlmsghdr
*nlh
;
3120 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_SET
,
3121 NLM_F_REQUEST
| NLM_F_ACK
);
3123 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_POOL
|
3124 DL_OPT_SB_TH
, DL_OPT_SB
);
3128 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3131 static int cmd_sb_port_pool(struct dl
*dl
)
3133 if (dl_argv_match(dl
, "help")) {
3136 } else if (dl_argv_match(dl
, "show") ||
3137 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3139 return cmd_sb_port_pool_show(dl
);
3140 } else if (dl_argv_match(dl
, "set")) {
3142 return cmd_sb_port_pool_set(dl
);
3144 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3148 static int cmd_sb_port(struct dl
*dl
)
3150 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3153 } else if (dl_argv_match(dl
, "pool")) {
3155 return cmd_sb_port_pool(dl
);
3157 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3161 static void pr_out_sb_tc_bind(struct dl
*dl
, struct nlattr
**tb
)
3163 pr_out_port_handle_start_arr(dl
, tb
, true);
3164 pr_out_uint(dl
, "sb",
3165 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_INDEX
]));
3166 pr_out_uint(dl
, "tc",
3167 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]));
3168 pr_out_str(dl
, "type",
3169 pool_type_name(mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
])));
3170 pr_out_uint(dl
, "pool",
3171 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]));
3172 pr_out_uint(dl
, "threshold",
3173 mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_THRESHOLD
]));
3174 pr_out_port_handle_end(dl
);
3177 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3179 struct dl
*dl
= data
;
3180 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3181 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3183 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3184 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3185 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3186 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3187 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] || !tb
[DEVLINK_ATTR_SB_THRESHOLD
])
3188 return MNL_CB_ERROR
;
3189 pr_out_sb_tc_bind(dl
, tb
);
3193 static int cmd_sb_tc_bind_show(struct dl
*dl
)
3195 struct nlmsghdr
*nlh
;
3196 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
3199 if (dl_argc(dl
) == 0)
3200 flags
|= NLM_F_DUMP
;
3202 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3204 if (dl_argc(dl
) > 0) {
3205 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3206 DL_OPT_SB_TYPE
, DL_OPT_SB
);
3211 pr_out_section_start(dl
, "tc_bind");
3212 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_sb_tc_bind_show_cb
, dl
);
3213 pr_out_section_end(dl
);
3217 static int cmd_sb_tc_bind_set(struct dl
*dl
)
3219 struct nlmsghdr
*nlh
;
3222 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_SET
,
3223 NLM_F_REQUEST
| NLM_F_ACK
);
3225 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLEP
| DL_OPT_SB_TC
|
3226 DL_OPT_SB_TYPE
| DL_OPT_SB_POOL
| DL_OPT_SB_TH
,
3231 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3234 static int cmd_sb_tc_bind(struct dl
*dl
)
3236 if (dl_argv_match(dl
, "help")) {
3239 } else if (dl_argv_match(dl
, "show") ||
3240 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3242 return cmd_sb_tc_bind_show(dl
);
3243 } else if (dl_argv_match(dl
, "set")) {
3245 return cmd_sb_tc_bind_set(dl
);
3247 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3251 static int cmd_sb_tc(struct dl
*dl
)
3253 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3256 } else if (dl_argv_match(dl
, "bind")) {
3258 return cmd_sb_tc_bind(dl
);
3260 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3265 struct list_head list
;
3269 uint32_t bound_pool_index
;
3273 struct list_head list
;
3276 uint32_t port_index
;
3278 struct list_head pool_list
;
3279 struct list_head ing_tc_list
;
3280 struct list_head eg_tc_list
;
3286 struct list_head port_list
;
3289 static struct occ_item
*occ_item_alloc(void)
3291 return calloc(1, sizeof(struct occ_item
));
3294 static void occ_item_free(struct occ_item
*occ_item
)
3299 static struct occ_port
*occ_port_alloc(uint32_t port_index
)
3301 struct occ_port
*occ_port
;
3303 occ_port
= calloc(1, sizeof(*occ_port
));
3306 occ_port
->port_index
= port_index
;
3307 INIT_LIST_HEAD(&occ_port
->pool_list
);
3308 INIT_LIST_HEAD(&occ_port
->ing_tc_list
);
3309 INIT_LIST_HEAD(&occ_port
->eg_tc_list
);
3313 static void occ_port_free(struct occ_port
*occ_port
)
3315 struct occ_item
*occ_item
, *tmp
;
3317 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->pool_list
, list
)
3318 occ_item_free(occ_item
);
3319 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->ing_tc_list
, list
)
3320 occ_item_free(occ_item
);
3321 list_for_each_entry_safe(occ_item
, tmp
, &occ_port
->eg_tc_list
, list
)
3322 occ_item_free(occ_item
);
3325 static struct occ_show
*occ_show_alloc(struct dl
*dl
)
3327 struct occ_show
*occ_show
;
3329 occ_show
= calloc(1, sizeof(*occ_show
));
3333 INIT_LIST_HEAD(&occ_show
->port_list
);
3337 static void occ_show_free(struct occ_show
*occ_show
)
3339 struct occ_port
*occ_port
, *tmp
;
3341 list_for_each_entry_safe(occ_port
, tmp
, &occ_show
->port_list
, list
)
3342 occ_port_free(occ_port
);
3345 static struct occ_port
*occ_port_get(struct occ_show
*occ_show
,
3348 struct occ_port
*occ_port
;
3349 uint32_t port_index
;
3351 port_index
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_PORT_INDEX
]);
3353 list_for_each_entry_reverse(occ_port
, &occ_show
->port_list
, list
) {
3354 if (occ_port
->port_index
== port_index
)
3357 occ_port
= occ_port_alloc(port_index
);
3360 list_add_tail(&occ_port
->list
, &occ_show
->port_list
);
3364 static void pr_out_occ_show_item_list(const char *label
, struct list_head
*list
,
3367 struct occ_item
*occ_item
;
3370 pr_out_sp(7, " %s:", label
);
3371 list_for_each_entry(occ_item
, list
, list
) {
3372 if ((i
- 1) % 4 == 0 && i
!= 1)
3375 pr_out_sp(7, "%2u(%u):", occ_item
->index
,
3376 occ_item
->bound_pool_index
);
3378 pr_out_sp(7, "%2u:", occ_item
->index
);
3379 pr_out_sp(15, "%7u/%u", occ_item
->cur
, occ_item
->max
);
3383 if ((i
- 1) % 4 != 0)
3387 static void pr_out_json_occ_show_item_list(struct dl
*dl
, const char *label
,
3388 struct list_head
*list
,
3391 struct occ_item
*occ_item
;
3394 jsonw_name(dl
->jw
, label
);
3395 jsonw_start_object(dl
->jw
);
3396 list_for_each_entry(occ_item
, list
, list
) {
3397 sprintf(buf
, "%u", occ_item
->index
);
3398 jsonw_name(dl
->jw
, buf
);
3399 jsonw_start_object(dl
->jw
);
3401 jsonw_uint_field(dl
->jw
, "bound_pool",
3402 occ_item
->bound_pool_index
);
3403 jsonw_uint_field(dl
->jw
, "current", occ_item
->cur
);
3404 jsonw_uint_field(dl
->jw
, "max", occ_item
->max
);
3405 jsonw_end_object(dl
->jw
);
3407 jsonw_end_object(dl
->jw
);
3410 static void pr_out_occ_show_port(struct dl
*dl
, struct occ_port
*occ_port
)
3412 if (dl
->json_output
) {
3413 pr_out_json_occ_show_item_list(dl
, "pool",
3414 &occ_port
->pool_list
, false);
3415 pr_out_json_occ_show_item_list(dl
, "itc",
3416 &occ_port
->ing_tc_list
, true);
3417 pr_out_json_occ_show_item_list(dl
, "etc",
3418 &occ_port
->eg_tc_list
, true);
3421 pr_out_occ_show_item_list("pool", &occ_port
->pool_list
, false);
3422 pr_out_occ_show_item_list("itc", &occ_port
->ing_tc_list
, true);
3423 pr_out_occ_show_item_list("etc", &occ_port
->eg_tc_list
, true);
3427 static void pr_out_occ_show(struct occ_show
*occ_show
)
3429 struct dl
*dl
= occ_show
->dl
;
3430 struct dl_opts
*opts
= &dl
->opts
;
3431 struct occ_port
*occ_port
;
3433 list_for_each_entry(occ_port
, &occ_show
->port_list
, list
) {
3434 __pr_out_port_handle_start(dl
, opts
->bus_name
, opts
->dev_name
,
3435 occ_port
->port_index
, true, false);
3436 pr_out_occ_show_port(dl
, occ_port
);
3437 pr_out_port_handle_end(dl
);
3441 static void cmd_sb_occ_port_pool_process(struct occ_show
*occ_show
,
3444 struct occ_port
*occ_port
;
3445 struct occ_item
*occ_item
;
3447 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
3450 occ_port
= occ_port_get(occ_show
, tb
);
3452 occ_show
->err
= -ENOMEM
;
3456 occ_item
= occ_item_alloc();
3458 occ_show
->err
= -ENOMEM
;
3461 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
3462 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
3463 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
3464 list_add_tail(&occ_item
->list
, &occ_port
->pool_list
);
3467 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
3469 struct occ_show
*occ_show
= data
;
3470 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3471 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3473 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3474 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3475 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3476 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3477 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
3478 return MNL_CB_ERROR
;
3479 cmd_sb_occ_port_pool_process(occ_show
, tb
);
3483 static void cmd_sb_occ_tc_pool_process(struct occ_show
*occ_show
,
3486 struct occ_port
*occ_port
;
3487 struct occ_item
*occ_item
;
3490 if (occ_show
->err
|| !dl_dump_filter(occ_show
->dl
, tb
))
3493 occ_port
= occ_port_get(occ_show
, tb
);
3495 occ_show
->err
= -ENOMEM
;
3499 occ_item
= occ_item_alloc();
3501 occ_show
->err
= -ENOMEM
;
3504 occ_item
->index
= mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_TC_INDEX
]);
3505 occ_item
->cur
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_CUR
]);
3506 occ_item
->max
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_SB_OCC_MAX
]);
3507 occ_item
->bound_pool_index
=
3508 mnl_attr_get_u16(tb
[DEVLINK_ATTR_SB_POOL_INDEX
]);
3509 pool_type
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_SB_POOL_TYPE
]);
3510 if (pool_type
== DEVLINK_SB_POOL_TYPE_INGRESS
)
3511 list_add_tail(&occ_item
->list
, &occ_port
->ing_tc_list
);
3512 else if (pool_type
== DEVLINK_SB_POOL_TYPE_EGRESS
)
3513 list_add_tail(&occ_item
->list
, &occ_port
->eg_tc_list
);
3515 occ_item_free(occ_item
);
3518 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr
*nlh
, void *data
)
3520 struct occ_show
*occ_show
= data
;
3521 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3522 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3524 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3525 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3526 !tb
[DEVLINK_ATTR_PORT_INDEX
] || !tb
[DEVLINK_ATTR_SB_INDEX
] ||
3527 !tb
[DEVLINK_ATTR_SB_TC_INDEX
] || !tb
[DEVLINK_ATTR_SB_POOL_TYPE
] ||
3528 !tb
[DEVLINK_ATTR_SB_POOL_INDEX
] ||
3529 !tb
[DEVLINK_ATTR_SB_OCC_CUR
] || !tb
[DEVLINK_ATTR_SB_OCC_MAX
])
3530 return MNL_CB_ERROR
;
3531 cmd_sb_occ_tc_pool_process(occ_show
, tb
);
3535 static int cmd_sb_occ_show(struct dl
*dl
)
3537 struct nlmsghdr
*nlh
;
3538 struct occ_show
*occ_show
;
3539 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
;
3542 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_HANDLEP
, DL_OPT_SB
);
3546 occ_show
= occ_show_alloc(dl
);
3550 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_PORT_POOL_GET
, flags
);
3552 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
3553 cmd_sb_occ_port_pool_process_cb
, occ_show
);
3557 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_TC_POOL_BIND_GET
, flags
);
3559 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
,
3560 cmd_sb_occ_tc_pool_process_cb
, occ_show
);
3564 pr_out_section_start(dl
, "occupancy");
3565 pr_out_occ_show(occ_show
);
3566 pr_out_section_end(dl
);
3569 occ_show_free(occ_show
);
3573 static int cmd_sb_occ_snapshot(struct dl
*dl
)
3575 struct nlmsghdr
*nlh
;
3578 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_SNAPSHOT
,
3579 NLM_F_REQUEST
| NLM_F_ACK
);
3581 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3585 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3588 static int cmd_sb_occ_clearmax(struct dl
*dl
)
3590 struct nlmsghdr
*nlh
;
3593 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_SB_OCC_MAX_CLEAR
,
3594 NLM_F_REQUEST
| NLM_F_ACK
);
3596 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, DL_OPT_SB
);
3600 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
3603 static int cmd_sb_occ(struct dl
*dl
)
3605 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
3608 } else if (dl_argv_match(dl
, "show") ||
3609 dl_argv_match(dl
, "list")) {
3611 return cmd_sb_occ_show(dl
);
3612 } else if (dl_argv_match(dl
, "snapshot")) {
3614 return cmd_sb_occ_snapshot(dl
);
3615 } else if (dl_argv_match(dl
, "clearmax")) {
3617 return cmd_sb_occ_clearmax(dl
);
3619 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3623 static int cmd_sb(struct dl
*dl
)
3625 if (dl_argv_match(dl
, "help")) {
3628 } else if (dl_argv_match(dl
, "show") ||
3629 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
3631 return cmd_sb_show(dl
);
3632 } else if (dl_argv_match(dl
, "pool")) {
3634 return cmd_sb_pool(dl
);
3635 } else if (dl_argv_match(dl
, "port")) {
3637 return cmd_sb_port(dl
);
3638 } else if (dl_argv_match(dl
, "tc")) {
3640 return cmd_sb_tc(dl
);
3641 } else if (dl_argv_match(dl
, "occupancy")) {
3643 return cmd_sb_occ(dl
);
3645 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3649 static const char *cmd_name(uint8_t cmd
)
3652 case DEVLINK_CMD_UNSPEC
: return "unspec";
3653 case DEVLINK_CMD_GET
: return "get";
3654 case DEVLINK_CMD_SET
: return "set";
3655 case DEVLINK_CMD_NEW
: return "new";
3656 case DEVLINK_CMD_DEL
: return "del";
3657 case DEVLINK_CMD_PORT_GET
: return "get";
3658 case DEVLINK_CMD_PORT_SET
: return "set";
3659 case DEVLINK_CMD_PORT_NEW
: return "new";
3660 case DEVLINK_CMD_PORT_DEL
: return "del";
3661 case DEVLINK_CMD_PARAM_GET
: return "get";
3662 case DEVLINK_CMD_PARAM_SET
: return "set";
3663 case DEVLINK_CMD_PARAM_NEW
: return "new";
3664 case DEVLINK_CMD_PARAM_DEL
: return "del";
3665 case DEVLINK_CMD_REGION_GET
: return "get";
3666 case DEVLINK_CMD_REGION_SET
: return "set";
3667 case DEVLINK_CMD_REGION_NEW
: return "new";
3668 case DEVLINK_CMD_REGION_DEL
: return "del";
3669 default: return "<unknown cmd>";
3673 static const char *cmd_obj(uint8_t cmd
)
3676 case DEVLINK_CMD_UNSPEC
: return "unspec";
3677 case DEVLINK_CMD_GET
:
3678 case DEVLINK_CMD_SET
:
3679 case DEVLINK_CMD_NEW
:
3680 case DEVLINK_CMD_DEL
:
3682 case DEVLINK_CMD_PORT_GET
:
3683 case DEVLINK_CMD_PORT_SET
:
3684 case DEVLINK_CMD_PORT_NEW
:
3685 case DEVLINK_CMD_PORT_DEL
:
3687 case DEVLINK_CMD_PARAM_GET
:
3688 case DEVLINK_CMD_PARAM_SET
:
3689 case DEVLINK_CMD_PARAM_NEW
:
3690 case DEVLINK_CMD_PARAM_DEL
:
3692 case DEVLINK_CMD_REGION_GET
:
3693 case DEVLINK_CMD_REGION_SET
:
3694 case DEVLINK_CMD_REGION_NEW
:
3695 case DEVLINK_CMD_REGION_DEL
:
3697 default: return "<unknown obj>";
3701 static void pr_out_mon_header(uint8_t cmd
)
3703 pr_out("[%s,%s] ", cmd_obj(cmd
), cmd_name(cmd
));
3706 static bool cmd_filter_check(struct dl
*dl
, uint8_t cmd
)
3708 const char *obj
= cmd_obj(cmd
);
3709 unsigned int index
= 0;
3710 const char *cur_obj
;
3714 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
3715 if (strcmp(cur_obj
, obj
) == 0 || strcmp(cur_obj
, "all") == 0)
3721 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
);
3723 static int cmd_mon_show_cb(const struct nlmsghdr
*nlh
, void *data
)
3725 struct dl
*dl
= data
;
3726 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
3727 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
3728 uint8_t cmd
= genl
->cmd
;
3730 if (!cmd_filter_check(dl
, cmd
))
3734 case DEVLINK_CMD_GET
: /* fall through */
3735 case DEVLINK_CMD_SET
: /* fall through */
3736 case DEVLINK_CMD_NEW
: /* fall through */
3737 case DEVLINK_CMD_DEL
:
3738 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3739 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
])
3740 return MNL_CB_ERROR
;
3741 pr_out_mon_header(genl
->cmd
);
3744 case DEVLINK_CMD_PORT_GET
: /* fall through */
3745 case DEVLINK_CMD_PORT_SET
: /* fall through */
3746 case DEVLINK_CMD_PORT_NEW
: /* fall through */
3747 case DEVLINK_CMD_PORT_DEL
:
3748 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3749 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3750 !tb
[DEVLINK_ATTR_PORT_INDEX
])
3751 return MNL_CB_ERROR
;
3752 pr_out_mon_header(genl
->cmd
);
3753 pr_out_port(dl
, tb
);
3755 case DEVLINK_CMD_PARAM_GET
: /* fall through */
3756 case DEVLINK_CMD_PARAM_SET
: /* fall through */
3757 case DEVLINK_CMD_PARAM_NEW
: /* fall through */
3758 case DEVLINK_CMD_PARAM_DEL
:
3759 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3760 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3761 !tb
[DEVLINK_ATTR_PARAM
])
3762 return MNL_CB_ERROR
;
3763 pr_out_mon_header(genl
->cmd
);
3764 pr_out_param(dl
, tb
, false);
3766 case DEVLINK_CMD_REGION_GET
: /* fall through */
3767 case DEVLINK_CMD_REGION_SET
: /* fall through */
3768 case DEVLINK_CMD_REGION_NEW
: /* fall through */
3769 case DEVLINK_CMD_REGION_DEL
:
3770 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
3771 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
3772 !tb
[DEVLINK_ATTR_REGION_NAME
])
3773 return MNL_CB_ERROR
;
3774 pr_out_mon_header(genl
->cmd
);
3775 pr_out_region(dl
, tb
);
3781 static int cmd_mon_show(struct dl
*dl
)
3784 unsigned int index
= 0;
3785 const char *cur_obj
;
3787 while ((cur_obj
= dl_argv_index(dl
, index
++))) {
3788 if (strcmp(cur_obj
, "all") != 0 &&
3789 strcmp(cur_obj
, "dev") != 0 &&
3790 strcmp(cur_obj
, "port") != 0) {
3791 pr_err("Unknown object \"%s\"\n", cur_obj
);
3795 err
= _mnlg_socket_group_add(dl
->nlg
, DEVLINK_GENL_MCGRP_CONFIG_NAME
);
3798 err
= _mnlg_socket_recv_run(dl
->nlg
, cmd_mon_show_cb
, dl
);
3804 static void cmd_mon_help(void)
3806 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
3807 "where OBJECT-LIST := { dev | port }\n");
3810 static int cmd_mon(struct dl
*dl
)
3812 if (dl_argv_match(dl
, "help")) {
3815 } else if (dl_no_arg(dl
)) {
3817 return cmd_mon_show(dl
);
3819 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
3823 struct dpipe_field
{
3826 unsigned int bitwidth
;
3827 enum devlink_dpipe_field_mapping_type mapping_type
;
3830 struct dpipe_header
{
3831 struct list_head list
;
3834 struct dpipe_field
*fields
;
3835 unsigned int fields_count
;
3838 struct dpipe_table
{
3839 struct list_head list
;
3841 unsigned int resource_id
;
3842 bool resource_valid
;
3845 struct dpipe_tables
{
3846 struct list_head table_list
;
3856 enum devlink_resource_unit unit
;
3861 struct list_head list
;
3862 struct list_head resource_list
;
3863 struct resource
*parent
;
3867 struct list_head resource_list
;
3870 struct resource_ctx
{
3873 struct resources
*resources
;
3874 struct dpipe_tables
*tables
;
3875 bool print_resources
;
3876 bool pending_change
;
3879 static struct resource
*resource_alloc(void)
3881 struct resource
*resource
;
3883 resource
= calloc(1, sizeof(struct resource
));
3886 INIT_LIST_HEAD(&resource
->resource_list
);
3890 static void resource_free(struct resource
*resource
)
3892 struct resource
*child_resource
, *tmp
;
3894 list_for_each_entry_safe(child_resource
, tmp
, &resource
->resource_list
,
3896 free(child_resource
->name
);
3897 resource_free(child_resource
);
3902 static struct resources
*resources_alloc(void)
3904 struct resources
*resources
;
3906 resources
= calloc(1, sizeof(struct resources
));
3909 INIT_LIST_HEAD(&resources
->resource_list
);
3913 static void resources_free(struct resources
*resources
)
3915 struct resource
*resource
, *tmp
;
3917 list_for_each_entry_safe(resource
, tmp
, &resources
->resource_list
, list
)
3918 resource_free(resource
);
3921 static int resource_ctx_init(struct resource_ctx
*ctx
, struct dl
*dl
)
3923 ctx
->resources
= resources_alloc();
3924 if (!ctx
->resources
)
3930 static void resource_ctx_fini(struct resource_ctx
*ctx
)
3932 resources_free(ctx
->resources
);
3938 struct list_head global_headers
;
3939 struct list_head local_headers
;
3940 struct dpipe_tables
*tables
;
3941 struct resources
*resources
;
3946 static struct dpipe_header
*dpipe_header_alloc(unsigned int fields_count
)
3948 struct dpipe_header
*header
;
3950 header
= calloc(1, sizeof(struct dpipe_header
));
3953 header
->fields
= calloc(fields_count
, sizeof(struct dpipe_field
));
3954 if (!header
->fields
)
3955 goto err_fields_alloc
;
3956 header
->fields_count
= fields_count
;
3964 static void dpipe_header_free(struct dpipe_header
*header
)
3966 free(header
->fields
);
3970 static void dpipe_header_clear(struct dpipe_header
*header
)
3972 struct dpipe_field
*field
;
3975 for (i
= 0; i
< header
->fields_count
; i
++) {
3976 field
= &header
->fields
[i
];
3982 static void dpipe_header_add(struct dpipe_ctx
*ctx
,
3983 struct dpipe_header
*header
, bool global
)
3986 list_add(&header
->list
, &ctx
->global_headers
);
3988 list_add(&header
->list
, &ctx
->local_headers
);
3991 static void dpipe_header_del(struct dpipe_header
*header
)
3993 list_del(&header
->list
);
3996 static struct dpipe_table
*dpipe_table_alloc(void)
3998 return calloc(1, sizeof(struct dpipe_table
));
4001 static void dpipe_table_free(struct dpipe_table
*table
)
4006 static struct dpipe_tables
*dpipe_tables_alloc(void)
4008 struct dpipe_tables
*tables
;
4010 tables
= calloc(1, sizeof(struct dpipe_tables
));
4013 INIT_LIST_HEAD(&tables
->table_list
);
4017 static void dpipe_tables_free(struct dpipe_tables
*tables
)
4019 struct dpipe_table
*table
, *tmp
;
4021 list_for_each_entry_safe(table
, tmp
, &tables
->table_list
, list
)
4022 dpipe_table_free(table
);
4026 static int dpipe_ctx_init(struct dpipe_ctx
*ctx
, struct dl
*dl
)
4028 ctx
->tables
= dpipe_tables_alloc();
4033 INIT_LIST_HEAD(&ctx
->global_headers
);
4034 INIT_LIST_HEAD(&ctx
->local_headers
);
4038 static void dpipe_ctx_fini(struct dpipe_ctx
*ctx
)
4040 struct dpipe_header
*header
, *tmp
;
4042 list_for_each_entry_safe(header
, tmp
, &ctx
->global_headers
,
4044 dpipe_header_del(header
);
4045 dpipe_header_clear(header
);
4046 dpipe_header_free(header
);
4048 list_for_each_entry_safe(header
, tmp
, &ctx
->local_headers
,
4050 dpipe_header_del(header
);
4051 dpipe_header_clear(header
);
4052 dpipe_header_free(header
);
4054 dpipe_tables_free(ctx
->tables
);
4057 static const char *dpipe_header_id2s(struct dpipe_ctx
*ctx
,
4058 uint32_t header_id
, bool global
)
4060 struct list_head
*header_list
;
4061 struct dpipe_header
*header
;
4064 header_list
= &ctx
->global_headers
;
4066 header_list
= &ctx
->local_headers
;
4067 list_for_each_entry(header
, header_list
, list
) {
4068 if (header
->id
!= header_id
)
4070 return header
->name
;
4075 static const char *dpipe_field_id2s(struct dpipe_ctx
*ctx
,
4077 uint32_t field_id
, bool global
)
4079 struct list_head
*header_list
;
4080 struct dpipe_header
*header
;
4083 header_list
= &ctx
->global_headers
;
4085 header_list
= &ctx
->local_headers
;
4086 list_for_each_entry(header
, header_list
, list
) {
4087 if (header
->id
!= header_id
)
4089 return header
->fields
[field_id
].name
;
4095 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type
)
4097 switch (mapping_type
) {
4098 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE
:
4100 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX
:
4108 dpipe_mapping_get(struct dpipe_ctx
*ctx
, uint32_t header_id
,
4109 uint32_t field_id
, bool global
)
4111 enum devlink_dpipe_field_mapping_type mapping_type
;
4112 struct list_head
*header_list
;
4113 struct dpipe_header
*header
;
4116 header_list
= &ctx
->global_headers
;
4118 header_list
= &ctx
->local_headers
;
4119 list_for_each_entry(header
, header_list
, list
) {
4120 if (header
->id
!= header_id
)
4122 mapping_type
= header
->fields
[field_id
].mapping_type
;
4123 return dpipe_field_mapping_e2s(mapping_type
);
4128 static void pr_out_dpipe_fields(struct dpipe_ctx
*ctx
,
4129 struct dpipe_field
*fields
,
4130 unsigned int field_count
)
4132 struct dpipe_field
*field
;
4135 for (i
= 0; i
< field_count
; i
++) {
4137 pr_out_entry_start(ctx
->dl
);
4138 pr_out_str(ctx
->dl
, "name", field
->name
);
4139 if (ctx
->dl
->verbose
)
4140 pr_out_uint(ctx
->dl
, "id", field
->id
);
4141 pr_out_uint(ctx
->dl
, "bitwidth", field
->bitwidth
);
4142 if (field
->mapping_type
)
4143 pr_out_str(ctx
->dl
, "mapping_type",
4144 dpipe_field_mapping_e2s(field
->mapping_type
));
4145 pr_out_entry_end(ctx
->dl
);
4150 pr_out_dpipe_header(struct dpipe_ctx
*ctx
, struct nlattr
**tb
,
4151 struct dpipe_header
*header
, bool global
)
4153 pr_out_handle_start_arr(ctx
->dl
, tb
);
4154 pr_out_str(ctx
->dl
, "name", header
->name
);
4155 if (ctx
->dl
->verbose
) {
4156 pr_out_uint(ctx
->dl
, "id", header
->id
);
4157 pr_out_str(ctx
->dl
, "global",
4158 global
? "true" : "false");
4160 pr_out_array_start(ctx
->dl
, "field");
4161 pr_out_dpipe_fields(ctx
, header
->fields
,
4162 header
->fields_count
);
4163 pr_out_array_end(ctx
->dl
);
4164 pr_out_handle_end(ctx
->dl
);
4167 static void pr_out_dpipe_headers(struct dpipe_ctx
*ctx
,
4170 struct dpipe_header
*header
;
4172 list_for_each_entry(header
, &ctx
->local_headers
, list
)
4173 pr_out_dpipe_header(ctx
, tb
, header
, false);
4175 list_for_each_entry(header
, &ctx
->global_headers
, list
)
4176 pr_out_dpipe_header(ctx
, tb
, header
, true);
4179 static int dpipe_header_field_get(struct nlattr
*nl
, struct dpipe_field
*field
)
4181 struct nlattr
*nla_field
[DEVLINK_ATTR_MAX
+ 1] = {};
4185 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_field
);
4186 if (err
!= MNL_CB_OK
)
4188 if (!nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
] ||
4189 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
] ||
4190 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
] ||
4191 !nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
])
4194 name
= mnl_attr_get_str(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_NAME
]);
4195 field
->id
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4196 field
->bitwidth
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH
]);
4197 field
->name
= strdup(name
);
4200 field
->mapping_type
= mnl_attr_get_u32(nla_field
[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE
]);
4204 static int dpipe_header_fields_get(struct nlattr
*nla_fields
,
4205 struct dpipe_field
*fields
)
4207 struct nlattr
*nla_field
;
4211 mnl_attr_for_each_nested(nla_field
, nla_fields
) {
4212 err
= dpipe_header_field_get(nla_field
, &fields
[count
]);
4220 static unsigned int dpipe_header_field_count_get(struct nlattr
*nla_fields
)
4222 struct nlattr
*nla_field
;
4223 unsigned int count
= 0;
4225 mnl_attr_for_each_nested(nla_field
, nla_fields
)
4230 static int dpipe_header_get(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
4232 struct nlattr
*nla_header
[DEVLINK_ATTR_MAX
+ 1] = {};
4233 struct dpipe_header
*header
;
4234 unsigned int fields_count
;
4235 const char *header_name
;
4239 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_header
);
4240 if (err
!= MNL_CB_OK
)
4243 if (!nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
] ||
4244 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4245 !nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
])
4248 fields_count
= dpipe_header_field_count_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
]);
4249 header
= dpipe_header_alloc(fields_count
);
4253 header_name
= mnl_attr_get_str(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_NAME
]);
4254 header
->name
= strdup(header_name
);
4255 header
->id
= mnl_attr_get_u32(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4256 header
->fields_count
= fields_count
;
4257 global
= !!mnl_attr_get_u8(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4259 err
= dpipe_header_fields_get(nla_header
[DEVLINK_ATTR_DPIPE_HEADER_FIELDS
],
4263 dpipe_header_add(ctx
, header
, global
);
4267 dpipe_header_free(header
);
4271 static int dpipe_headers_get(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
4273 struct nlattr
*nla_headers
= tb
[DEVLINK_ATTR_DPIPE_HEADERS
];
4274 struct nlattr
*nla_header
;
4277 mnl_attr_for_each_nested(nla_header
, nla_headers
) {
4278 err
= dpipe_header_get(ctx
, nla_header
);
4285 static int cmd_dpipe_header_cb(const struct nlmsghdr
*nlh
, void *data
)
4287 struct dpipe_ctx
*ctx
= data
;
4288 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4289 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4292 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4293 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4294 !tb
[DEVLINK_ATTR_DPIPE_HEADERS
])
4295 return MNL_CB_ERROR
;
4296 err
= dpipe_headers_get(ctx
, tb
);
4299 return MNL_CB_ERROR
;
4302 if (ctx
->print_headers
)
4303 pr_out_dpipe_headers(ctx
, tb
);
4307 static int cmd_dpipe_headers_show(struct dl
*dl
)
4309 struct nlmsghdr
*nlh
;
4310 struct dpipe_ctx ctx
= {};
4311 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
4314 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
4316 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE
, 0);
4320 err
= dpipe_ctx_init(&ctx
, dl
);
4324 ctx
.print_headers
= true;
4326 pr_out_section_start(dl
, "header");
4327 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
4329 pr_err("error get headers %s\n", strerror(ctx
.err
));
4330 pr_out_section_end(dl
);
4332 dpipe_ctx_fini(&ctx
);
4336 static void cmd_dpipe_header_help(void)
4338 pr_err("Usage: devlink dpipe headers show DEV\n");
4341 static int cmd_dpipe_header(struct dl
*dl
)
4343 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
4344 cmd_dpipe_header_help();
4346 } else if (dl_argv_match(dl
, "show")) {
4348 return cmd_dpipe_headers_show(dl
);
4350 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
4355 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type
)
4357 switch (action_type
) {
4358 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY
:
4359 return "field_modify";
4365 struct dpipe_op_info
{
4371 struct dpipe_action
{
4372 struct dpipe_op_info info
;
4376 static void pr_out_dpipe_action(struct dpipe_action
*action
,
4377 struct dpipe_ctx
*ctx
)
4379 struct dpipe_op_info
*op_info
= &action
->info
;
4380 const char *mapping
;
4382 pr_out_str(ctx
->dl
, "type",
4383 dpipe_action_type_e2s(action
->type
));
4384 pr_out_str(ctx
->dl
, "header",
4385 dpipe_header_id2s(ctx
, op_info
->header_id
,
4386 op_info
->header_global
));
4387 pr_out_str(ctx
->dl
, "field",
4388 dpipe_field_id2s(ctx
, op_info
->header_id
,
4390 op_info
->header_global
));
4391 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
4393 op_info
->header_global
);
4395 pr_out_str(ctx
->dl
, "mapping", mapping
);
4398 static int dpipe_action_parse(struct dpipe_action
*action
, struct nlattr
*nl
)
4400 struct nlattr
*nla_action
[DEVLINK_ATTR_MAX
+ 1] = {};
4403 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action
);
4404 if (err
!= MNL_CB_OK
)
4407 if (!nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
] ||
4408 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
4409 !nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4410 !nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
4414 action
->type
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_ACTION_TYPE
]);
4415 action
->info
.header_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4416 action
->info
.field_id
= mnl_attr_get_u32(nla_action
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4417 action
->info
.header_global
= !!mnl_attr_get_u8(nla_action
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4422 static int dpipe_table_actions_show(struct dpipe_ctx
*ctx
,
4423 struct nlattr
*nla_actions
)
4425 struct nlattr
*nla_action
;
4426 struct dpipe_action action
;
4428 mnl_attr_for_each_nested(nla_action
, nla_actions
) {
4429 pr_out_entry_start(ctx
->dl
);
4430 if (dpipe_action_parse(&action
, nla_action
))
4431 goto err_action_parse
;
4432 pr_out_dpipe_action(&action
, ctx
);
4433 pr_out_entry_end(ctx
->dl
);
4438 pr_out_entry_end(ctx
->dl
);
4443 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type
)
4445 switch (match_type
) {
4446 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT
:
4447 return "field_exact";
4453 struct dpipe_match
{
4454 struct dpipe_op_info info
;
4458 static void pr_out_dpipe_match(struct dpipe_match
*match
,
4459 struct dpipe_ctx
*ctx
)
4461 struct dpipe_op_info
*op_info
= &match
->info
;
4462 const char *mapping
;
4464 pr_out_str(ctx
->dl
, "type",
4465 dpipe_match_type_e2s(match
->type
));
4466 pr_out_str(ctx
->dl
, "header",
4467 dpipe_header_id2s(ctx
, op_info
->header_id
,
4468 op_info
->header_global
));
4469 pr_out_str(ctx
->dl
, "field",
4470 dpipe_field_id2s(ctx
, op_info
->header_id
,
4472 op_info
->header_global
));
4473 mapping
= dpipe_mapping_get(ctx
, op_info
->header_id
,
4475 op_info
->header_global
);
4477 pr_out_str(ctx
->dl
, "mapping", mapping
);
4480 static int dpipe_match_parse(struct dpipe_match
*match
,
4484 struct nlattr
*nla_match
[DEVLINK_ATTR_MAX
+ 1] = {};
4487 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match
);
4488 if (err
!= MNL_CB_OK
)
4491 if (!nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
] ||
4492 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_INDEX
] ||
4493 !nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
] ||
4494 !nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]) {
4498 match
->type
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_MATCH_TYPE
]);
4499 match
->info
.header_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_ID
]);
4500 match
->info
.field_id
= mnl_attr_get_u32(nla_match
[DEVLINK_ATTR_DPIPE_FIELD_ID
]);
4501 match
->info
.header_global
= !!mnl_attr_get_u8(nla_match
[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL
]);
4506 static int dpipe_table_matches_show(struct dpipe_ctx
*ctx
,
4507 struct nlattr
*nla_matches
)
4509 struct nlattr
*nla_match
;
4510 struct dpipe_match match
;
4512 mnl_attr_for_each_nested(nla_match
, nla_matches
) {
4513 pr_out_entry_start(ctx
->dl
);
4514 if (dpipe_match_parse(&match
, nla_match
))
4515 goto err_match_parse
;
4516 pr_out_dpipe_match(&match
, ctx
);
4517 pr_out_entry_end(ctx
->dl
);
4522 pr_out_entry_end(ctx
->dl
);
4526 static struct resource
*
4527 resource_find(struct resources
*resources
, struct resource
*resource
,
4528 uint64_t resource_id
)
4530 struct list_head
*list_head
;
4533 list_head
= &resources
->resource_list
;
4535 list_head
= &resource
->resource_list
;
4537 list_for_each_entry(resource
, list_head
, list
) {
4538 struct resource
*child_resource
;
4540 if (resource
->id
== resource_id
)
4543 child_resource
= resource_find(resources
, resource
,
4546 return child_resource
;
4552 resource_path_print(struct dl
*dl
, struct resources
*resources
,
4553 uint64_t resource_id
)
4555 struct resource
*resource
, *parent_resource
;
4556 const char del
[] = "/";
4560 resource
= resource_find(resources
, NULL
, resource_id
);
4564 for (parent_resource
= resource
; parent_resource
;
4565 parent_resource
= parent_resource
->parent
)
4566 path_len
+= strlen(parent_resource
->name
) + 1;
4569 path
= calloc(1, path_len
);
4573 path
+= path_len
- 1;
4574 for (parent_resource
= resource
; parent_resource
;
4575 parent_resource
= parent_resource
->parent
) {
4576 path
-= strlen(parent_resource
->name
);
4577 memcpy(path
, parent_resource
->name
,
4578 strlen(parent_resource
->name
));
4579 path
-= strlen(del
);
4580 memcpy(path
, del
, strlen(del
));
4582 pr_out_str(dl
, "resource_path", path
);
4586 static int dpipe_table_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
4588 struct nlattr
*nla_table
[DEVLINK_ATTR_MAX
+ 1] = {};
4589 struct dpipe_table
*table
;
4590 uint32_t resource_units
;
4591 bool counters_enabled
;
4592 bool resource_valid
;
4596 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_table
);
4597 if (err
!= MNL_CB_OK
)
4600 if (!nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
] ||
4601 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
] ||
4602 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
] ||
4603 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
] ||
4604 !nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]) {
4608 table
= dpipe_table_alloc();
4612 table
->name
= strdup(mnl_attr_get_str(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_NAME
]));
4613 size
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_SIZE
]);
4614 counters_enabled
= !!mnl_attr_get_u8(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED
]);
4616 resource_valid
= nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
] &&
4618 if (resource_valid
) {
4619 table
->resource_id
= mnl_attr_get_u64(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID
]);
4620 table
->resource_valid
= true;
4623 list_add_tail(&table
->list
, &ctx
->tables
->table_list
);
4624 if (!ctx
->print_tables
)
4627 pr_out_str(ctx
->dl
, "name", table
->name
);
4628 pr_out_uint(ctx
->dl
, "size", size
);
4629 pr_out_str(ctx
->dl
, "counters_enabled",
4630 counters_enabled
? "true" : "false");
4632 if (resource_valid
) {
4633 resource_units
= mnl_attr_get_u32(nla_table
[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS
]);
4634 resource_path_print(ctx
->dl
, ctx
->resources
,
4635 table
->resource_id
);
4636 pr_out_uint(ctx
->dl
, "resource_units", resource_units
);
4639 pr_out_array_start(ctx
->dl
, "match");
4640 if (dpipe_table_matches_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_MATCHES
]))
4641 goto err_matches_show
;
4642 pr_out_array_end(ctx
->dl
);
4644 pr_out_array_start(ctx
->dl
, "action");
4645 if (dpipe_table_actions_show(ctx
, nla_table
[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS
]))
4646 goto err_actions_show
;
4647 pr_out_array_end(ctx
->dl
);
4653 pr_out_array_end(ctx
->dl
);
4657 static int dpipe_tables_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
4659 struct nlattr
*nla_tables
= tb
[DEVLINK_ATTR_DPIPE_TABLES
];
4660 struct nlattr
*nla_table
;
4662 mnl_attr_for_each_nested(nla_table
, nla_tables
) {
4663 if (ctx
->print_tables
)
4664 pr_out_handle_start_arr(ctx
->dl
, tb
);
4665 if (dpipe_table_show(ctx
, nla_table
))
4666 goto err_table_show
;
4667 if (ctx
->print_tables
)
4668 pr_out_handle_end(ctx
->dl
);
4673 if (ctx
->print_tables
)
4674 pr_out_handle_end(ctx
->dl
);
4678 static int cmd_dpipe_table_show_cb(const struct nlmsghdr
*nlh
, void *data
)
4680 struct dpipe_ctx
*ctx
= data
;
4681 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
4682 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
4684 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
4685 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
4686 !tb
[DEVLINK_ATTR_DPIPE_TABLES
])
4687 return MNL_CB_ERROR
;
4689 if (dpipe_tables_show(ctx
, tb
))
4690 return MNL_CB_ERROR
;
4694 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
);
4696 static int cmd_dpipe_table_show(struct dl
*dl
)
4698 struct nlmsghdr
*nlh
;
4699 struct dpipe_ctx dpipe_ctx
= {};
4700 struct resource_ctx resource_ctx
= {};
4701 uint16_t flags
= NLM_F_REQUEST
;
4704 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, DL_OPT_DPIPE_TABLE_NAME
);
4708 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
4710 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
4714 dpipe_ctx
.print_tables
= true;
4716 dl_opts_put(nlh
, dl
);
4717 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
,
4720 pr_err("error get headers %s\n", strerror(dpipe_ctx
.err
));
4721 goto err_headers_get
;
4724 err
= resource_ctx_init(&resource_ctx
, dl
);
4726 goto err_resource_ctx_init
;
4728 resource_ctx
.print_resources
= false;
4729 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
, flags
);
4730 dl_opts_put(nlh
, dl
);
4731 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
4734 dpipe_ctx
.resources
= resource_ctx
.resources
;
4736 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
4737 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
, flags
);
4738 dl_opts_put(nlh
, dl
);
4740 pr_out_section_start(dl
, "table");
4741 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
, &dpipe_ctx
);
4742 pr_out_section_end(dl
);
4744 resource_ctx_fini(&resource_ctx
);
4745 dpipe_ctx_fini(&dpipe_ctx
);
4748 err_resource_ctx_init
:
4750 dpipe_ctx_fini(&dpipe_ctx
);
4754 static int cmd_dpipe_table_set(struct dl
*dl
)
4756 struct nlmsghdr
*nlh
;
4759 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET
,
4760 NLM_F_REQUEST
| NLM_F_ACK
);
4762 err
= dl_argv_parse_put(nlh
, dl
,
4763 DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
|
4764 DL_OPT_DPIPE_TABLE_COUNTERS
, 0);
4768 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
4771 enum dpipe_value_type
{
4772 DPIPE_VALUE_TYPE_VALUE
,
4773 DPIPE_VALUE_TYPE_MASK
,
4777 dpipe_value_type_e2s(enum dpipe_value_type type
)
4780 case DPIPE_VALUE_TYPE_VALUE
:
4782 case DPIPE_VALUE_TYPE_MASK
:
4783 return "value_mask";
4789 struct dpipe_field_printer
{
4790 unsigned int field_id
;
4791 void (*printer
)(struct dpipe_ctx
*, enum dpipe_value_type
, void *);
4794 struct dpipe_header_printer
{
4795 struct dpipe_field_printer
*printers
;
4796 unsigned int printers_count
;
4797 unsigned int header_id
;
4800 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx
*ctx
,
4801 enum dpipe_value_type type
,
4804 struct in_addr ip_addr
;
4806 ip_addr
.s_addr
= htonl(*(uint32_t *)value
);
4807 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
), inet_ntoa(ip_addr
));
4811 dpipe_field_printer_ethernet_addr(struct dpipe_ctx
*ctx
,
4812 enum dpipe_value_type type
,
4815 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
),
4816 ether_ntoa((struct ether_addr
*)value
));
4819 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx
*ctx
,
4820 enum dpipe_value_type type
,
4823 char str
[INET6_ADDRSTRLEN
];
4825 inet_ntop(AF_INET6
, value
, str
, INET6_ADDRSTRLEN
);
4826 pr_out_str(ctx
->dl
, dpipe_value_type_e2s(type
), str
);
4829 static struct dpipe_field_printer dpipe_field_printers_ipv4
[] = {
4831 .printer
= dpipe_field_printer_ipv4_addr
,
4832 .field_id
= DEVLINK_DPIPE_FIELD_IPV4_DST_IP
,
4836 static struct dpipe_header_printer dpipe_header_printer_ipv4
= {
4837 .printers
= dpipe_field_printers_ipv4
,
4838 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv4
),
4839 .header_id
= DEVLINK_DPIPE_HEADER_IPV4
,
4842 static struct dpipe_field_printer dpipe_field_printers_ethernet
[] = {
4844 .printer
= dpipe_field_printer_ethernet_addr
,
4845 .field_id
= DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC
,
4849 static struct dpipe_header_printer dpipe_header_printer_ethernet
= {
4850 .printers
= dpipe_field_printers_ethernet
,
4851 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ethernet
),
4852 .header_id
= DEVLINK_DPIPE_HEADER_ETHERNET
,
4855 static struct dpipe_field_printer dpipe_field_printers_ipv6
[] = {
4857 .printer
= dpipe_field_printer_ipv6_addr
,
4858 .field_id
= DEVLINK_DPIPE_FIELD_IPV6_DST_IP
,
4862 static struct dpipe_header_printer dpipe_header_printer_ipv6
= {
4863 .printers
= dpipe_field_printers_ipv6
,
4864 .printers_count
= ARRAY_SIZE(dpipe_field_printers_ipv6
),
4865 .header_id
= DEVLINK_DPIPE_HEADER_IPV6
,
4868 static struct dpipe_header_printer
*dpipe_header_printers
[] = {
4869 &dpipe_header_printer_ipv4
,
4870 &dpipe_header_printer_ethernet
,
4871 &dpipe_header_printer_ipv6
,
4874 static int dpipe_print_prot_header(struct dpipe_ctx
*ctx
,
4875 struct dpipe_op_info
*info
,
4876 enum dpipe_value_type type
,
4879 unsigned int header_printers_count
= ARRAY_SIZE(dpipe_header_printers
);
4880 struct dpipe_header_printer
*header_printer
;
4881 struct dpipe_field_printer
*field_printer
;
4882 unsigned int field_printers_count
;
4886 for (i
= 0; i
< header_printers_count
; i
++) {
4887 header_printer
= dpipe_header_printers
[i
];
4888 if (header_printer
->header_id
!= info
->header_id
)
4890 field_printers_count
= header_printer
->printers_count
;
4891 for (j
= 0; j
< field_printers_count
; j
++) {
4892 field_printer
= &header_printer
->printers
[j
];
4893 if (field_printer
->field_id
!= info
->field_id
)
4895 field_printer
->printer(ctx
, type
, value
);
4903 static void __pr_out_entry_value(struct dpipe_ctx
*ctx
,
4905 unsigned int value_len
,
4906 struct dpipe_op_info
*info
,
4907 enum dpipe_value_type type
)
4909 if (info
->header_global
&&
4910 !dpipe_print_prot_header(ctx
, info
, type
, value
))
4913 if (value_len
== sizeof(uint32_t)) {
4914 uint32_t *value_32
= value
;
4916 pr_out_uint(ctx
->dl
, dpipe_value_type_e2s(type
), *value_32
);
4920 static void pr_out_dpipe_entry_value(struct dpipe_ctx
*ctx
,
4921 struct nlattr
**nla_match_value
,
4922 struct dpipe_op_info
*info
)
4924 void *value
, *value_mask
;
4925 uint32_t value_mapping
;
4929 mask
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MASK
];
4930 mapping
= !!nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
];
4932 value_len
= mnl_attr_get_payload_len(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
4933 value
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
4936 value_mapping
= mnl_attr_get_u32(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE_MAPPING
]);
4937 pr_out_uint(ctx
->dl
, "mapping_value", value_mapping
);
4941 value_mask
= mnl_attr_get_payload(nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]);
4942 __pr_out_entry_value(ctx
, value_mask
, value_len
, info
,
4943 DPIPE_VALUE_TYPE_MASK
);
4946 __pr_out_entry_value(ctx
, value
, value_len
, info
, DPIPE_VALUE_TYPE_VALUE
);
4949 static int dpipe_entry_match_value_show(struct dpipe_ctx
*ctx
,
4952 struct nlattr
*nla_match_value
[DEVLINK_ATTR_MAX
+ 1] = {};
4953 struct dpipe_match match
;
4956 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_match_value
);
4957 if (err
!= MNL_CB_OK
)
4960 if (!nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
] ||
4961 !nla_match_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
4965 pr_out_entry_start(ctx
->dl
);
4966 if (dpipe_match_parse(&match
,
4967 nla_match_value
[DEVLINK_ATTR_DPIPE_MATCH
]))
4968 goto err_match_parse
;
4969 pr_out_dpipe_match(&match
, ctx
);
4970 pr_out_dpipe_entry_value(ctx
, nla_match_value
, &match
.info
);
4971 pr_out_entry_end(ctx
->dl
);
4976 pr_out_entry_end(ctx
->dl
);
4980 static int dpipe_entry_action_value_show(struct dpipe_ctx
*ctx
,
4983 struct nlattr
*nla_action_value
[DEVLINK_ATTR_MAX
+ 1] = {};
4984 struct dpipe_action action
;
4987 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_action_value
);
4988 if (err
!= MNL_CB_OK
)
4991 if (!nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
] ||
4992 !nla_action_value
[DEVLINK_ATTR_DPIPE_VALUE
]) {
4996 pr_out_entry_start(ctx
->dl
);
4997 if (dpipe_action_parse(&action
,
4998 nla_action_value
[DEVLINK_ATTR_DPIPE_ACTION
]))
4999 goto err_action_parse
;
5000 pr_out_dpipe_action(&action
, ctx
);
5001 pr_out_dpipe_entry_value(ctx
, nla_action_value
, &action
.info
);
5002 pr_out_entry_end(ctx
->dl
);
5007 pr_out_entry_end(ctx
->dl
);
5012 dpipe_tables_action_values_show(struct dpipe_ctx
*ctx
,
5013 struct nlattr
*nla_action_values
)
5015 struct nlattr
*nla_action_value
;
5017 mnl_attr_for_each_nested(nla_action_value
, nla_action_values
) {
5018 if (dpipe_entry_action_value_show(ctx
, nla_action_value
))
5025 dpipe_tables_match_values_show(struct dpipe_ctx
*ctx
,
5026 struct nlattr
*nla_match_values
)
5028 struct nlattr
*nla_match_value
;
5030 mnl_attr_for_each_nested(nla_match_value
, nla_match_values
) {
5031 if (dpipe_entry_match_value_show(ctx
, nla_match_value
))
5037 static int dpipe_entry_show(struct dpipe_ctx
*ctx
, struct nlattr
*nl
)
5039 struct nlattr
*nla_entry
[DEVLINK_ATTR_MAX
+ 1] = {};
5040 uint32_t entry_index
;
5044 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_entry
);
5045 if (err
!= MNL_CB_OK
)
5048 if (!nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
] ||
5049 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
] ||
5050 !nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]) {
5054 entry_index
= mnl_attr_get_u32(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_INDEX
]);
5055 pr_out_uint(ctx
->dl
, "index", entry_index
);
5057 if (nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]) {
5058 counter
= mnl_attr_get_u64(nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER
]);
5059 pr_out_uint(ctx
->dl
, "counter", counter
);
5062 pr_out_array_start(ctx
->dl
, "match_value");
5063 if (dpipe_tables_match_values_show(ctx
,
5064 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES
]))
5065 goto err_match_values_show
;
5066 pr_out_array_end(ctx
->dl
);
5068 pr_out_array_start(ctx
->dl
, "action_value");
5069 if (dpipe_tables_action_values_show(ctx
,
5070 nla_entry
[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES
]))
5071 goto err_action_values_show
;
5072 pr_out_array_end(ctx
->dl
);
5075 err_action_values_show
:
5076 err_match_values_show
:
5077 pr_out_array_end(ctx
->dl
);
5081 static int dpipe_table_entries_show(struct dpipe_ctx
*ctx
, struct nlattr
**tb
)
5083 struct nlattr
*nla_entries
= tb
[DEVLINK_ATTR_DPIPE_ENTRIES
];
5084 struct nlattr
*nla_entry
;
5086 mnl_attr_for_each_nested(nla_entry
, nla_entries
) {
5087 pr_out_handle_start_arr(ctx
->dl
, tb
);
5088 if (dpipe_entry_show(ctx
, nla_entry
))
5089 goto err_entry_show
;
5090 pr_out_handle_end(ctx
->dl
);
5095 pr_out_handle_end(ctx
->dl
);
5099 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5101 struct dpipe_ctx
*ctx
= data
;
5102 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5103 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5105 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5106 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5107 !tb
[DEVLINK_ATTR_DPIPE_ENTRIES
])
5108 return MNL_CB_ERROR
;
5110 if (dpipe_table_entries_show(ctx
, tb
))
5111 return MNL_CB_ERROR
;
5115 static int cmd_dpipe_table_dump(struct dl
*dl
)
5117 struct nlmsghdr
*nlh
;
5118 struct dpipe_ctx ctx
= {};
5119 uint16_t flags
= NLM_F_REQUEST
;
5122 err
= dpipe_ctx_init(&ctx
, dl
);
5126 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_DPIPE_TABLE_NAME
, 0);
5130 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_HEADERS_GET
, flags
);
5131 dl_opts_put(nlh
, dl
);
5132 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_header_cb
, &ctx
);
5134 pr_err("error get headers %s\n", strerror(ctx
.err
));
5138 flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5139 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_ENTRIES_GET
, flags
);
5140 dl_opts_put(nlh
, dl
);
5142 pr_out_section_start(dl
, "table_entry");
5143 _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_entry_dump_cb
, &ctx
);
5144 pr_out_section_end(dl
);
5146 dpipe_ctx_fini(&ctx
);
5150 static void cmd_dpipe_table_help(void)
5152 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
5153 "where OBJECT-LIST := { show | set | dump }\n");
5156 static int cmd_dpipe_table(struct dl
*dl
)
5158 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5159 cmd_dpipe_table_help();
5161 } else if (dl_argv_match(dl
, "show")) {
5163 return cmd_dpipe_table_show(dl
);
5164 } else if (dl_argv_match(dl
, "set")) {
5166 return cmd_dpipe_table_set(dl
);
5167 } else if (dl_argv_match(dl
, "dump")) {
5169 return cmd_dpipe_table_dump(dl
);
5171 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5175 static void cmd_dpipe_help(void)
5177 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
5178 "where OBJECT-LIST := { header | table }\n");
5181 static int cmd_dpipe(struct dl
*dl
)
5183 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5186 } else if (dl_argv_match(dl
, "header")) {
5188 return cmd_dpipe_header(dl
);
5189 } else if (dl_argv_match(dl
, "table")) {
5191 return cmd_dpipe_table(dl
);
5193 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5198 resource_parse(struct resource_ctx
*ctx
, struct resource
*resource
,
5199 struct nlattr
**nla_resource
)
5201 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
] ||
5202 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
] ||
5203 !nla_resource
[DEVLINK_ATTR_RESOURCE_ID
] ||
5204 !nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
] ||
5205 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
] ||
5206 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
] ||
5207 !nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]) {
5211 resource
->name
= strdup(mnl_attr_get_str(nla_resource
[DEVLINK_ATTR_RESOURCE_NAME
]));
5212 resource
->size
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE
]);
5213 resource
->id
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_ID
]);
5214 resource
->unit
= mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_UNIT
]);
5215 resource
->size_min
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MIN
]);
5216 resource
->size_max
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_MAX
]);
5217 resource
->size_gran
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_GRAN
]);
5219 if (nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
])
5220 resource
->size_new
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_NEW
]);
5222 resource
->size_new
= resource
->size
;
5224 if (nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]) {
5225 resource
->size_occ
= mnl_attr_get_u64(nla_resource
[DEVLINK_ATTR_RESOURCE_OCC
]);
5226 resource
->occ_valid
= true;
5229 if (resource
->size_new
!= resource
->size
)
5230 ctx
->pending_change
= true;
5236 resource_get(struct resource_ctx
*ctx
, struct resource
*resource
,
5237 struct resource
*parent_resource
, struct nlattr
*nl
)
5239 struct nlattr
*nla_resource
[DEVLINK_ATTR_MAX
+ 1] = {};
5240 struct nlattr
*nla_child_resource
;
5241 struct nlattr
*nla_resources
;
5251 err
= mnl_attr_parse_nested(nl
, attr_cb
, nla_resource
);
5252 if (err
!= MNL_CB_OK
)
5255 err
= resource_parse(ctx
, resource
, nla_resource
);
5259 resource
->parent
= parent_resource
;
5260 if (!nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
])
5263 resource
->size_valid
= !!mnl_attr_get_u8(nla_resource
[DEVLINK_ATTR_RESOURCE_SIZE_VALID
]);
5264 nla_resources
= nla_resource
[DEVLINK_ATTR_RESOURCE_LIST
];
5266 mnl_attr_for_each_nested(nla_child_resource
, nla_resources
) {
5267 struct resource
*child_resource
;
5268 struct list_head
*list
;
5270 child_resource
= resource_alloc();
5271 if (!child_resource
)
5275 list
= &ctx
->resources
->resource_list
;
5277 list
= &resource
->resource_list
;
5279 list_add_tail(&child_resource
->list
, list
);
5280 err
= resource_get(ctx
, child_resource
, resource
,
5281 nla_child_resource
);
5289 static const char *resource_unit_str_get(enum devlink_resource_unit unit
)
5292 case DEVLINK_RESOURCE_UNIT_ENTRY
: return "entry";
5293 default: return "<unknown unit>";
5297 static void resource_show(struct resource
*resource
,
5298 struct resource_ctx
*ctx
)
5300 struct resource
*child_resource
;
5301 struct dpipe_table
*table
;
5302 struct dl
*dl
= ctx
->dl
;
5305 pr_out_str(dl
, "name", resource
->name
);
5307 resource_path_print(dl
, ctx
->resources
, resource
->id
);
5308 pr_out_u64(dl
, "size", resource
->size
);
5309 if (resource
->size
!= resource
->size_new
)
5310 pr_out_u64(dl
, "size_new", resource
->size_new
);
5311 if (resource
->occ_valid
)
5312 pr_out_uint(dl
, "occ", resource
->size_occ
);
5313 pr_out_str(dl
, "unit", resource_unit_str_get(resource
->unit
));
5315 if (resource
->size_min
!= resource
->size_max
) {
5316 pr_out_uint(dl
, "size_min", resource
->size_min
);
5317 pr_out_u64(dl
, "size_max", resource
->size_max
);
5318 pr_out_uint(dl
, "size_gran", resource
->size_gran
);
5321 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
)
5322 if (table
->resource_id
== resource
->id
&&
5323 table
->resource_valid
)
5327 pr_out_array_start(dl
, "dpipe_tables");
5329 pr_out_str(dl
, "dpipe_tables", "none");
5331 list_for_each_entry(table
, &ctx
->tables
->table_list
, list
) {
5332 if (table
->resource_id
!= resource
->id
||
5333 !table
->resource_valid
)
5335 pr_out_entry_start(dl
);
5336 pr_out_str(dl
, "table_name", table
->name
);
5337 pr_out_entry_end(dl
);
5340 pr_out_array_end(dl
);
5342 if (list_empty(&resource
->resource_list
))
5345 if (ctx
->pending_change
)
5346 pr_out_str(dl
, "size_valid", resource
->size_valid
?
5348 pr_out_array_start(dl
, "resources");
5349 list_for_each_entry(child_resource
, &resource
->resource_list
, list
) {
5350 pr_out_entry_start(dl
);
5351 resource_show(child_resource
, ctx
);
5352 pr_out_entry_end(dl
);
5354 pr_out_array_end(dl
);
5358 resources_show(struct resource_ctx
*ctx
, struct nlattr
**tb
)
5360 struct resources
*resources
= ctx
->resources
;
5361 struct resource
*resource
;
5363 list_for_each_entry(resource
, &resources
->resource_list
, list
) {
5364 pr_out_handle_start_arr(ctx
->dl
, tb
);
5365 resource_show(resource
, ctx
);
5366 pr_out_handle_end(ctx
->dl
);
5370 static int resources_get(struct resource_ctx
*ctx
, struct nlattr
**tb
)
5372 return resource_get(ctx
, NULL
, NULL
, tb
[DEVLINK_ATTR_RESOURCE_LIST
]);
5375 static int cmd_resource_dump_cb(const struct nlmsghdr
*nlh
, void *data
)
5377 struct resource_ctx
*ctx
= data
;
5378 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5379 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5382 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5383 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5384 !tb
[DEVLINK_ATTR_RESOURCE_LIST
])
5385 return MNL_CB_ERROR
;
5387 err
= resources_get(ctx
, tb
);
5390 return MNL_CB_ERROR
;
5393 if (ctx
->print_resources
)
5394 resources_show(ctx
, tb
);
5399 static int cmd_resource_show(struct dl
*dl
)
5401 struct nlmsghdr
*nlh
;
5402 struct dpipe_ctx dpipe_ctx
= {};
5403 struct resource_ctx resource_ctx
= {};
5406 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
, 0);
5410 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_DPIPE_TABLE_GET
,
5412 dl_opts_put(nlh
, dl
);
5414 err
= dpipe_ctx_init(&dpipe_ctx
, dl
);
5418 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_dpipe_table_show_cb
,
5421 pr_err("error get tables %s\n", strerror(dpipe_ctx
.err
));
5425 err
= resource_ctx_init(&resource_ctx
, dl
);
5429 resource_ctx
.print_resources
= true;
5430 resource_ctx
.tables
= dpipe_ctx
.tables
;
5431 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
5432 NLM_F_REQUEST
| NLM_F_ACK
);
5433 dl_opts_put(nlh
, dl
);
5434 pr_out_section_start(dl
, "resources");
5435 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
,
5437 pr_out_section_end(dl
);
5438 resource_ctx_fini(&resource_ctx
);
5440 dpipe_ctx_fini(&dpipe_ctx
);
5444 static void cmd_resource_help(void)
5446 pr_err("Usage: devlink resource show DEV\n"
5447 " devlink resource set DEV path PATH size SIZE\n");
5450 static struct resource
*
5451 resource_find_by_name(struct list_head
*list
, char *name
)
5453 struct resource
*resource
;
5455 list_for_each_entry(resource
, list
, list
) {
5456 if (!strcmp(resource
->name
, name
))
5463 resource_path_parse(struct resource_ctx
*ctx
, const char *resource_path
,
5464 uint32_t *p_resource_id
, bool *p_resource_valid
)
5466 struct resource
*resource
;
5467 uint32_t resource_id
= 0;
5468 char *resource_path_dup
;
5469 struct list_head
*list
;
5470 const char del
[] = "/";
5471 char *resource_name
;
5473 resource_path_dup
= strdup(resource_path
);
5474 list
= &ctx
->resources
->resource_list
;
5475 resource_name
= strtok(resource_path_dup
, del
);
5476 while (resource_name
!= NULL
) {
5477 resource
= resource_find_by_name(list
, resource_name
);
5479 goto err_resource_lookup
;
5481 list
= &resource
->resource_list
;
5482 resource_name
= strtok(NULL
, del
);
5483 resource_id
= resource
->id
;
5485 free(resource_path_dup
);
5486 *p_resource_valid
= true;
5487 *p_resource_id
= resource_id
;
5490 err_resource_lookup
:
5491 free(resource_path_dup
);
5495 static int cmd_resource_set(struct dl
*dl
)
5497 struct nlmsghdr
*nlh
;
5498 struct resource_ctx ctx
= {};
5501 err
= resource_ctx_init(&ctx
, dl
);
5505 ctx
.print_resources
= false;
5506 err
= dl_argv_parse(dl
, DL_OPT_HANDLE
| DL_OPT_RESOURCE_PATH
|
5507 DL_OPT_RESOURCE_SIZE
, 0);
5511 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_DUMP
,
5513 dl_opts_put(nlh
, dl
);
5514 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_resource_dump_cb
, &ctx
);
5516 pr_err("error getting resources %s\n", strerror(ctx
.err
));
5520 err
= resource_path_parse(&ctx
, dl
->opts
.resource_path
,
5521 &dl
->opts
.resource_id
,
5522 &dl
->opts
.resource_id_valid
);
5524 pr_err("error parsing resource path %s\n", strerror(-err
));
5528 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_RESOURCE_SET
,
5529 NLM_F_REQUEST
| NLM_F_ACK
);
5531 dl_opts_put(nlh
, dl
);
5532 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5534 resource_ctx_fini(&ctx
);
5538 static int cmd_resource(struct dl
*dl
)
5540 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
5541 cmd_resource_help();
5543 } else if (dl_argv_match(dl
, "show")) {
5545 return cmd_resource_show(dl
);
5546 } else if (dl_argv_match(dl
, "set")) {
5548 return cmd_resource_set(dl
);
5550 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5554 static void pr_out_region_handle_start(struct dl
*dl
, struct nlattr
**tb
)
5556 const char *bus_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_BUS_NAME
]);
5557 const char *dev_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_DEV_NAME
]);
5558 const char *region_name
= mnl_attr_get_str(tb
[DEVLINK_ATTR_REGION_NAME
]);
5561 sprintf(buf
, "%s/%s/%s", bus_name
, dev_name
, region_name
);
5562 if (dl
->json_output
) {
5563 jsonw_name(dl
->jw
, buf
);
5564 jsonw_start_object(dl
->jw
);
5570 static void pr_out_region_handle_end(struct dl
*dl
)
5572 if (dl
->json_output
)
5573 jsonw_end_object(dl
->jw
);
5578 static void pr_out_region_snapshots_start(struct dl
*dl
, bool array
)
5580 if (dl
->json_output
) {
5581 jsonw_name(dl
->jw
, "snapshot");
5582 jsonw_start_array(dl
->jw
);
5584 if (g_indent_newline
)
5585 pr_out("snapshot %s", array
? "[" : "");
5587 pr_out(" snapshot %s", array
? "[" : "");
5591 static void pr_out_region_snapshots_end(struct dl
*dl
, bool array
)
5593 if (dl
->json_output
)
5594 jsonw_end_array(dl
->jw
);
5599 static void pr_out_region_snapshots_id(struct dl
*dl
, struct nlattr
**tb
, int index
)
5601 uint32_t snapshot_id
;
5603 if (!tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
5606 snapshot_id
= mnl_attr_get_u32(tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
]);
5608 if (dl
->json_output
)
5609 jsonw_uint(dl
->jw
, snapshot_id
);
5611 pr_out("%s%u", index
? " " : "", snapshot_id
);
5614 static void pr_out_snapshots(struct dl
*dl
, struct nlattr
**tb
)
5616 struct nlattr
*tb_snapshot
[DEVLINK_ATTR_MAX
+ 1] = {};
5617 struct nlattr
*nla_sanpshot
;
5620 pr_out_region_snapshots_start(dl
, true);
5621 mnl_attr_for_each_nested(nla_sanpshot
, tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
]) {
5622 err
= mnl_attr_parse_nested(nla_sanpshot
, attr_cb
, tb_snapshot
);
5623 if (err
!= MNL_CB_OK
)
5625 pr_out_region_snapshots_id(dl
, tb_snapshot
, index
++);
5627 pr_out_region_snapshots_end(dl
, true);
5630 static void pr_out_snapshot(struct dl
*dl
, struct nlattr
**tb
)
5632 pr_out_region_snapshots_start(dl
, false);
5633 pr_out_region_snapshots_id(dl
, tb
, 0);
5634 pr_out_region_snapshots_end(dl
, false);
5637 static void pr_out_region(struct dl
*dl
, struct nlattr
**tb
)
5639 pr_out_region_handle_start(dl
, tb
);
5641 if (tb
[DEVLINK_ATTR_REGION_SIZE
])
5642 pr_out_u64(dl
, "size",
5643 mnl_attr_get_u64(tb
[DEVLINK_ATTR_REGION_SIZE
]));
5645 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOTS
])
5646 pr_out_snapshots(dl
, tb
);
5648 if (tb
[DEVLINK_ATTR_REGION_SNAPSHOT_ID
])
5649 pr_out_snapshot(dl
, tb
);
5651 pr_out_region_handle_end(dl
);
5654 static int cmd_region_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5656 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5657 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5658 struct dl
*dl
= data
;
5660 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5661 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5662 !tb
[DEVLINK_ATTR_REGION_NAME
] || !tb
[DEVLINK_ATTR_REGION_SIZE
])
5663 return MNL_CB_ERROR
;
5665 pr_out_region(dl
, tb
);
5670 static int cmd_region_show(struct dl
*dl
)
5672 struct nlmsghdr
*nlh
;
5673 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5676 if (dl_argc(dl
) == 0)
5677 flags
|= NLM_F_DUMP
;
5679 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_GET
, flags
);
5681 if (dl_argc(dl
) > 0) {
5682 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
, 0);
5687 pr_out_section_start(dl
, "regions");
5688 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_show_cb
, dl
);
5689 pr_out_section_end(dl
);
5693 static int cmd_region_snapshot_del(struct dl
*dl
)
5695 struct nlmsghdr
*nlh
;
5698 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_DEL
,
5699 NLM_F_REQUEST
| NLM_F_ACK
);
5701 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
5702 DL_OPT_REGION_SNAPSHOT_ID
, 0);
5706 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5709 static int cmd_region_read_cb(const struct nlmsghdr
*nlh
, void *data
)
5711 struct nlattr
*nla_entry
, *nla_chunk_data
, *nla_chunk_addr
;
5712 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5713 struct nlattr
*tb_field
[DEVLINK_ATTR_MAX
+ 1] = {};
5714 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5715 struct dl
*dl
= data
;
5718 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5719 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5720 !tb
[DEVLINK_ATTR_REGION_CHUNKS
])
5721 return MNL_CB_ERROR
;
5723 mnl_attr_for_each_nested(nla_entry
, tb
[DEVLINK_ATTR_REGION_CHUNKS
]) {
5724 err
= mnl_attr_parse_nested(nla_entry
, attr_cb
, tb_field
);
5725 if (err
!= MNL_CB_OK
)
5726 return MNL_CB_ERROR
;
5728 nla_chunk_data
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_DATA
];
5729 if (!nla_chunk_data
)
5732 nla_chunk_addr
= tb_field
[DEVLINK_ATTR_REGION_CHUNK_ADDR
];
5733 if (!nla_chunk_addr
)
5736 pr_out_region_chunk(dl
, mnl_attr_get_payload(nla_chunk_data
),
5737 mnl_attr_get_payload_len(nla_chunk_data
),
5738 mnl_attr_get_u64(nla_chunk_addr
));
5743 static int cmd_region_dump(struct dl
*dl
)
5745 struct nlmsghdr
*nlh
;
5748 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
5749 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
5751 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
5752 DL_OPT_REGION_SNAPSHOT_ID
, 0);
5756 pr_out_section_start(dl
, "dump");
5757 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
5758 pr_out_section_end(dl
);
5759 if (!dl
->json_output
)
5764 static int cmd_region_read(struct dl
*dl
)
5766 struct nlmsghdr
*nlh
;
5769 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_REGION_READ
,
5770 NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_DUMP
);
5772 err
= dl_argv_parse_put(nlh
, dl
, DL_OPT_HANDLE_REGION
|
5773 DL_OPT_REGION_ADDRESS
| DL_OPT_REGION_LENGTH
|
5774 DL_OPT_REGION_SNAPSHOT_ID
, 0);
5778 pr_out_section_start(dl
, "read");
5779 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_region_read_cb
, dl
);
5780 pr_out_section_end(dl
);
5781 if (!dl
->json_output
)
5786 static void cmd_region_help(void)
5788 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
5789 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
5790 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
5791 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
5794 static int cmd_region(struct dl
*dl
)
5796 if (dl_no_arg(dl
)) {
5797 return cmd_region_show(dl
);
5798 } else if (dl_argv_match(dl
, "help")) {
5801 } else if (dl_argv_match(dl
, "show")) {
5803 return cmd_region_show(dl
);
5804 } else if (dl_argv_match(dl
, "del")) {
5806 return cmd_region_snapshot_del(dl
);
5807 } else if (dl_argv_match(dl
, "dump")) {
5809 return cmd_region_dump(dl
);
5810 } else if (dl_argv_match(dl
, "read")) {
5812 return cmd_region_read(dl
);
5814 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5818 static int cmd_health_recover(struct dl
*dl
)
5820 struct nlmsghdr
*nlh
;
5823 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_RECOVER
,
5824 NLM_F_REQUEST
| NLM_F_ACK
);
5826 err
= dl_argv_parse_put(nlh
, dl
,
5827 DL_OPT_HANDLE
| DL_OPT_HEALTH_REPORTER_NAME
, 0);
5831 dl_opts_put(nlh
, dl
);
5832 return _mnlg_socket_sndrcv(dl
->nlg
, nlh
, NULL
, NULL
);
5835 enum devlink_health_reporter_state
{
5836 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
,
5837 DEVLINK_HEALTH_REPORTER_STATE_ERROR
,
5840 static const char *health_state_name(uint8_t state
)
5843 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY
:
5844 return HEALTH_REPORTER_STATE_HEALTHY_STR
;
5845 case DEVLINK_HEALTH_REPORTER_STATE_ERROR
:
5846 return HEALTH_REPORTER_STATE_ERROR_STR
;
5848 return "<unknown state>";
5852 static void format_logtime(uint64_t time_ms
, char *ts_date
, char *ts_time
)
5854 struct sysinfo s_info
;
5860 info
= localtime(&now
);
5861 err
= sysinfo(&s_info
);
5864 /* Subtract uptime in sec from now yields the time of system
5865 * uptime. To this, add time_ms which is the amount of
5866 * milliseconds elapsed between uptime and the dump taken.
5868 sec
= now
- s_info
.uptime
+ time_ms
/ 1000;
5869 info
= localtime(&sec
);
5871 strftime(ts_date
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%Y-%m-%d", info
);
5872 strftime(ts_time
, HEALTH_REPORTER_TIMESTAMP_FMT_LEN
, "%H:%M:%S", info
);
5875 static void pr_out_health(struct dl
*dl
, struct nlattr
**tb_health
)
5877 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5878 enum devlink_health_reporter_state state
;
5879 const struct nlattr
*attr
;
5883 err
= mnl_attr_parse_nested(tb_health
[DEVLINK_ATTR_HEALTH_REPORTER
],
5885 if (err
!= MNL_CB_OK
)
5888 if (!tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
] ||
5889 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
] ||
5890 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
] ||
5891 !tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
])
5894 pr_out_handle_start_arr(dl
, tb_health
);
5896 pr_out_str(dl
, "name",
5897 mnl_attr_get_str(tb
[DEVLINK_ATTR_HEALTH_REPORTER_NAME
]));
5898 if (!dl
->json_output
) {
5900 __pr_out_indent_inc();
5902 state
= mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_STATE
]);
5903 pr_out_str(dl
, "state", health_state_name(state
));
5904 pr_out_u64(dl
, "error",
5905 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT
]));
5906 pr_out_u64(dl
, "recover",
5907 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT
]));
5908 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
]) {
5909 char dump_date
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
5910 char dump_time
[HEALTH_REPORTER_TIMESTAMP_FMT_LEN
];
5912 attr
= tb
[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS
];
5913 time_ms
= mnl_attr_get_u64(attr
);
5914 format_logtime(time_ms
, dump_date
, dump_time
);
5916 pr_out_str(dl
, "last_dump_date", dump_date
);
5917 pr_out_str(dl
, "last_dump_time", dump_time
);
5919 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
])
5920 pr_out_u64(dl
, "grace_period",
5921 mnl_attr_get_u64(tb
[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD
]));
5922 if (tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
])
5923 pr_out_bool(dl
, "auto_recover",
5924 mnl_attr_get_u8(tb
[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER
]));
5926 __pr_out_indent_dec();
5927 pr_out_handle_end(dl
);
5930 static int cmd_health_show_cb(const struct nlmsghdr
*nlh
, void *data
)
5932 struct genlmsghdr
*genl
= mnl_nlmsg_get_payload(nlh
);
5933 struct nlattr
*tb
[DEVLINK_ATTR_MAX
+ 1] = {};
5934 struct dl
*dl
= data
;
5936 mnl_attr_parse(nlh
, sizeof(*genl
), attr_cb
, tb
);
5937 if (!tb
[DEVLINK_ATTR_BUS_NAME
] || !tb
[DEVLINK_ATTR_DEV_NAME
] ||
5938 !tb
[DEVLINK_ATTR_HEALTH_REPORTER
])
5939 return MNL_CB_ERROR
;
5941 pr_out_health(dl
, tb
);
5946 static int cmd_health_show(struct dl
*dl
)
5948 struct nlmsghdr
*nlh
;
5949 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
;
5952 if (dl_argc(dl
) == 0)
5953 flags
|= NLM_F_DUMP
;
5954 nlh
= mnlg_msg_prepare(dl
->nlg
, DEVLINK_CMD_HEALTH_REPORTER_GET
,
5957 if (dl_argc(dl
) > 0) {
5958 err
= dl_argv_parse_put(nlh
, dl
,
5960 DL_OPT_HEALTH_REPORTER_NAME
, 0);
5964 pr_out_section_start(dl
, "health");
5966 err
= _mnlg_socket_sndrcv(dl
->nlg
, nlh
, cmd_health_show_cb
, dl
);
5967 pr_out_section_end(dl
);
5971 static void cmd_health_help(void)
5973 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
5974 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
5977 static int cmd_health(struct dl
*dl
)
5979 if (dl_argv_match(dl
, "help")) {
5982 } else if (dl_argv_match(dl
, "show") ||
5983 dl_argv_match(dl
, "list") || dl_no_arg(dl
)) {
5985 return cmd_health_show(dl
);
5986 } else if (dl_argv_match(dl
, "recover")) {
5988 return cmd_health_recover(dl
);
5990 pr_err("Command \"%s\" not found\n", dl_argv(dl
));
5994 static void help(void)
5996 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
5997 " devlink [ -f[orce] ] -b[atch] filename\n"
5998 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health }\n"
5999 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] }\n");
6002 static int dl_cmd(struct dl
*dl
, int argc
, char **argv
)
6007 if (dl_argv_match(dl
, "help") || dl_no_arg(dl
)) {
6010 } else if (dl_argv_match(dl
, "dev")) {
6013 } else if (dl_argv_match(dl
, "port")) {
6015 return cmd_port(dl
);
6016 } else if (dl_argv_match(dl
, "sb")) {
6019 } else if (dl_argv_match(dl
, "monitor")) {
6022 } else if (dl_argv_match(dl
, "dpipe")) {
6024 return cmd_dpipe(dl
);
6025 } else if (dl_argv_match(dl
, "resource")) {
6027 return cmd_resource(dl
);
6028 } else if (dl_argv_match(dl
, "region")) {
6030 return cmd_region(dl
);
6031 } else if (dl_argv_match(dl
, "health")) {
6033 return cmd_health(dl
);
6035 pr_err("Object \"%s\" not found\n", dl_argv(dl
));
6039 static int dl_init(struct dl
*dl
)
6043 dl
->nlg
= mnlg_socket_open(DEVLINK_GENL_NAME
, DEVLINK_GENL_VERSION
);
6045 pr_err("Failed to connect to devlink Netlink\n");
6049 err
= ifname_map_init(dl
);
6051 pr_err("Failed to create index map\n");
6052 goto err_ifname_map_create
;
6054 if (dl
->json_output
) {
6055 dl
->jw
= jsonw_new(stdout
);
6057 pr_err("Failed to create JSON writer\n");
6060 jsonw_pretty(dl
->jw
, dl
->pretty_output
);
6065 ifname_map_fini(dl
);
6066 err_ifname_map_create
:
6067 mnlg_socket_close(dl
->nlg
);
6071 static void dl_fini(struct dl
*dl
)
6073 if (dl
->json_output
)
6074 jsonw_destroy(&dl
->jw
);
6075 ifname_map_fini(dl
);
6076 mnlg_socket_close(dl
->nlg
);
6079 static struct dl
*dl_alloc(void)
6083 dl
= calloc(1, sizeof(*dl
));
6089 static void dl_free(struct dl
*dl
)
6094 static int dl_batch(struct dl
*dl
, const char *name
, bool force
)
6098 int ret
= EXIT_SUCCESS
;
6100 if (name
&& strcmp(name
, "-") != 0) {
6101 if (freopen(name
, "r", stdin
) == NULL
) {
6103 "Cannot open file \"%s\" for reading: %s\n",
6104 name
, strerror(errno
));
6105 return EXIT_FAILURE
;
6110 while (getcmdline(&line
, &len
, stdin
) != -1) {
6114 largc
= makeargs(line
, largv
, 100);
6116 continue; /* blank line */
6118 if (dl_cmd(dl
, largc
, largv
)) {
6119 fprintf(stderr
, "Command failed %s:%d\n",
6133 int main(int argc
, char **argv
)
6135 static const struct option long_options
[] = {
6136 { "Version", no_argument
, NULL
, 'V' },
6137 { "force", no_argument
, NULL
, 'f' },
6138 { "batch", required_argument
, NULL
, 'b' },
6139 { "no-nice-names", no_argument
, NULL
, 'n' },
6140 { "json", no_argument
, NULL
, 'j' },
6141 { "pretty", no_argument
, NULL
, 'p' },
6142 { "verbose", no_argument
, NULL
, 'v' },
6143 { NULL
, 0, NULL
, 0 }
6145 const char *batch_file
= NULL
;
6154 pr_err("Failed to allocate memory for devlink\n");
6155 return EXIT_FAILURE
;
6158 while ((opt
= getopt_long(argc
, argv
, "Vfb:njpv",
6159 long_options
, NULL
)) >= 0) {
6163 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT
);
6170 batch_file
= optarg
;
6173 dl
->no_nice_names
= true;
6176 dl
->json_output
= true;
6179 dl
->pretty_output
= true;
6185 pr_err("Unknown option.\n");
6202 err
= dl_batch(dl
, batch_file
, force
);
6204 err
= dl_cmd(dl
, argc
, argv
);