]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
0293373928f50c9328e1e376122361e1ec444a67
[mirror_iproute2.git] / devlink / devlink.c
1 /*
2 * devlink.c Devlink tool
3 *
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.
8 *
9 * Authors: Jiri Pirko <jiri@mellanox.com>
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdarg.h>
15 #include <string.h>
16 #include <stdbool.h>
17 #include <unistd.h>
18 #include <getopt.h>
19 #include <limits.h>
20 #include <errno.h>
21 #include <inttypes.h>
22 #include <sys/sysinfo.h>
23 #define _LINUX_SYSINFO_H /* avoid collision with musl header */
24 #include <linux/genetlink.h>
25 #include <linux/devlink.h>
26 #include <libmnl/libmnl.h>
27 #include <netinet/ether.h>
28
29 #include "SNAPSHOT.h"
30 #include "list.h"
31 #include "mnlg.h"
32 #include "json_writer.h"
33 #include "utils.h"
34
35 #define ESWITCH_MODE_LEGACY "legacy"
36 #define ESWITCH_MODE_SWITCHDEV "switchdev"
37 #define ESWITCH_INLINE_MODE_NONE "none"
38 #define ESWITCH_INLINE_MODE_LINK "link"
39 #define ESWITCH_INLINE_MODE_NETWORK "network"
40 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
41
42 #define PARAM_CMODE_RUNTIME_STR "runtime"
43 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
44 #define PARAM_CMODE_PERMANENT_STR "permanent"
45 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
46
47 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
48 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
49 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
50
51 static int g_new_line_count;
52 static int g_indent_level;
53 static bool g_indent_newline;
54
55 #define INDENT_STR_STEP 2
56 #define INDENT_STR_MAXLEN 32
57 static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
58
59 static void __attribute__((format(printf, 1, 2)))
60 pr_err(const char *fmt, ...)
61 {
62 va_list ap;
63
64 va_start(ap, fmt);
65 vfprintf(stderr, fmt, ap);
66 va_end(ap);
67 }
68
69 static void __attribute__((format(printf, 1, 2)))
70 pr_out(const char *fmt, ...)
71 {
72 va_list ap;
73
74 if (g_indent_newline) {
75 printf("%s", g_indent_str);
76 g_indent_newline = false;
77 }
78 va_start(ap, fmt);
79 vprintf(fmt, ap);
80 va_end(ap);
81 g_new_line_count = 0;
82 }
83
84 static void __attribute__((format(printf, 2, 3)))
85 pr_out_sp(unsigned int num, const char *fmt, ...)
86 {
87 va_list ap;
88 int ret;
89
90 va_start(ap, fmt);
91 ret = vprintf(fmt, ap);
92 va_end(ap);
93
94 if (ret < num)
95 printf("%*s", num - ret, "");
96 g_new_line_count = 0; \
97 }
98
99 static void __pr_out_indent_inc(void)
100 {
101 if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
102 return;
103 g_indent_level += INDENT_STR_STEP;
104 memset(g_indent_str, ' ', sizeof(g_indent_str));
105 g_indent_str[g_indent_level] = '\0';
106 }
107
108 static void __pr_out_indent_dec(void)
109 {
110 if (g_indent_level - INDENT_STR_STEP < 0)
111 return;
112 g_indent_level -= INDENT_STR_STEP;
113 g_indent_str[g_indent_level] = '\0';
114 }
115
116 static void __pr_out_newline(void)
117 {
118 if (g_new_line_count < 1) {
119 pr_out("\n");
120 g_indent_newline = true;
121 }
122 g_new_line_count++;
123 }
124
125 static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
126 mnl_cb_t data_cb, void *data)
127 {
128 int err;
129
130 err = mnlg_socket_recv_run(nlg, data_cb, data);
131 if (err < 0) {
132 pr_err("devlink answers: %s\n", strerror(errno));
133 return -errno;
134 }
135 return 0;
136 }
137
138 static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
139 const struct nlmsghdr *nlh,
140 mnl_cb_t data_cb, void *data)
141 {
142 int err;
143
144 err = mnlg_socket_send(nlg, nlh);
145 if (err < 0) {
146 pr_err("Failed to call mnlg_socket_send\n");
147 return -errno;
148 }
149 return _mnlg_socket_recv_run(nlg, data_cb, data);
150 }
151
152 static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
153 const char *group_name)
154 {
155 int err;
156
157 err = mnlg_socket_group_add(nlg, group_name);
158 if (err < 0) {
159 pr_err("Failed to call mnlg_socket_group_add\n");
160 return -errno;
161 }
162 return 0;
163 }
164
165 struct ifname_map {
166 struct list_head list;
167 char *bus_name;
168 char *dev_name;
169 uint32_t port_index;
170 char *ifname;
171 };
172
173 static struct ifname_map *ifname_map_alloc(const char *bus_name,
174 const char *dev_name,
175 uint32_t port_index,
176 const char *ifname)
177 {
178 struct ifname_map *ifname_map;
179
180 ifname_map = calloc(1, sizeof(*ifname_map));
181 if (!ifname_map)
182 return NULL;
183 ifname_map->bus_name = strdup(bus_name);
184 ifname_map->dev_name = strdup(dev_name);
185 ifname_map->port_index = port_index;
186 ifname_map->ifname = strdup(ifname);
187 if (!ifname_map->bus_name || !ifname_map->dev_name ||
188 !ifname_map->ifname) {
189 free(ifname_map->ifname);
190 free(ifname_map->dev_name);
191 free(ifname_map->bus_name);
192 free(ifname_map);
193 return NULL;
194 }
195 return ifname_map;
196 }
197
198 static void ifname_map_free(struct ifname_map *ifname_map)
199 {
200 free(ifname_map->ifname);
201 free(ifname_map->dev_name);
202 free(ifname_map->bus_name);
203 free(ifname_map);
204 }
205
206 #define DL_OPT_HANDLE BIT(0)
207 #define DL_OPT_HANDLEP BIT(1)
208 #define DL_OPT_PORT_TYPE BIT(2)
209 #define DL_OPT_PORT_COUNT BIT(3)
210 #define DL_OPT_SB BIT(4)
211 #define DL_OPT_SB_POOL BIT(5)
212 #define DL_OPT_SB_SIZE BIT(6)
213 #define DL_OPT_SB_TYPE BIT(7)
214 #define DL_OPT_SB_THTYPE BIT(8)
215 #define DL_OPT_SB_TH BIT(9)
216 #define DL_OPT_SB_TC BIT(10)
217 #define DL_OPT_ESWITCH_MODE BIT(11)
218 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
219 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
220 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
221 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
222 #define DL_OPT_RESOURCE_PATH BIT(16)
223 #define DL_OPT_RESOURCE_SIZE BIT(17)
224 #define DL_OPT_PARAM_NAME BIT(18)
225 #define DL_OPT_PARAM_VALUE BIT(19)
226 #define DL_OPT_PARAM_CMODE BIT(20)
227 #define DL_OPT_HANDLE_REGION BIT(21)
228 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
229 #define DL_OPT_REGION_ADDRESS BIT(23)
230 #define DL_OPT_REGION_LENGTH BIT(24)
231 #define DL_OPT_FLASH_FILE_NAME BIT(25)
232 #define DL_OPT_FLASH_COMPONENT BIT(26)
233 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
234 #define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(28)
235 #define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(29)
236
237 struct dl_opts {
238 uint32_t present; /* flags of present items */
239 char *bus_name;
240 char *dev_name;
241 uint32_t port_index;
242 enum devlink_port_type port_type;
243 uint32_t port_count;
244 uint32_t sb_index;
245 uint16_t sb_pool_index;
246 uint32_t sb_pool_size;
247 enum devlink_sb_pool_type sb_pool_type;
248 enum devlink_sb_threshold_type sb_pool_thtype;
249 uint32_t sb_threshold;
250 uint16_t sb_tc_index;
251 enum devlink_eswitch_mode eswitch_mode;
252 enum devlink_eswitch_inline_mode eswitch_inline_mode;
253 const char *dpipe_table_name;
254 bool dpipe_counters_enable;
255 bool eswitch_encap_mode;
256 const char *resource_path;
257 uint32_t resource_size;
258 uint32_t resource_id;
259 bool resource_id_valid;
260 const char *param_name;
261 const char *param_value;
262 enum devlink_param_cmode cmode;
263 char *region_name;
264 uint32_t region_snapshot_id;
265 uint64_t region_address;
266 uint64_t region_length;
267 const char *flash_file_name;
268 const char *flash_component;
269 const char *reporter_name;
270 uint64_t reporter_graceful_period;
271 bool reporter_auto_recover;
272 };
273
274 struct dl {
275 struct mnlg_socket *nlg;
276 struct list_head ifname_map_list;
277 int argc;
278 char **argv;
279 bool no_nice_names;
280 struct dl_opts opts;
281 json_writer_t *jw;
282 bool json_output;
283 bool pretty_output;
284 bool verbose;
285 struct {
286 bool present;
287 char *bus_name;
288 char *dev_name;
289 uint32_t port_index;
290 } arr_last;
291 };
292
293 static int dl_argc(struct dl *dl)
294 {
295 return dl->argc;
296 }
297
298 static char *dl_argv(struct dl *dl)
299 {
300 if (dl_argc(dl) == 0)
301 return NULL;
302 return *dl->argv;
303 }
304
305 static void dl_arg_inc(struct dl *dl)
306 {
307 if (dl_argc(dl) == 0)
308 return;
309 dl->argc--;
310 dl->argv++;
311 }
312
313 static char *dl_argv_next(struct dl *dl)
314 {
315 char *ret;
316
317 if (dl_argc(dl) == 0)
318 return NULL;
319
320 ret = *dl->argv;
321 dl_arg_inc(dl);
322 return ret;
323 }
324
325 static char *dl_argv_index(struct dl *dl, unsigned int index)
326 {
327 if (index >= dl_argc(dl))
328 return NULL;
329 return dl->argv[index];
330 }
331
332 static int strcmpx(const char *str1, const char *str2)
333 {
334 if (strlen(str1) > strlen(str2))
335 return -1;
336 return strncmp(str1, str2, strlen(str1));
337 }
338
339 static bool dl_argv_match(struct dl *dl, const char *pattern)
340 {
341 if (dl_argc(dl) == 0)
342 return false;
343 return strcmpx(dl_argv(dl), pattern) == 0;
344 }
345
346 static bool dl_no_arg(struct dl *dl)
347 {
348 return dl_argc(dl) == 0;
349 }
350
351 static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
352 [DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
353 [DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
354 [DEVLINK_ATTR_PORT_INDEX] = MNL_TYPE_U32,
355 [DEVLINK_ATTR_PORT_TYPE] = MNL_TYPE_U16,
356 [DEVLINK_ATTR_PORT_DESIRED_TYPE] = MNL_TYPE_U16,
357 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX] = MNL_TYPE_U32,
358 [DEVLINK_ATTR_PORT_NETDEV_NAME] = MNL_TYPE_NUL_STRING,
359 [DEVLINK_ATTR_PORT_IBDEV_NAME] = MNL_TYPE_NUL_STRING,
360 [DEVLINK_ATTR_SB_INDEX] = MNL_TYPE_U32,
361 [DEVLINK_ATTR_SB_SIZE] = MNL_TYPE_U32,
362 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] = MNL_TYPE_U16,
363 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] = MNL_TYPE_U16,
364 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT] = MNL_TYPE_U16,
365 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT] = MNL_TYPE_U16,
366 [DEVLINK_ATTR_SB_POOL_INDEX] = MNL_TYPE_U16,
367 [DEVLINK_ATTR_SB_POOL_TYPE] = MNL_TYPE_U8,
368 [DEVLINK_ATTR_SB_POOL_SIZE] = MNL_TYPE_U32,
369 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = MNL_TYPE_U8,
370 [DEVLINK_ATTR_SB_THRESHOLD] = MNL_TYPE_U32,
371 [DEVLINK_ATTR_SB_TC_INDEX] = MNL_TYPE_U16,
372 [DEVLINK_ATTR_SB_OCC_CUR] = MNL_TYPE_U32,
373 [DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
374 [DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
375 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
376 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = MNL_TYPE_U8,
377 [DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED,
378 [DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED,
379 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING,
380 [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = MNL_TYPE_U64,
381 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = MNL_TYPE_NESTED,
382 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = MNL_TYPE_NESTED,
383 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = MNL_TYPE_U8,
384 [DEVLINK_ATTR_DPIPE_ENTRIES] = MNL_TYPE_NESTED,
385 [DEVLINK_ATTR_DPIPE_ENTRY] = MNL_TYPE_NESTED,
386 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = MNL_TYPE_U64,
387 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = MNL_TYPE_NESTED,
388 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = MNL_TYPE_NESTED,
389 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = MNL_TYPE_U64,
390 [DEVLINK_ATTR_DPIPE_MATCH] = MNL_TYPE_NESTED,
391 [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = MNL_TYPE_NESTED,
392 [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = MNL_TYPE_U32,
393 [DEVLINK_ATTR_DPIPE_ACTION] = MNL_TYPE_NESTED,
394 [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = MNL_TYPE_NESTED,
395 [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = MNL_TYPE_U32,
396 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = MNL_TYPE_U32,
397 [DEVLINK_ATTR_DPIPE_HEADERS] = MNL_TYPE_NESTED,
398 [DEVLINK_ATTR_DPIPE_HEADER] = MNL_TYPE_NESTED,
399 [DEVLINK_ATTR_DPIPE_HEADER_NAME] = MNL_TYPE_STRING,
400 [DEVLINK_ATTR_DPIPE_HEADER_ID] = MNL_TYPE_U32,
401 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = MNL_TYPE_NESTED,
402 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = MNL_TYPE_U8,
403 [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = MNL_TYPE_U32,
404 [DEVLINK_ATTR_DPIPE_FIELD] = MNL_TYPE_NESTED,
405 [DEVLINK_ATTR_DPIPE_FIELD_NAME] = MNL_TYPE_STRING,
406 [DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
407 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
408 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
409 [DEVLINK_ATTR_PARAM] = MNL_TYPE_NESTED,
410 [DEVLINK_ATTR_PARAM_NAME] = MNL_TYPE_STRING,
411 [DEVLINK_ATTR_PARAM_TYPE] = MNL_TYPE_U8,
412 [DEVLINK_ATTR_PARAM_VALUES_LIST] = MNL_TYPE_NESTED,
413 [DEVLINK_ATTR_PARAM_VALUE] = MNL_TYPE_NESTED,
414 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = MNL_TYPE_U8,
415 [DEVLINK_ATTR_REGION_NAME] = MNL_TYPE_STRING,
416 [DEVLINK_ATTR_REGION_SIZE] = MNL_TYPE_U64,
417 [DEVLINK_ATTR_REGION_SNAPSHOTS] = MNL_TYPE_NESTED,
418 [DEVLINK_ATTR_REGION_SNAPSHOT] = MNL_TYPE_NESTED,
419 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = MNL_TYPE_U32,
420 [DEVLINK_ATTR_REGION_CHUNKS] = MNL_TYPE_NESTED,
421 [DEVLINK_ATTR_REGION_CHUNK] = MNL_TYPE_NESTED,
422 [DEVLINK_ATTR_REGION_CHUNK_DATA] = MNL_TYPE_BINARY,
423 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = MNL_TYPE_U64,
424 [DEVLINK_ATTR_REGION_CHUNK_LEN] = MNL_TYPE_U64,
425 [DEVLINK_ATTR_INFO_DRIVER_NAME] = MNL_TYPE_STRING,
426 [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = MNL_TYPE_STRING,
427 [DEVLINK_ATTR_INFO_VERSION_FIXED] = MNL_TYPE_NESTED,
428 [DEVLINK_ATTR_INFO_VERSION_RUNNING] = MNL_TYPE_NESTED,
429 [DEVLINK_ATTR_INFO_VERSION_STORED] = MNL_TYPE_NESTED,
430 [DEVLINK_ATTR_INFO_VERSION_NAME] = MNL_TYPE_STRING,
431 [DEVLINK_ATTR_INFO_VERSION_VALUE] = MNL_TYPE_STRING,
432 [DEVLINK_ATTR_HEALTH_REPORTER] = MNL_TYPE_NESTED,
433 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = MNL_TYPE_STRING,
434 [DEVLINK_ATTR_HEALTH_REPORTER_STATE] = MNL_TYPE_U8,
435 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] = MNL_TYPE_U64,
436 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] = MNL_TYPE_U64,
437 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS] = MNL_TYPE_U64,
438 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = MNL_TYPE_U64,
439 };
440
441 static int attr_cb(const struct nlattr *attr, void *data)
442 {
443 const struct nlattr **tb = data;
444 int type;
445
446 if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
447 return MNL_CB_OK;
448
449 type = mnl_attr_get_type(attr);
450 if (mnl_attr_validate(attr, devlink_policy[type]) < 0)
451 return MNL_CB_ERROR;
452
453 tb[type] = attr;
454 return MNL_CB_OK;
455 }
456
457 static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
458 {
459 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
460 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
461 struct dl *dl = data;
462 struct ifname_map *ifname_map;
463 const char *bus_name;
464 const char *dev_name;
465 uint32_t port_ifindex;
466 const char *port_ifname;
467
468 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
469 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
470 !tb[DEVLINK_ATTR_PORT_INDEX])
471 return MNL_CB_ERROR;
472
473 if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
474 return MNL_CB_OK;
475
476 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
477 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
478 port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
479 port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
480 ifname_map = ifname_map_alloc(bus_name, dev_name,
481 port_ifindex, port_ifname);
482 if (!ifname_map)
483 return MNL_CB_ERROR;
484 list_add(&ifname_map->list, &dl->ifname_map_list);
485
486 return MNL_CB_OK;
487 }
488
489 static void ifname_map_fini(struct dl *dl)
490 {
491 struct ifname_map *ifname_map, *tmp;
492
493 list_for_each_entry_safe(ifname_map, tmp,
494 &dl->ifname_map_list, list) {
495 list_del(&ifname_map->list);
496 ifname_map_free(ifname_map);
497 }
498 }
499
500 static int ifname_map_init(struct dl *dl)
501 {
502 struct nlmsghdr *nlh;
503 int err;
504
505 INIT_LIST_HEAD(&dl->ifname_map_list);
506
507 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
508 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
509
510 err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl);
511 if (err) {
512 ifname_map_fini(dl);
513 return err;
514 }
515 return 0;
516 }
517
518 static int ifname_map_lookup(struct dl *dl, const char *ifname,
519 char **p_bus_name, char **p_dev_name,
520 uint32_t *p_port_index)
521 {
522 struct ifname_map *ifname_map;
523
524 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
525 if (strcmp(ifname, ifname_map->ifname) == 0) {
526 *p_bus_name = ifname_map->bus_name;
527 *p_dev_name = ifname_map->dev_name;
528 *p_port_index = ifname_map->port_index;
529 return 0;
530 }
531 }
532 return -ENOENT;
533 }
534
535 static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name,
536 const char *dev_name, uint32_t port_index,
537 char **p_ifname)
538 {
539 struct ifname_map *ifname_map;
540
541 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
542 if (strcmp(bus_name, ifname_map->bus_name) == 0 &&
543 strcmp(dev_name, ifname_map->dev_name) == 0 &&
544 port_index == ifname_map->port_index) {
545 *p_ifname = ifname_map->ifname;
546 return 0;
547 }
548 }
549 return -ENOENT;
550 }
551
552 static unsigned int strslashcount(char *str)
553 {
554 unsigned int count = 0;
555 char *pos = str;
556
557 while ((pos = strchr(pos, '/'))) {
558 count++;
559 pos++;
560 }
561 return count;
562 }
563
564 static int strslashrsplit(char *str, char **before, char **after)
565 {
566 char *slash;
567
568 slash = strrchr(str, '/');
569 if (!slash)
570 return -EINVAL;
571 *slash = '\0';
572 *before = str;
573 *after = slash + 1;
574 return 0;
575 }
576
577 static int strtouint64_t(const char *str, uint64_t *p_val)
578 {
579 char *endptr;
580 unsigned long long int val;
581
582 val = strtoull(str, &endptr, 10);
583 if (endptr == str || *endptr != '\0')
584 return -EINVAL;
585 if (val > ULONG_MAX)
586 return -ERANGE;
587 *p_val = val;
588 return 0;
589 }
590
591 static int strtouint32_t(const char *str, uint32_t *p_val)
592 {
593 char *endptr;
594 unsigned long int val;
595
596 val = strtoul(str, &endptr, 10);
597 if (endptr == str || *endptr != '\0')
598 return -EINVAL;
599 if (val > UINT_MAX)
600 return -ERANGE;
601 *p_val = val;
602 return 0;
603 }
604
605 static int strtouint16_t(const char *str, uint16_t *p_val)
606 {
607 char *endptr;
608 unsigned long int val;
609
610 val = strtoul(str, &endptr, 10);
611 if (endptr == str || *endptr != '\0')
612 return -EINVAL;
613 if (val > USHRT_MAX)
614 return -ERANGE;
615 *p_val = val;
616 return 0;
617 }
618
619 static int strtouint8_t(const char *str, uint8_t *p_val)
620 {
621 char *endptr;
622 unsigned long int val;
623
624 val = strtoul(str, &endptr, 10);
625 if (endptr == str || *endptr != '\0')
626 return -EINVAL;
627 if (val > UCHAR_MAX)
628 return -ERANGE;
629 *p_val = val;
630 return 0;
631 }
632
633 static int strtobool(const char *str, bool *p_val)
634 {
635 bool val;
636
637 if (!strcmp(str, "true") || !strcmp(str, "1"))
638 val = true;
639 else if (!strcmp(str, "false") || !strcmp(str, "0"))
640 val = false;
641 else
642 return -EINVAL;
643 *p_val = val;
644 return 0;
645 }
646
647 static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
648 {
649 strslashrsplit(str, p_bus_name, p_dev_name);
650 return 0;
651 }
652
653 static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
654 {
655 char *str = dl_argv_next(dl);
656
657 if (!str) {
658 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
659 return -EINVAL;
660 }
661 if (strslashcount(str) != 1) {
662 pr_err("Wrong devlink identification string format.\n");
663 pr_err("Expected \"bus_name/dev_name\".\n");
664 return -EINVAL;
665 }
666 return __dl_argv_handle(str, p_bus_name, p_dev_name);
667 }
668
669 static int __dl_argv_handle_port(char *str,
670 char **p_bus_name, char **p_dev_name,
671 uint32_t *p_port_index)
672 {
673 char *handlestr;
674 char *portstr;
675 int err;
676
677 err = strslashrsplit(str, &handlestr, &portstr);
678 if (err) {
679 pr_err("Port identification \"%s\" is invalid\n", str);
680 return err;
681 }
682 err = strtouint32_t(portstr, p_port_index);
683 if (err) {
684 pr_err("Port index \"%s\" is not a number or not within range\n",
685 portstr);
686 return err;
687 }
688 err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
689 if (err) {
690 pr_err("Port identification \"%s\" is invalid\n", str);
691 return err;
692 }
693 return 0;
694 }
695
696 static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
697 char **p_bus_name, char **p_dev_name,
698 uint32_t *p_port_index)
699 {
700 int err;
701
702 err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
703 p_port_index);
704 if (err) {
705 pr_err("Netdevice \"%s\" not found\n", str);
706 return err;
707 }
708 return 0;
709 }
710
711 static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
712 char **p_dev_name, uint32_t *p_port_index)
713 {
714 char *str = dl_argv_next(dl);
715 unsigned int slash_count;
716
717 if (!str) {
718 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
719 return -EINVAL;
720 }
721 slash_count = strslashcount(str);
722 switch (slash_count) {
723 case 0:
724 return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
725 p_dev_name, p_port_index);
726 case 2:
727 return __dl_argv_handle_port(str, p_bus_name,
728 p_dev_name, p_port_index);
729 default:
730 pr_err("Wrong port identification string format.\n");
731 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
732 return -EINVAL;
733 }
734 }
735
736 static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
737 char **p_dev_name, uint32_t *p_port_index,
738 uint32_t *p_handle_bit)
739 {
740 char *str = dl_argv_next(dl);
741 unsigned int slash_count;
742 int err;
743
744 if (!str) {
745 pr_err("One of following identifications expected:\n"
746 "Devlink identification (\"bus_name/dev_name\")\n"
747 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
748 return -EINVAL;
749 }
750 slash_count = strslashcount(str);
751 if (slash_count == 1) {
752 err = __dl_argv_handle(str, p_bus_name, p_dev_name);
753 if (err)
754 return err;
755 *p_handle_bit = DL_OPT_HANDLE;
756 } else if (slash_count == 2) {
757 err = __dl_argv_handle_port(str, p_bus_name,
758 p_dev_name, p_port_index);
759 if (err)
760 return err;
761 *p_handle_bit = DL_OPT_HANDLEP;
762 } else if (slash_count == 0) {
763 err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
764 p_dev_name, p_port_index);
765 if (err)
766 return err;
767 *p_handle_bit = DL_OPT_HANDLEP;
768 } else {
769 pr_err("Wrong port identification string format.\n");
770 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
771 return -EINVAL;
772 }
773 return 0;
774 }
775
776 static int __dl_argv_handle_region(char *str, char **p_bus_name,
777 char **p_dev_name, char **p_region)
778 {
779 char *handlestr;
780 int err;
781
782 err = strslashrsplit(str, &handlestr, p_region);
783 if (err) {
784 pr_err("Region identification \"%s\" is invalid\n", str);
785 return err;
786 }
787 err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
788 if (err) {
789 pr_err("Region identification \"%s\" is invalid\n", str);
790 return err;
791 }
792 return 0;
793 }
794
795 static int dl_argv_handle_region(struct dl *dl, char **p_bus_name,
796 char **p_dev_name, char **p_region)
797 {
798 char *str = dl_argv_next(dl);
799 unsigned int slash_count;
800
801 if (!str) {
802 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
803 return -EINVAL;
804 }
805
806 slash_count = strslashcount(str);
807 if (slash_count != 2) {
808 pr_err("Wrong region identification string format.\n");
809 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
810 return -EINVAL;
811 }
812
813 return __dl_argv_handle_region(str, p_bus_name, p_dev_name, p_region);
814 }
815
816 static int dl_argv_uint64_t(struct dl *dl, uint64_t *p_val)
817 {
818 char *str = dl_argv_next(dl);
819 int err;
820
821 if (!str) {
822 pr_err("Unsigned number argument expected\n");
823 return -EINVAL;
824 }
825
826 err = strtouint64_t(str, p_val);
827 if (err) {
828 pr_err("\"%s\" is not a number or not within range\n", str);
829 return err;
830 }
831 return 0;
832 }
833
834 static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
835 {
836 char *str = dl_argv_next(dl);
837 int err;
838
839 if (!str) {
840 pr_err("Unsigned number argument expected\n");
841 return -EINVAL;
842 }
843
844 err = strtouint32_t(str, p_val);
845 if (err) {
846 pr_err("\"%s\" is not a number or not within range\n", str);
847 return err;
848 }
849 return 0;
850 }
851
852 static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val)
853 {
854 char *str = dl_argv_next(dl);
855 int err;
856
857 if (!str) {
858 pr_err("Unsigned number argument expected\n");
859 return -EINVAL;
860 }
861
862 err = strtouint16_t(str, p_val);
863 if (err) {
864 pr_err("\"%s\" is not a number or not within range\n", str);
865 return err;
866 }
867 return 0;
868 }
869
870 static int dl_argv_bool(struct dl *dl, bool *p_val)
871 {
872 char *str = dl_argv_next(dl);
873 int err;
874
875 if (!str) {
876 pr_err("Boolean argument expected\n");
877 return -EINVAL;
878 }
879
880 err = strtobool(str, p_val);
881 if (err) {
882 pr_err("\"%s\" is not a valid boolean value\n", str);
883 return err;
884 }
885 return 0;
886 }
887
888 static int dl_argv_str(struct dl *dl, const char **p_str)
889 {
890 const char *str = dl_argv_next(dl);
891
892 if (!str) {
893 pr_err("String parameter expected\n");
894 return -EINVAL;
895 }
896 *p_str = str;
897 return 0;
898 }
899
900 static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
901 {
902 if (strcmp(typestr, "auto") == 0) {
903 *p_type = DEVLINK_PORT_TYPE_AUTO;
904 } else if (strcmp(typestr, "eth") == 0) {
905 *p_type = DEVLINK_PORT_TYPE_ETH;
906 } else if (strcmp(typestr, "ib") == 0) {
907 *p_type = DEVLINK_PORT_TYPE_IB;
908 } else {
909 pr_err("Unknown port type \"%s\"\n", typestr);
910 return -EINVAL;
911 }
912 return 0;
913 }
914
915 static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type)
916 {
917 if (strcmp(typestr, "ingress") == 0) {
918 *p_type = DEVLINK_SB_POOL_TYPE_INGRESS;
919 } else if (strcmp(typestr, "egress") == 0) {
920 *p_type = DEVLINK_SB_POOL_TYPE_EGRESS;
921 } else {
922 pr_err("Unknown pool type \"%s\"\n", typestr);
923 return -EINVAL;
924 }
925 return 0;
926 }
927
928 static int threshold_type_get(const char *typestr,
929 enum devlink_sb_threshold_type *p_type)
930 {
931 if (strcmp(typestr, "static") == 0) {
932 *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC;
933 } else if (strcmp(typestr, "dynamic") == 0) {
934 *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC;
935 } else {
936 pr_err("Unknown threshold type \"%s\"\n", typestr);
937 return -EINVAL;
938 }
939 return 0;
940 }
941
942 static int eswitch_mode_get(const char *typestr,
943 enum devlink_eswitch_mode *p_mode)
944 {
945 if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) {
946 *p_mode = DEVLINK_ESWITCH_MODE_LEGACY;
947 } else if (strcmp(typestr, ESWITCH_MODE_SWITCHDEV) == 0) {
948 *p_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
949 } else {
950 pr_err("Unknown eswitch mode \"%s\"\n", typestr);
951 return -EINVAL;
952 }
953 return 0;
954 }
955
956 static int eswitch_inline_mode_get(const char *typestr,
957 enum devlink_eswitch_inline_mode *p_mode)
958 {
959 if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) {
960 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
961 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) {
962 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
963 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) {
964 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
965 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) {
966 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
967 } else {
968 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr);
969 return -EINVAL;
970 }
971 return 0;
972 }
973
974 static int dpipe_counters_enable_get(const char *typestr,
975 bool *counters_enable)
976 {
977 if (strcmp(typestr, "enable") == 0) {
978 *counters_enable = 1;
979 } else if (strcmp(typestr, "disable") == 0) {
980 *counters_enable = 0;
981 } else {
982 pr_err("Unknown counter_state \"%s\"\n", typestr);
983 return -EINVAL;
984 }
985 return 0;
986 }
987
988 static int eswitch_encap_mode_get(const char *typestr, bool *p_mode)
989 {
990 if (strcmp(typestr, "enable") == 0) {
991 *p_mode = true;
992 } else if (strcmp(typestr, "disable") == 0) {
993 *p_mode = false;
994 } else {
995 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr);
996 return -EINVAL;
997 }
998 return 0;
999 }
1000
1001 static int param_cmode_get(const char *cmodestr,
1002 enum devlink_param_cmode *cmode)
1003 {
1004 if (strcmp(cmodestr, PARAM_CMODE_RUNTIME_STR) == 0) {
1005 *cmode = DEVLINK_PARAM_CMODE_RUNTIME;
1006 } else if (strcmp(cmodestr, PARAM_CMODE_DRIVERINIT_STR) == 0) {
1007 *cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
1008 } else if (strcmp(cmodestr, PARAM_CMODE_PERMANENT_STR) == 0) {
1009 *cmode = DEVLINK_PARAM_CMODE_PERMANENT;
1010 } else {
1011 pr_err("Unknown configuration mode \"%s\"\n", cmodestr);
1012 return -EINVAL;
1013 }
1014 return 0;
1015 }
1016
1017 struct dl_args_metadata {
1018 uint32_t o_flag;
1019 char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
1020 };
1021
1022 static const struct dl_args_metadata dl_args_required[] = {
1023 {DL_OPT_PORT_TYPE, "Port type not set."},
1024 {DL_OPT_PORT_COUNT, "Port split count option expected."},
1025 {DL_OPT_SB_POOL, "Pool index option expected."},
1026 {DL_OPT_SB_SIZE, "Pool size option expected."},
1027 {DL_OPT_SB_TYPE, "Pool type option expected."},
1028 {DL_OPT_SB_THTYPE, "Pool threshold type option expected."},
1029 {DL_OPT_SB_TH, "Threshold option expected."},
1030 {DL_OPT_SB_TC, "TC index option expected."},
1031 {DL_OPT_ESWITCH_MODE, "E-Switch mode option expected."},
1032 {DL_OPT_ESWITCH_INLINE_MODE, "E-Switch inline-mode option expected."},
1033 {DL_OPT_DPIPE_TABLE_NAME, "Dpipe table name expected."},
1034 {DL_OPT_DPIPE_TABLE_COUNTERS, "Dpipe table counter state expected."},
1035 {DL_OPT_ESWITCH_ENCAP_MODE, "E-Switch encapsulation option expected."},
1036 {DL_OPT_PARAM_NAME, "Parameter name expected."},
1037 {DL_OPT_PARAM_VALUE, "Value to set expected."},
1038 {DL_OPT_PARAM_CMODE, "Configuration mode expected."},
1039 {DL_OPT_REGION_SNAPSHOT_ID, "Region snapshot id expected."},
1040 {DL_OPT_REGION_ADDRESS, "Region address value expected."},
1041 {DL_OPT_REGION_LENGTH, "Region length value expected."},
1042 {DL_OPT_HEALTH_REPORTER_NAME, "Reporter's name is expected."},
1043 };
1044
1045 static int dl_args_finding_required_validate(uint32_t o_required,
1046 uint32_t o_found)
1047 {
1048 uint32_t o_flag;
1049 int i;
1050
1051 for (i = 0; i < ARRAY_SIZE(dl_args_required); i++) {
1052 o_flag = dl_args_required[i].o_flag;
1053 if ((o_required & o_flag) && !(o_found & o_flag)) {
1054 pr_err("%s\n", dl_args_required[i].err_msg);
1055 return -EINVAL;
1056 }
1057 }
1058 return 0;
1059 }
1060
1061 static int dl_argv_parse(struct dl *dl, uint32_t o_required,
1062 uint32_t o_optional)
1063 {
1064 struct dl_opts *opts = &dl->opts;
1065 uint32_t o_all = o_required | o_optional;
1066 uint32_t o_found = 0;
1067 int err;
1068
1069 if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
1070 uint32_t handle_bit;
1071
1072 err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
1073 &opts->port_index, &handle_bit);
1074 if (err)
1075 return err;
1076 o_found |= handle_bit;
1077 } else if (o_required & DL_OPT_HANDLE) {
1078 err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
1079 if (err)
1080 return err;
1081 o_found |= DL_OPT_HANDLE;
1082 } else if (o_required & DL_OPT_HANDLEP) {
1083 err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
1084 &opts->port_index);
1085 if (err)
1086 return err;
1087 o_found |= DL_OPT_HANDLEP;
1088 } else if (o_required & DL_OPT_HANDLE_REGION) {
1089 err = dl_argv_handle_region(dl, &opts->bus_name,
1090 &opts->dev_name,
1091 &opts->region_name);
1092 if (err)
1093 return err;
1094 o_found |= DL_OPT_HANDLE_REGION;
1095 }
1096
1097 while (dl_argc(dl)) {
1098 if (dl_argv_match(dl, "type") &&
1099 (o_all & DL_OPT_PORT_TYPE)) {
1100 const char *typestr;
1101
1102 dl_arg_inc(dl);
1103 err = dl_argv_str(dl, &typestr);
1104 if (err)
1105 return err;
1106 err = port_type_get(typestr, &opts->port_type);
1107 if (err)
1108 return err;
1109 o_found |= DL_OPT_PORT_TYPE;
1110 } else if (dl_argv_match(dl, "count") &&
1111 (o_all & DL_OPT_PORT_COUNT)) {
1112 dl_arg_inc(dl);
1113 err = dl_argv_uint32_t(dl, &opts->port_count);
1114 if (err)
1115 return err;
1116 o_found |= DL_OPT_PORT_COUNT;
1117 } else if (dl_argv_match(dl, "sb") &&
1118 (o_all & DL_OPT_SB)) {
1119 dl_arg_inc(dl);
1120 err = dl_argv_uint32_t(dl, &opts->sb_index);
1121 if (err)
1122 return err;
1123 o_found |= DL_OPT_SB;
1124 } else if (dl_argv_match(dl, "pool") &&
1125 (o_all & DL_OPT_SB_POOL)) {
1126 dl_arg_inc(dl);
1127 err = dl_argv_uint16_t(dl, &opts->sb_pool_index);
1128 if (err)
1129 return err;
1130 o_found |= DL_OPT_SB_POOL;
1131 } else if (dl_argv_match(dl, "size") &&
1132 (o_all & DL_OPT_SB_SIZE)) {
1133 dl_arg_inc(dl);
1134 err = dl_argv_uint32_t(dl, &opts->sb_pool_size);
1135 if (err)
1136 return err;
1137 o_found |= DL_OPT_SB_SIZE;
1138 } else if (dl_argv_match(dl, "type") &&
1139 (o_all & DL_OPT_SB_TYPE)) {
1140 const char *typestr;
1141
1142 dl_arg_inc(dl);
1143 err = dl_argv_str(dl, &typestr);
1144 if (err)
1145 return err;
1146 err = pool_type_get(typestr, &opts->sb_pool_type);
1147 if (err)
1148 return err;
1149 o_found |= DL_OPT_SB_TYPE;
1150 } else if (dl_argv_match(dl, "thtype") &&
1151 (o_all & DL_OPT_SB_THTYPE)) {
1152 const char *typestr;
1153
1154 dl_arg_inc(dl);
1155 err = dl_argv_str(dl, &typestr);
1156 if (err)
1157 return err;
1158 err = threshold_type_get(typestr,
1159 &opts->sb_pool_thtype);
1160 if (err)
1161 return err;
1162 o_found |= DL_OPT_SB_THTYPE;
1163 } else if (dl_argv_match(dl, "th") &&
1164 (o_all & DL_OPT_SB_TH)) {
1165 dl_arg_inc(dl);
1166 err = dl_argv_uint32_t(dl, &opts->sb_threshold);
1167 if (err)
1168 return err;
1169 o_found |= DL_OPT_SB_TH;
1170 } else if (dl_argv_match(dl, "tc") &&
1171 (o_all & DL_OPT_SB_TC)) {
1172 dl_arg_inc(dl);
1173 err = dl_argv_uint16_t(dl, &opts->sb_tc_index);
1174 if (err)
1175 return err;
1176 o_found |= DL_OPT_SB_TC;
1177 } else if (dl_argv_match(dl, "mode") &&
1178 (o_all & DL_OPT_ESWITCH_MODE)) {
1179 const char *typestr;
1180
1181 dl_arg_inc(dl);
1182 err = dl_argv_str(dl, &typestr);
1183 if (err)
1184 return err;
1185 err = eswitch_mode_get(typestr, &opts->eswitch_mode);
1186 if (err)
1187 return err;
1188 o_found |= DL_OPT_ESWITCH_MODE;
1189 } else if (dl_argv_match(dl, "inline-mode") &&
1190 (o_all & DL_OPT_ESWITCH_INLINE_MODE)) {
1191 const char *typestr;
1192
1193 dl_arg_inc(dl);
1194 err = dl_argv_str(dl, &typestr);
1195 if (err)
1196 return err;
1197 err = eswitch_inline_mode_get(
1198 typestr, &opts->eswitch_inline_mode);
1199 if (err)
1200 return err;
1201 o_found |= DL_OPT_ESWITCH_INLINE_MODE;
1202 } else if (dl_argv_match(dl, "name") &&
1203 (o_all & DL_OPT_DPIPE_TABLE_NAME)) {
1204 dl_arg_inc(dl);
1205 err = dl_argv_str(dl, &opts->dpipe_table_name);
1206 if (err)
1207 return err;
1208 o_found |= DL_OPT_DPIPE_TABLE_NAME;
1209 } else if (dl_argv_match(dl, "counters") &&
1210 (o_all & DL_OPT_DPIPE_TABLE_COUNTERS)) {
1211 const char *typestr;
1212
1213 dl_arg_inc(dl);
1214 err = dl_argv_str(dl, &typestr);
1215 if (err)
1216 return err;
1217 err = dpipe_counters_enable_get(typestr,
1218 &opts->dpipe_counters_enable);
1219 if (err)
1220 return err;
1221 o_found |= DL_OPT_DPIPE_TABLE_COUNTERS;
1222 } else if (dl_argv_match(dl, "encap") &&
1223 (o_all & DL_OPT_ESWITCH_ENCAP_MODE)) {
1224 const char *typestr;
1225
1226 dl_arg_inc(dl);
1227 err = dl_argv_str(dl, &typestr);
1228 if (err)
1229 return err;
1230 err = eswitch_encap_mode_get(typestr,
1231 &opts->eswitch_encap_mode);
1232 if (err)
1233 return err;
1234 o_found |= DL_OPT_ESWITCH_ENCAP_MODE;
1235 } else if (dl_argv_match(dl, "path") &&
1236 (o_all & DL_OPT_RESOURCE_PATH)) {
1237 dl_arg_inc(dl);
1238 err = dl_argv_str(dl, &opts->resource_path);
1239 if (err)
1240 return err;
1241 o_found |= DL_OPT_RESOURCE_PATH;
1242 } else if (dl_argv_match(dl, "size") &&
1243 (o_all & DL_OPT_RESOURCE_SIZE)) {
1244 dl_arg_inc(dl);
1245 err = dl_argv_uint32_t(dl, &opts->resource_size);
1246 if (err)
1247 return err;
1248 o_found |= DL_OPT_RESOURCE_SIZE;
1249 } else if (dl_argv_match(dl, "name") &&
1250 (o_all & DL_OPT_PARAM_NAME)) {
1251 dl_arg_inc(dl);
1252 err = dl_argv_str(dl, &opts->param_name);
1253 if (err)
1254 return err;
1255 o_found |= DL_OPT_PARAM_NAME;
1256 } else if (dl_argv_match(dl, "value") &&
1257 (o_all & DL_OPT_PARAM_VALUE)) {
1258 dl_arg_inc(dl);
1259 err = dl_argv_str(dl, &opts->param_value);
1260 if (err)
1261 return err;
1262 o_found |= DL_OPT_PARAM_VALUE;
1263 } else if (dl_argv_match(dl, "cmode") &&
1264 (o_all & DL_OPT_PARAM_CMODE)) {
1265 const char *cmodestr;
1266
1267 dl_arg_inc(dl);
1268 err = dl_argv_str(dl, &cmodestr);
1269 if (err)
1270 return err;
1271 err = param_cmode_get(cmodestr, &opts->cmode);
1272 if (err)
1273 return err;
1274 o_found |= DL_OPT_PARAM_CMODE;
1275 } else if (dl_argv_match(dl, "snapshot") &&
1276 (o_all & DL_OPT_REGION_SNAPSHOT_ID)) {
1277 dl_arg_inc(dl);
1278 err = dl_argv_uint32_t(dl, &opts->region_snapshot_id);
1279 if (err)
1280 return err;
1281 o_found |= DL_OPT_REGION_SNAPSHOT_ID;
1282 } else if (dl_argv_match(dl, "address") &&
1283 (o_all & DL_OPT_REGION_ADDRESS)) {
1284 dl_arg_inc(dl);
1285 err = dl_argv_uint64_t(dl, &opts->region_address);
1286 if (err)
1287 return err;
1288 o_found |= DL_OPT_REGION_ADDRESS;
1289 } else if (dl_argv_match(dl, "length") &&
1290 (o_all & DL_OPT_REGION_LENGTH)) {
1291 dl_arg_inc(dl);
1292 err = dl_argv_uint64_t(dl, &opts->region_length);
1293 if (err)
1294 return err;
1295 o_found |= DL_OPT_REGION_LENGTH;
1296 } else if (dl_argv_match(dl, "file") &&
1297 (o_all & DL_OPT_FLASH_FILE_NAME)) {
1298 dl_arg_inc(dl);
1299 err = dl_argv_str(dl, &opts->flash_file_name);
1300 if (err)
1301 return err;
1302 o_found |= DL_OPT_FLASH_FILE_NAME;
1303 } else if (dl_argv_match(dl, "component") &&
1304 (o_all & DL_OPT_FLASH_COMPONENT)) {
1305 dl_arg_inc(dl);
1306 err = dl_argv_str(dl, &opts->flash_component);
1307 if (err)
1308 return err;
1309 o_found |= DL_OPT_FLASH_COMPONENT;
1310 } else if (dl_argv_match(dl, "reporter") &&
1311 (o_all & DL_OPT_HEALTH_REPORTER_NAME)) {
1312 dl_arg_inc(dl);
1313 err = dl_argv_str(dl, &opts->reporter_name);
1314 if (err)
1315 return err;
1316 o_found |= DL_OPT_HEALTH_REPORTER_NAME;
1317 } else if (dl_argv_match(dl, "grace_period") &&
1318 (o_all & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)) {
1319 dl_arg_inc(dl);
1320 err = dl_argv_uint64_t(dl,
1321 &opts->reporter_graceful_period);
1322 if (err)
1323 return err;
1324 o_found |= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD;
1325 } else if (dl_argv_match(dl, "auto_recover") &&
1326 (o_all & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)) {
1327 dl_arg_inc(dl);
1328 err = dl_argv_bool(dl, &opts->reporter_auto_recover);
1329 if (err)
1330 return err;
1331 o_found |= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER;
1332 } else {
1333 pr_err("Unknown option \"%s\"\n", dl_argv(dl));
1334 return -EINVAL;
1335 }
1336 }
1337
1338 opts->present = o_found;
1339
1340 if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) {
1341 opts->sb_index = 0;
1342 opts->present |= DL_OPT_SB;
1343 }
1344
1345 return dl_args_finding_required_validate(o_required, o_found);
1346 }
1347
1348 static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
1349 {
1350 struct dl_opts *opts = &dl->opts;
1351
1352 if (opts->present & DL_OPT_HANDLE) {
1353 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1354 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1355 } else if (opts->present & DL_OPT_HANDLEP) {
1356 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1357 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1358 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
1359 opts->port_index);
1360 } else if (opts->present & DL_OPT_HANDLE_REGION) {
1361 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1362 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1363 mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME,
1364 opts->region_name);
1365 }
1366 if (opts->present & DL_OPT_PORT_TYPE)
1367 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
1368 opts->port_type);
1369 if (opts->present & DL_OPT_PORT_COUNT)
1370 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
1371 opts->port_count);
1372 if (opts->present & DL_OPT_SB)
1373 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX,
1374 opts->sb_index);
1375 if (opts->present & DL_OPT_SB_POOL)
1376 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX,
1377 opts->sb_pool_index);
1378 if (opts->present & DL_OPT_SB_SIZE)
1379 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE,
1380 opts->sb_pool_size);
1381 if (opts->present & DL_OPT_SB_TYPE)
1382 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE,
1383 opts->sb_pool_type);
1384 if (opts->present & DL_OPT_SB_THTYPE)
1385 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1386 opts->sb_pool_thtype);
1387 if (opts->present & DL_OPT_SB_TH)
1388 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD,
1389 opts->sb_threshold);
1390 if (opts->present & DL_OPT_SB_TC)
1391 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX,
1392 opts->sb_tc_index);
1393 if (opts->present & DL_OPT_ESWITCH_MODE)
1394 mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
1395 opts->eswitch_mode);
1396 if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
1397 mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1398 opts->eswitch_inline_mode);
1399 if (opts->present & DL_OPT_DPIPE_TABLE_NAME)
1400 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME,
1401 opts->dpipe_table_name);
1402 if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS)
1403 mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1404 opts->dpipe_counters_enable);
1405 if (opts->present & DL_OPT_ESWITCH_ENCAP_MODE)
1406 mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE,
1407 opts->eswitch_encap_mode);
1408 if ((opts->present & DL_OPT_RESOURCE_PATH) && opts->resource_id_valid)
1409 mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_ID,
1410 opts->resource_id);
1411 if (opts->present & DL_OPT_RESOURCE_SIZE)
1412 mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE,
1413 opts->resource_size);
1414 if (opts->present & DL_OPT_PARAM_NAME)
1415 mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME,
1416 opts->param_name);
1417 if (opts->present & DL_OPT_PARAM_CMODE)
1418 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE,
1419 opts->cmode);
1420 if (opts->present & DL_OPT_REGION_SNAPSHOT_ID)
1421 mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
1422 opts->region_snapshot_id);
1423 if (opts->present & DL_OPT_REGION_ADDRESS)
1424 mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR,
1425 opts->region_address);
1426 if (opts->present & DL_OPT_REGION_LENGTH)
1427 mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN,
1428 opts->region_length);
1429 if (opts->present & DL_OPT_FLASH_FILE_NAME)
1430 mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME,
1431 opts->flash_file_name);
1432 if (opts->present & DL_OPT_FLASH_COMPONENT)
1433 mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
1434 opts->flash_component);
1435 if (opts->present & DL_OPT_HEALTH_REPORTER_NAME)
1436 mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
1437 opts->reporter_name);
1438 if (opts->present & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)
1439 mnl_attr_put_u64(nlh,
1440 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
1441 opts->reporter_graceful_period);
1442 if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)
1443 mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
1444 opts->reporter_auto_recover);
1445
1446 }
1447
1448 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
1449 uint32_t o_required, uint32_t o_optional)
1450 {
1451 int err;
1452
1453 err = dl_argv_parse(dl, o_required, o_optional);
1454 if (err)
1455 return err;
1456 dl_opts_put(nlh, dl);
1457 return 0;
1458 }
1459
1460 static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
1461 {
1462 struct dl_opts *opts = &dl->opts;
1463 struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME];
1464 struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME];
1465 struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX];
1466 struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX];
1467
1468 if (opts->present & DL_OPT_HANDLE &&
1469 attr_bus_name && attr_dev_name) {
1470 const char *bus_name = mnl_attr_get_str(attr_bus_name);
1471 const char *dev_name = mnl_attr_get_str(attr_dev_name);
1472
1473 if (strcmp(bus_name, opts->bus_name) != 0 ||
1474 strcmp(dev_name, opts->dev_name) != 0)
1475 return false;
1476 }
1477 if (opts->present & DL_OPT_HANDLEP &&
1478 attr_bus_name && attr_dev_name && attr_port_index) {
1479 const char *bus_name = mnl_attr_get_str(attr_bus_name);
1480 const char *dev_name = mnl_attr_get_str(attr_dev_name);
1481 uint32_t port_index = mnl_attr_get_u32(attr_port_index);
1482
1483 if (strcmp(bus_name, opts->bus_name) != 0 ||
1484 strcmp(dev_name, opts->dev_name) != 0 ||
1485 port_index != opts->port_index)
1486 return false;
1487 }
1488 if (opts->present & DL_OPT_SB && attr_sb_index) {
1489 uint32_t sb_index = mnl_attr_get_u32(attr_sb_index);
1490
1491 if (sb_index != opts->sb_index)
1492 return false;
1493 }
1494 return true;
1495 }
1496
1497 static void cmd_dev_help(void)
1498 {
1499 pr_err("Usage: devlink dev show [ DEV ]\n");
1500 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1501 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1502 pr_err(" [ encap { disable | enable } ]\n");
1503 pr_err(" devlink dev eswitch show DEV\n");
1504 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
1505 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
1506 pr_err(" devlink dev reload DEV\n");
1507 pr_err(" devlink dev info [ DEV ]\n");
1508 pr_err(" devlink dev flash DEV file PATH [ component NAME ]\n");
1509 }
1510
1511 static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
1512 const char *dev_name)
1513 {
1514 if (!dl->arr_last.present)
1515 return false;
1516 return strcmp(dl->arr_last.bus_name, bus_name) == 0 &&
1517 strcmp(dl->arr_last.dev_name, dev_name) == 0;
1518 }
1519
1520 static void arr_last_handle_set(struct dl *dl, const char *bus_name,
1521 const char *dev_name)
1522 {
1523 dl->arr_last.present = true;
1524 free(dl->arr_last.dev_name);
1525 free(dl->arr_last.bus_name);
1526 dl->arr_last.bus_name = strdup(bus_name);
1527 dl->arr_last.dev_name = strdup(dev_name);
1528 }
1529
1530 static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name,
1531 const char *dev_name)
1532 {
1533 return !cmp_arr_last_handle(dl, bus_name, dev_name);
1534 }
1535
1536 static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name,
1537 const char *dev_name)
1538 {
1539 return dl->arr_last.present &&
1540 !cmp_arr_last_handle(dl, bus_name, dev_name);
1541 }
1542
1543 static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb,
1544 bool content, bool array)
1545 {
1546 const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1547 const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1548 char buf[64];
1549
1550 sprintf(buf, "%s/%s", bus_name, dev_name);
1551
1552 if (dl->json_output) {
1553 if (array) {
1554 if (should_arr_last_handle_end(dl, bus_name, dev_name))
1555 jsonw_end_array(dl->jw);
1556 if (should_arr_last_handle_start(dl, bus_name,
1557 dev_name)) {
1558 jsonw_name(dl->jw, buf);
1559 jsonw_start_array(dl->jw);
1560 jsonw_start_object(dl->jw);
1561 arr_last_handle_set(dl, bus_name, dev_name);
1562 } else {
1563 jsonw_start_object(dl->jw);
1564 }
1565 } else {
1566 jsonw_name(dl->jw, buf);
1567 jsonw_start_object(dl->jw);
1568 }
1569 } else {
1570 if (array) {
1571 if (should_arr_last_handle_end(dl, bus_name, dev_name))
1572 __pr_out_indent_dec();
1573 if (should_arr_last_handle_start(dl, bus_name,
1574 dev_name)) {
1575 pr_out("%s%s", buf, content ? ":" : "");
1576 __pr_out_newline();
1577 __pr_out_indent_inc();
1578 arr_last_handle_set(dl, bus_name, dev_name);
1579 }
1580 } else {
1581 pr_out("%s%s", buf, content ? ":" : "");
1582 }
1583 }
1584 }
1585
1586 static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb)
1587 {
1588 __pr_out_handle_start(dl, tb, true, true);
1589 }
1590
1591 static void pr_out_handle_end(struct dl *dl)
1592 {
1593 if (dl->json_output)
1594 jsonw_end_object(dl->jw);
1595 else
1596 __pr_out_newline();
1597 }
1598
1599 static void pr_out_handle(struct dl *dl, struct nlattr **tb)
1600 {
1601 __pr_out_handle_start(dl, tb, false, false);
1602 pr_out_handle_end(dl);
1603 }
1604
1605 static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name,
1606 const char *dev_name, uint32_t port_index)
1607 {
1608 return cmp_arr_last_handle(dl, bus_name, dev_name) &&
1609 dl->arr_last.port_index == port_index;
1610 }
1611
1612 static void arr_last_port_handle_set(struct dl *dl, const char *bus_name,
1613 const char *dev_name, uint32_t port_index)
1614 {
1615 arr_last_handle_set(dl, bus_name, dev_name);
1616 dl->arr_last.port_index = port_index;
1617 }
1618
1619 static bool should_arr_last_port_handle_start(struct dl *dl,
1620 const char *bus_name,
1621 const char *dev_name,
1622 uint32_t port_index)
1623 {
1624 return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
1625 }
1626
1627 static bool should_arr_last_port_handle_end(struct dl *dl,
1628 const char *bus_name,
1629 const char *dev_name,
1630 uint32_t port_index)
1631 {
1632 return dl->arr_last.present &&
1633 !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
1634 }
1635
1636 static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name,
1637 const char *dev_name,
1638 uint32_t port_index, bool try_nice,
1639 bool array)
1640 {
1641 static char buf[64];
1642 char *ifname = NULL;
1643
1644 if (dl->no_nice_names || !try_nice ||
1645 ifname_map_rev_lookup(dl, bus_name, dev_name,
1646 port_index, &ifname) != 0)
1647 sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index);
1648 else
1649 sprintf(buf, "%s", ifname);
1650
1651 if (dl->json_output) {
1652 if (array) {
1653 if (should_arr_last_port_handle_end(dl, bus_name,
1654 dev_name,
1655 port_index))
1656 jsonw_end_array(dl->jw);
1657 if (should_arr_last_port_handle_start(dl, bus_name,
1658 dev_name,
1659 port_index)) {
1660 jsonw_name(dl->jw, buf);
1661 jsonw_start_array(dl->jw);
1662 jsonw_start_object(dl->jw);
1663 arr_last_port_handle_set(dl, bus_name, dev_name,
1664 port_index);
1665 } else {
1666 jsonw_start_object(dl->jw);
1667 }
1668 } else {
1669 jsonw_name(dl->jw, buf);
1670 jsonw_start_object(dl->jw);
1671 }
1672 } else {
1673 pr_out("%s:", buf);
1674 }
1675 }
1676
1677 static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
1678 {
1679 const char *bus_name;
1680 const char *dev_name;
1681 uint32_t port_index;
1682
1683 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1684 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1685 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
1686 __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false);
1687 }
1688
1689 static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice)
1690 {
1691 const char *bus_name;
1692 const char *dev_name;
1693 uint32_t port_index;
1694
1695 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1696 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1697 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
1698 __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true);
1699 }
1700
1701 static void pr_out_port_handle_end(struct dl *dl)
1702 {
1703 if (dl->json_output)
1704 jsonw_end_object(dl->jw);
1705 else
1706 pr_out("\n");
1707 }
1708
1709
1710 static void pr_out_str(struct dl *dl, const char *name, const char *val)
1711 {
1712 if (dl->json_output) {
1713 jsonw_string_field(dl->jw, name, val);
1714 } else {
1715 if (g_indent_newline)
1716 pr_out("%s %s", name, val);
1717 else
1718 pr_out(" %s %s", name, val);
1719 }
1720 }
1721
1722 static void pr_out_bool(struct dl *dl, const char *name, bool val)
1723 {
1724 if (dl->json_output)
1725 jsonw_bool_field(dl->jw, name, val);
1726 else
1727 pr_out_str(dl, name, val ? "true" : "false");
1728 }
1729
1730 static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
1731 {
1732 if (dl->json_output) {
1733 jsonw_uint_field(dl->jw, name, val);
1734 } else {
1735 if (g_indent_newline)
1736 pr_out("%s %u", name, val);
1737 else
1738 pr_out(" %s %u", name, val);
1739 }
1740 }
1741
1742 static void pr_out_u64(struct dl *dl, const char *name, uint64_t val)
1743 {
1744 if (val == (uint64_t) -1)
1745 return pr_out_str(dl, name, "unlimited");
1746
1747 if (dl->json_output) {
1748 jsonw_u64_field(dl->jw, name, val);
1749 } else {
1750 if (g_indent_newline)
1751 pr_out("%s %"PRIu64, name, val);
1752 else
1753 pr_out(" %s %"PRIu64, name, val);
1754 }
1755 }
1756
1757 static void pr_out_bool_value(struct dl *dl, bool value)
1758 {
1759 if (dl->json_output)
1760 jsonw_bool(dl->jw, value);
1761 else
1762 pr_out(" %s", value ? "true" : "false");
1763 }
1764
1765 static void pr_out_uint_value(struct dl *dl, unsigned int value)
1766 {
1767 if (dl->json_output)
1768 jsonw_uint(dl->jw, value);
1769 else
1770 pr_out(" %u", value);
1771 }
1772
1773 static void pr_out_uint64_value(struct dl *dl, uint64_t value)
1774 {
1775 if (dl->json_output)
1776 jsonw_u64(dl->jw, value);
1777 else
1778 pr_out(" %"PRIu64, value);
1779 }
1780
1781 static bool is_binary_eol(int i)
1782 {
1783 return !(i%16);
1784 }
1785
1786 static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len)
1787 {
1788 int i = 0;
1789
1790 while (i < len) {
1791 if (dl->json_output)
1792 jsonw_printf(dl->jw, "%d", data[i]);
1793 else
1794 pr_out("%02x ", data[i]);
1795 i++;
1796 if (!dl->json_output && is_binary_eol(i))
1797 __pr_out_newline();
1798 }
1799 if (!dl->json_output && !is_binary_eol(i))
1800 __pr_out_newline();
1801 }
1802
1803 static void pr_out_str_value(struct dl *dl, const char *value)
1804 {
1805 if (dl->json_output)
1806 jsonw_string(dl->jw, value);
1807 else
1808 pr_out(" %s", value);
1809 }
1810
1811 static void pr_out_name(struct dl *dl, const char *name)
1812 {
1813 if (dl->json_output)
1814 jsonw_name(dl->jw, name);
1815 else
1816 pr_out(" %s:", name);
1817 }
1818
1819 static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr)
1820 {
1821 if (dl->json_output) {
1822 jsonw_name(dl->jw, "address");
1823 jsonw_uint(dl->jw, addr);
1824 jsonw_name(dl->jw, "data");
1825 jsonw_start_array(dl->jw);
1826 }
1827 }
1828
1829 static void pr_out_region_chunk_end(struct dl *dl)
1830 {
1831 if (dl->json_output)
1832 jsonw_end_array(dl->jw);
1833 }
1834
1835 static void pr_out_region_chunk(struct dl *dl, uint8_t *data, uint32_t len,
1836 uint64_t addr)
1837 {
1838 static uint64_t align_val;
1839 uint32_t i = 0;
1840
1841 pr_out_region_chunk_start(dl, addr);
1842 while (i < len) {
1843 if (!dl->json_output)
1844 if (!(align_val % 16))
1845 pr_out("%s%016"PRIx64" ",
1846 align_val ? "\n" : "",
1847 addr);
1848
1849 align_val++;
1850
1851 if (dl->json_output)
1852 jsonw_printf(dl->jw, "%d", data[i]);
1853 else
1854 pr_out("%02x ", data[i]);
1855
1856 addr++;
1857 i++;
1858 }
1859 pr_out_region_chunk_end(dl);
1860 }
1861
1862 static void pr_out_dev(struct dl *dl, struct nlattr **tb)
1863 {
1864 pr_out_handle(dl, tb);
1865 }
1866
1867 static void pr_out_section_start(struct dl *dl, const char *name)
1868 {
1869 if (dl->json_output) {
1870 jsonw_start_object(dl->jw);
1871 jsonw_name(dl->jw, name);
1872 jsonw_start_object(dl->jw);
1873 }
1874 }
1875
1876 static void pr_out_section_end(struct dl *dl)
1877 {
1878 if (dl->json_output) {
1879 if (dl->arr_last.present)
1880 jsonw_end_array(dl->jw);
1881 jsonw_end_object(dl->jw);
1882 jsonw_end_object(dl->jw);
1883 }
1884 }
1885
1886 static void pr_out_array_start(struct dl *dl, const char *name)
1887 {
1888 if (dl->json_output) {
1889 jsonw_name(dl->jw, name);
1890 jsonw_start_array(dl->jw);
1891 } else {
1892 __pr_out_indent_inc();
1893 __pr_out_newline();
1894 pr_out("%s:", name);
1895 __pr_out_indent_inc();
1896 __pr_out_newline();
1897 }
1898 }
1899
1900 static void pr_out_array_end(struct dl *dl)
1901 {
1902 if (dl->json_output) {
1903 jsonw_end_array(dl->jw);
1904 } else {
1905 __pr_out_indent_dec();
1906 __pr_out_indent_dec();
1907 }
1908 }
1909
1910 static void pr_out_object_start(struct dl *dl, const char *name)
1911 {
1912 if (dl->json_output) {
1913 jsonw_name(dl->jw, name);
1914 jsonw_start_object(dl->jw);
1915 } else {
1916 __pr_out_indent_inc();
1917 __pr_out_newline();
1918 pr_out("%s:", name);
1919 __pr_out_indent_inc();
1920 __pr_out_newline();
1921 }
1922 }
1923
1924 static void pr_out_object_end(struct dl *dl)
1925 {
1926 if (dl->json_output) {
1927 jsonw_end_object(dl->jw);
1928 } else {
1929 __pr_out_indent_dec();
1930 __pr_out_indent_dec();
1931 }
1932 }
1933
1934 static void pr_out_entry_start(struct dl *dl)
1935 {
1936 if (dl->json_output)
1937 jsonw_start_object(dl->jw);
1938 }
1939
1940 static void pr_out_entry_end(struct dl *dl)
1941 {
1942 if (dl->json_output)
1943 jsonw_end_object(dl->jw);
1944 else
1945 __pr_out_newline();
1946 }
1947
1948 static const char *param_cmode_name(uint8_t cmode)
1949 {
1950 switch (cmode) {
1951 case DEVLINK_PARAM_CMODE_RUNTIME:
1952 return PARAM_CMODE_RUNTIME_STR;
1953 case DEVLINK_PARAM_CMODE_DRIVERINIT:
1954 return PARAM_CMODE_DRIVERINIT_STR;
1955 case DEVLINK_PARAM_CMODE_PERMANENT:
1956 return PARAM_CMODE_PERMANENT_STR;
1957 default: return "<unknown type>";
1958 }
1959 }
1960
1961 static const char *eswitch_mode_name(uint32_t mode)
1962 {
1963 switch (mode) {
1964 case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY;
1965 case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV;
1966 default: return "<unknown mode>";
1967 }
1968 }
1969
1970 static const char *eswitch_inline_mode_name(uint32_t mode)
1971 {
1972 switch (mode) {
1973 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1974 return ESWITCH_INLINE_MODE_NONE;
1975 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1976 return ESWITCH_INLINE_MODE_LINK;
1977 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1978 return ESWITCH_INLINE_MODE_NETWORK;
1979 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1980 return ESWITCH_INLINE_MODE_TRANSPORT;
1981 default:
1982 return "<unknown mode>";
1983 }
1984 }
1985
1986 static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
1987 {
1988 __pr_out_handle_start(dl, tb, true, false);
1989
1990 if (tb[DEVLINK_ATTR_ESWITCH_MODE])
1991 pr_out_str(dl, "mode",
1992 eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE])));
1993
1994 if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])
1995 pr_out_str(dl, "inline-mode",
1996 eswitch_inline_mode_name(mnl_attr_get_u8(
1997 tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
1998
1999 if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
2000 bool encap_mode = !!mnl_attr_get_u8(tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
2001
2002 pr_out_str(dl, "encap", encap_mode ? "enable" : "disable");
2003 }
2004
2005 pr_out_handle_end(dl);
2006 }
2007
2008 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data)
2009 {
2010 struct dl *dl = data;
2011 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2012 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2013
2014 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2015 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2016 return MNL_CB_ERROR;
2017 pr_out_eswitch(dl, tb);
2018 return MNL_CB_OK;
2019 }
2020
2021 static int cmd_dev_eswitch_show(struct dl *dl)
2022 {
2023 struct nlmsghdr *nlh;
2024 int err;
2025
2026 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_GET,
2027 NLM_F_REQUEST | NLM_F_ACK);
2028
2029 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2030 if (err)
2031 return err;
2032
2033 pr_out_section_start(dl, "dev");
2034 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl);
2035 pr_out_section_end(dl);
2036 return err;
2037 }
2038
2039 static int cmd_dev_eswitch_set(struct dl *dl)
2040 {
2041 struct nlmsghdr *nlh;
2042 int err;
2043
2044 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_SET,
2045 NLM_F_REQUEST | NLM_F_ACK);
2046
2047 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
2048 DL_OPT_ESWITCH_MODE |
2049 DL_OPT_ESWITCH_INLINE_MODE |
2050 DL_OPT_ESWITCH_ENCAP_MODE);
2051
2052 if (err)
2053 return err;
2054
2055 if (dl->opts.present == 1) {
2056 pr_err("Need to set at least one option\n");
2057 return -ENOENT;
2058 }
2059
2060 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2061 }
2062
2063 static int cmd_dev_eswitch(struct dl *dl)
2064 {
2065 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2066 cmd_dev_help();
2067 return 0;
2068 } else if (dl_argv_match(dl, "set")) {
2069 dl_arg_inc(dl);
2070 return cmd_dev_eswitch_set(dl);
2071 } else if (dl_argv_match(dl, "show")) {
2072 dl_arg_inc(dl);
2073 return cmd_dev_eswitch_show(dl);
2074 }
2075 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2076 return -ENOENT;
2077 }
2078
2079 struct param_val_conv {
2080 const char *name;
2081 const char *vstr;
2082 uint32_t vuint;
2083 };
2084
2085 static bool param_val_conv_exists(const struct param_val_conv *param_val_conv,
2086 uint32_t len, const char *name)
2087 {
2088 uint32_t i;
2089
2090 for (i = 0; i < len; i++)
2091 if (!strcmp(param_val_conv[i].name, name))
2092 return true;
2093
2094 return false;
2095 }
2096
2097 static int
2098 param_val_conv_uint_get(const struct param_val_conv *param_val_conv,
2099 uint32_t len, const char *name, const char *vstr,
2100 uint32_t *vuint)
2101 {
2102 uint32_t i;
2103
2104 for (i = 0; i < len; i++)
2105 if (!strcmp(param_val_conv[i].name, name) &&
2106 !strcmp(param_val_conv[i].vstr, vstr)) {
2107 *vuint = param_val_conv[i].vuint;
2108 return 0;
2109 }
2110
2111 return -ENOENT;
2112 }
2113
2114 static int
2115 param_val_conv_str_get(const struct param_val_conv *param_val_conv,
2116 uint32_t len, const char *name, uint32_t vuint,
2117 const char **vstr)
2118 {
2119 uint32_t i;
2120
2121 for (i = 0; i < len; i++)
2122 if (!strcmp(param_val_conv[i].name, name) &&
2123 param_val_conv[i].vuint == vuint) {
2124 *vstr = param_val_conv[i].vstr;
2125 return 0;
2126 }
2127
2128 return -ENOENT;
2129 }
2130
2131 static const struct param_val_conv param_val_conv[] = {
2132 {
2133 .name = "fw_load_policy",
2134 .vstr = "driver",
2135 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
2136 },
2137 {
2138 .name = "fw_load_policy",
2139 .vstr = "flash",
2140 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
2141 },
2142 };
2143
2144 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2145
2146 static void pr_out_param_value(struct dl *dl, const char *nla_name,
2147 int nla_type, struct nlattr *nl)
2148 {
2149 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2150 struct nlattr *val_attr;
2151 const char *vstr;
2152 bool conv_exists;
2153 int err;
2154
2155 err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
2156 if (err != MNL_CB_OK)
2157 return;
2158
2159 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2160 (nla_type != MNL_TYPE_FLAG &&
2161 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2162 return;
2163
2164 pr_out_str(dl, "cmode",
2165 param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
2166 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2167
2168 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2169 nla_name);
2170
2171 switch (nla_type) {
2172 case MNL_TYPE_U8:
2173 if (conv_exists) {
2174 err = param_val_conv_str_get(param_val_conv,
2175 PARAM_VAL_CONV_LEN,
2176 nla_name,
2177 mnl_attr_get_u8(val_attr),
2178 &vstr);
2179 if (err)
2180 return;
2181 pr_out_str(dl, "value", vstr);
2182 } else {
2183 pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
2184 }
2185 break;
2186 case MNL_TYPE_U16:
2187 if (conv_exists) {
2188 err = param_val_conv_str_get(param_val_conv,
2189 PARAM_VAL_CONV_LEN,
2190 nla_name,
2191 mnl_attr_get_u16(val_attr),
2192 &vstr);
2193 if (err)
2194 return;
2195 pr_out_str(dl, "value", vstr);
2196 } else {
2197 pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
2198 }
2199 break;
2200 case MNL_TYPE_U32:
2201 if (conv_exists) {
2202 err = param_val_conv_str_get(param_val_conv,
2203 PARAM_VAL_CONV_LEN,
2204 nla_name,
2205 mnl_attr_get_u32(val_attr),
2206 &vstr);
2207 if (err)
2208 return;
2209 pr_out_str(dl, "value", vstr);
2210 } else {
2211 pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
2212 }
2213 break;
2214 case MNL_TYPE_STRING:
2215 pr_out_str(dl, "value", mnl_attr_get_str(val_attr));
2216 break;
2217 case MNL_TYPE_FLAG:
2218 pr_out_bool(dl, "value", val_attr ? true : false);
2219 break;
2220 }
2221 }
2222
2223 static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
2224 {
2225 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2226 struct nlattr *param_value_attr;
2227 const char *nla_name;
2228 int nla_type;
2229 int err;
2230
2231 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2232 if (err != MNL_CB_OK)
2233 return;
2234 if (!nla_param[DEVLINK_ATTR_PARAM_NAME] ||
2235 !nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2236 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2237 return;
2238
2239 if (array)
2240 pr_out_handle_start_arr(dl, tb);
2241 else
2242 __pr_out_handle_start(dl, tb, true, false);
2243
2244 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2245
2246 nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
2247 pr_out_str(dl, "name", nla_name);
2248
2249 if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
2250 pr_out_str(dl, "type", "driver-specific");
2251 else
2252 pr_out_str(dl, "type", "generic");
2253
2254 pr_out_array_start(dl, "values");
2255 mnl_attr_for_each_nested(param_value_attr,
2256 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2257 pr_out_entry_start(dl);
2258 pr_out_param_value(dl, nla_name, nla_type, param_value_attr);
2259 pr_out_entry_end(dl);
2260 }
2261 pr_out_array_end(dl);
2262 pr_out_handle_end(dl);
2263 }
2264
2265 static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
2266 {
2267 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2268 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2269 struct dl *dl = data;
2270
2271 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2272 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2273 !tb[DEVLINK_ATTR_PARAM])
2274 return MNL_CB_ERROR;
2275 pr_out_param(dl, tb, true);
2276 return MNL_CB_OK;
2277 }
2278
2279 struct param_ctx {
2280 struct dl *dl;
2281 int nla_type;
2282 union {
2283 uint8_t vu8;
2284 uint16_t vu16;
2285 uint32_t vu32;
2286 const char *vstr;
2287 bool vbool;
2288 } value;
2289 };
2290
2291 static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
2292 {
2293 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2294 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2295 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2296 struct nlattr *param_value_attr;
2297 enum devlink_param_cmode cmode;
2298 struct param_ctx *ctx = data;
2299 struct dl *dl = ctx->dl;
2300 int nla_type;
2301 int err;
2302
2303 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2304 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2305 !tb[DEVLINK_ATTR_PARAM])
2306 return MNL_CB_ERROR;
2307
2308 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2309 if (err != MNL_CB_OK)
2310 return MNL_CB_ERROR;
2311
2312 if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2313 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2314 return MNL_CB_ERROR;
2315
2316 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2317 mnl_attr_for_each_nested(param_value_attr,
2318 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2319 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2320 struct nlattr *val_attr;
2321
2322 err = mnl_attr_parse_nested(param_value_attr,
2323 attr_cb, nla_value);
2324 if (err != MNL_CB_OK)
2325 return MNL_CB_ERROR;
2326
2327 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2328 (nla_type != MNL_TYPE_FLAG &&
2329 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2330 return MNL_CB_ERROR;
2331
2332 cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
2333 if (cmode == dl->opts.cmode) {
2334 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2335 switch (nla_type) {
2336 case MNL_TYPE_U8:
2337 ctx->value.vu8 = mnl_attr_get_u8(val_attr);
2338 break;
2339 case MNL_TYPE_U16:
2340 ctx->value.vu16 = mnl_attr_get_u16(val_attr);
2341 break;
2342 case MNL_TYPE_U32:
2343 ctx->value.vu32 = mnl_attr_get_u32(val_attr);
2344 break;
2345 case MNL_TYPE_STRING:
2346 ctx->value.vstr = mnl_attr_get_str(val_attr);
2347 break;
2348 case MNL_TYPE_FLAG:
2349 ctx->value.vbool = val_attr ? true : false;
2350 break;
2351 }
2352 break;
2353 }
2354 }
2355 ctx->nla_type = nla_type;
2356 return MNL_CB_OK;
2357 }
2358
2359 static int cmd_dev_param_set(struct dl *dl)
2360 {
2361 struct param_ctx ctx = {};
2362 struct nlmsghdr *nlh;
2363 bool conv_exists;
2364 uint32_t val_u32;
2365 uint16_t val_u16;
2366 uint8_t val_u8;
2367 bool val_bool;
2368 int err;
2369
2370 err = dl_argv_parse(dl, DL_OPT_HANDLE |
2371 DL_OPT_PARAM_NAME |
2372 DL_OPT_PARAM_VALUE |
2373 DL_OPT_PARAM_CMODE, 0);
2374 if (err)
2375 return err;
2376
2377 /* Get value type */
2378 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET,
2379 NLM_F_REQUEST | NLM_F_ACK);
2380 dl_opts_put(nlh, dl);
2381
2382 ctx.dl = dl;
2383 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
2384 if (err)
2385 return err;
2386
2387 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_SET,
2388 NLM_F_REQUEST | NLM_F_ACK);
2389 dl_opts_put(nlh, dl);
2390
2391 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2392 dl->opts.param_name);
2393
2394 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
2395 switch (ctx.nla_type) {
2396 case MNL_TYPE_U8:
2397 if (conv_exists) {
2398 err = param_val_conv_uint_get(param_val_conv,
2399 PARAM_VAL_CONV_LEN,
2400 dl->opts.param_name,
2401 dl->opts.param_value,
2402 &val_u32);
2403 val_u8 = val_u32;
2404 } else {
2405 err = strtouint8_t(dl->opts.param_value, &val_u8);
2406 }
2407 if (err)
2408 goto err_param_value_parse;
2409 if (val_u8 == ctx.value.vu8)
2410 return 0;
2411 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
2412 break;
2413 case MNL_TYPE_U16:
2414 if (conv_exists) {
2415 err = param_val_conv_uint_get(param_val_conv,
2416 PARAM_VAL_CONV_LEN,
2417 dl->opts.param_name,
2418 dl->opts.param_value,
2419 &val_u32);
2420 val_u16 = val_u32;
2421 } else {
2422 err = strtouint16_t(dl->opts.param_value, &val_u16);
2423 }
2424 if (err)
2425 goto err_param_value_parse;
2426 if (val_u16 == ctx.value.vu16)
2427 return 0;
2428 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
2429 break;
2430 case MNL_TYPE_U32:
2431 if (conv_exists)
2432 err = param_val_conv_uint_get(param_val_conv,
2433 PARAM_VAL_CONV_LEN,
2434 dl->opts.param_name,
2435 dl->opts.param_value,
2436 &val_u32);
2437 else
2438 err = strtouint32_t(dl->opts.param_value, &val_u32);
2439 if (err)
2440 goto err_param_value_parse;
2441 if (val_u32 == ctx.value.vu32)
2442 return 0;
2443 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
2444 break;
2445 case MNL_TYPE_FLAG:
2446 err = strtobool(dl->opts.param_value, &val_bool);
2447 if (err)
2448 goto err_param_value_parse;
2449 if (val_bool == ctx.value.vbool)
2450 return 0;
2451 if (val_bool)
2452 mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2453 0, NULL);
2454 break;
2455 case MNL_TYPE_STRING:
2456 mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2457 dl->opts.param_value);
2458 if (!strcmp(dl->opts.param_value, ctx.value.vstr))
2459 return 0;
2460 break;
2461 default:
2462 printf("Value type not supported\n");
2463 return -ENOTSUP;
2464 }
2465 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2466
2467 err_param_value_parse:
2468 pr_err("Value \"%s\" is not a number or not within range\n",
2469 dl->opts.param_value);
2470 return err;
2471 }
2472
2473 static int cmd_dev_param_show(struct dl *dl)
2474 {
2475 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2476 struct nlmsghdr *nlh;
2477 int err;
2478
2479 if (dl_argc(dl) == 0)
2480 flags |= NLM_F_DUMP;
2481
2482 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
2483
2484 if (dl_argc(dl) > 0) {
2485 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
2486 DL_OPT_PARAM_NAME, 0);
2487 if (err)
2488 return err;
2489 }
2490
2491 pr_out_section_start(dl, "param");
2492 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_show_cb, dl);
2493 pr_out_section_end(dl);
2494 return err;
2495 }
2496
2497 static int cmd_dev_param(struct dl *dl)
2498 {
2499 if (dl_argv_match(dl, "help")) {
2500 cmd_dev_help();
2501 return 0;
2502 } else if (dl_argv_match(dl, "show") ||
2503 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2504 dl_arg_inc(dl);
2505 return cmd_dev_param_show(dl);
2506 } else if (dl_argv_match(dl, "set")) {
2507 dl_arg_inc(dl);
2508 return cmd_dev_param_set(dl);
2509 }
2510 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2511 return -ENOENT;
2512 }
2513 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
2514 {
2515 struct dl *dl = data;
2516 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2517 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2518
2519 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2520 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2521 return MNL_CB_ERROR;
2522 pr_out_dev(dl, tb);
2523 return MNL_CB_OK;
2524 }
2525
2526 static int cmd_dev_show(struct dl *dl)
2527 {
2528 struct nlmsghdr *nlh;
2529 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2530 int err;
2531
2532 if (dl_argc(dl) == 0)
2533 flags |= NLM_F_DUMP;
2534
2535 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
2536
2537 if (dl_argc(dl) > 0) {
2538 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2539 if (err)
2540 return err;
2541 }
2542
2543 pr_out_section_start(dl, "dev");
2544 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl);
2545 pr_out_section_end(dl);
2546 return err;
2547 }
2548
2549 static void cmd_dev_reload_help(void)
2550 {
2551 pr_err("Usage: devlink dev reload [ DEV ]\n");
2552 }
2553
2554 static int cmd_dev_reload(struct dl *dl)
2555 {
2556 struct nlmsghdr *nlh;
2557 int err;
2558
2559 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2560 cmd_dev_reload_help();
2561 return 0;
2562 }
2563
2564 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RELOAD,
2565 NLM_F_REQUEST | NLM_F_ACK);
2566
2567 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2568 if (err)
2569 return err;
2570
2571 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2572 }
2573
2574 static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
2575 const char *name, int type)
2576 {
2577 struct nlattr *version;
2578
2579 mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) {
2580 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2581 const char *ver_value;
2582 const char *ver_name;
2583 int err;
2584
2585 if (mnl_attr_get_type(version) != type)
2586 continue;
2587
2588 err = mnl_attr_parse_nested(version, attr_cb, tb);
2589 if (err != MNL_CB_OK)
2590 continue;
2591
2592 if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] ||
2593 !tb[DEVLINK_ATTR_INFO_VERSION_VALUE])
2594 continue;
2595
2596 if (name) {
2597 pr_out_object_start(dl, name);
2598 name = NULL;
2599 }
2600
2601 ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
2602 ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
2603
2604 pr_out_str(dl, ver_name, ver_value);
2605 if (!dl->json_output)
2606 __pr_out_newline();
2607 }
2608
2609 if (!name)
2610 pr_out_object_end(dl);
2611 }
2612
2613 static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh,
2614 struct nlattr **tb, bool has_versions)
2615 {
2616 __pr_out_handle_start(dl, tb, true, false);
2617
2618 __pr_out_indent_inc();
2619 if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) {
2620 struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME];
2621
2622 if (!dl->json_output)
2623 __pr_out_newline();
2624 pr_out_str(dl, "driver", mnl_attr_get_str(nla_drv));
2625 }
2626
2627 if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
2628 struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER];
2629
2630 if (!dl->json_output)
2631 __pr_out_newline();
2632 pr_out_str(dl, "serial_number", mnl_attr_get_str(nla_sn));
2633 }
2634 __pr_out_indent_dec();
2635
2636 if (has_versions) {
2637 pr_out_object_start(dl, "versions");
2638
2639 pr_out_versions_single(dl, nlh, "fixed",
2640 DEVLINK_ATTR_INFO_VERSION_FIXED);
2641 pr_out_versions_single(dl, nlh, "running",
2642 DEVLINK_ATTR_INFO_VERSION_RUNNING);
2643 pr_out_versions_single(dl, nlh, "stored",
2644 DEVLINK_ATTR_INFO_VERSION_STORED);
2645
2646 pr_out_object_end(dl);
2647 }
2648
2649 pr_out_handle_end(dl);
2650 }
2651
2652 static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data)
2653 {
2654 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2655 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2656 bool has_versions, has_info;
2657 struct dl *dl = data;
2658
2659 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2660
2661 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2662 return MNL_CB_ERROR;
2663
2664 has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] ||
2665 tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] ||
2666 tb[DEVLINK_ATTR_INFO_VERSION_STORED];
2667 has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] ||
2668 tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] ||
2669 has_versions;
2670
2671 if (has_info)
2672 pr_out_info(dl, nlh, tb, has_versions);
2673
2674 return MNL_CB_OK;
2675 }
2676
2677 static void cmd_dev_info_help(void)
2678 {
2679 pr_err("Usage: devlink dev info [ DEV ]\n");
2680 }
2681
2682 static int cmd_dev_info(struct dl *dl)
2683 {
2684 struct nlmsghdr *nlh;
2685 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2686 int err;
2687
2688 if (dl_argv_match(dl, "help")) {
2689 cmd_dev_info_help();
2690 return 0;
2691 }
2692
2693 if (dl_argc(dl) == 0)
2694 flags |= NLM_F_DUMP;
2695
2696 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_INFO_GET, flags);
2697
2698 if (dl_argc(dl) > 0) {
2699 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2700 if (err)
2701 return err;
2702 }
2703
2704 pr_out_section_start(dl, "info");
2705 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_versions_show_cb, dl);
2706 pr_out_section_end(dl);
2707 return err;
2708 }
2709
2710 static void cmd_dev_flash_help(void)
2711 {
2712 pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
2713 }
2714
2715 static int cmd_dev_flash(struct dl *dl)
2716 {
2717 struct nlmsghdr *nlh;
2718 int err;
2719
2720 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2721 cmd_dev_flash_help();
2722 return 0;
2723 }
2724
2725 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
2726 NLM_F_REQUEST | NLM_F_ACK);
2727
2728 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
2729 DL_OPT_FLASH_COMPONENT);
2730 if (err)
2731 return err;
2732
2733 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2734 }
2735
2736 static int cmd_dev(struct dl *dl)
2737 {
2738 if (dl_argv_match(dl, "help")) {
2739 cmd_dev_help();
2740 return 0;
2741 } else if (dl_argv_match(dl, "show") ||
2742 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2743 dl_arg_inc(dl);
2744 return cmd_dev_show(dl);
2745 } else if (dl_argv_match(dl, "eswitch")) {
2746 dl_arg_inc(dl);
2747 return cmd_dev_eswitch(dl);
2748 } else if (dl_argv_match(dl, "reload")) {
2749 dl_arg_inc(dl);
2750 return cmd_dev_reload(dl);
2751 } else if (dl_argv_match(dl, "param")) {
2752 dl_arg_inc(dl);
2753 return cmd_dev_param(dl);
2754 } else if (dl_argv_match(dl, "info")) {
2755 dl_arg_inc(dl);
2756 return cmd_dev_info(dl);
2757 } else if (dl_argv_match(dl, "flash")) {
2758 dl_arg_inc(dl);
2759 return cmd_dev_flash(dl);
2760 }
2761 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2762 return -ENOENT;
2763 }
2764
2765 static void cmd_port_help(void)
2766 {
2767 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
2768 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
2769 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
2770 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
2771 }
2772
2773 static const char *port_type_name(uint32_t type)
2774 {
2775 switch (type) {
2776 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
2777 case DEVLINK_PORT_TYPE_AUTO: return "auto";
2778 case DEVLINK_PORT_TYPE_ETH: return "eth";
2779 case DEVLINK_PORT_TYPE_IB: return "ib";
2780 default: return "<unknown type>";
2781 }
2782 }
2783
2784 static const char *port_flavour_name(uint16_t flavour)
2785 {
2786 switch (flavour) {
2787 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
2788 return "physical";
2789 case DEVLINK_PORT_FLAVOUR_CPU:
2790 return "cpu";
2791 case DEVLINK_PORT_FLAVOUR_DSA:
2792 return "dsa";
2793 case DEVLINK_PORT_FLAVOUR_PCI_PF:
2794 return "pcipf";
2795 case DEVLINK_PORT_FLAVOUR_PCI_VF:
2796 return "pcivf";
2797 default:
2798 return "<unknown flavour>";
2799 }
2800 }
2801
2802 static void pr_out_port_pfvf_num(struct dl *dl, struct nlattr **tb)
2803 {
2804 uint16_t fn_num;
2805
2806 if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
2807 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
2808 pr_out_uint(dl, "pfnum", fn_num);
2809 }
2810 if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
2811 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
2812 pr_out_uint(dl, "vfnum", fn_num);
2813 }
2814 }
2815
2816 static void pr_out_port(struct dl *dl, struct nlattr **tb)
2817 {
2818 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
2819 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
2820
2821 pr_out_port_handle_start(dl, tb, false);
2822 if (pt_attr) {
2823 uint16_t port_type = mnl_attr_get_u16(pt_attr);
2824
2825 pr_out_str(dl, "type", port_type_name(port_type));
2826 if (dpt_attr) {
2827 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
2828
2829 if (port_type != des_port_type)
2830 pr_out_str(dl, "des_type",
2831 port_type_name(des_port_type));
2832 }
2833 }
2834 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
2835 pr_out_str(dl, "netdev",
2836 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
2837 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
2838 pr_out_str(dl, "ibdev",
2839 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
2840 if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
2841 uint16_t port_flavour =
2842 mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
2843
2844 pr_out_str(dl, "flavour", port_flavour_name(port_flavour));
2845
2846 switch (port_flavour) {
2847 case DEVLINK_PORT_FLAVOUR_PCI_PF:
2848 case DEVLINK_PORT_FLAVOUR_PCI_VF:
2849 pr_out_port_pfvf_num(dl, tb);
2850 break;
2851 default:
2852 break;
2853 }
2854 }
2855 if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
2856 uint32_t port_number;
2857
2858 port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
2859 pr_out_uint(dl, "port", port_number);
2860 }
2861 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
2862 pr_out_uint(dl, "split_group",
2863 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
2864 pr_out_port_handle_end(dl);
2865 }
2866
2867 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
2868 {
2869 struct dl *dl = data;
2870 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2871 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2872
2873 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2874 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2875 !tb[DEVLINK_ATTR_PORT_INDEX])
2876 return MNL_CB_ERROR;
2877 pr_out_port(dl, tb);
2878 return MNL_CB_OK;
2879 }
2880
2881 static int cmd_port_show(struct dl *dl)
2882 {
2883 struct nlmsghdr *nlh;
2884 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2885 int err;
2886
2887 if (dl_argc(dl) == 0)
2888 flags |= NLM_F_DUMP;
2889
2890 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
2891
2892 if (dl_argc(dl) > 0) {
2893 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
2894 if (err)
2895 return err;
2896 }
2897
2898 pr_out_section_start(dl, "port");
2899 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
2900 pr_out_section_end(dl);
2901 return err;
2902 }
2903
2904 static int cmd_port_set(struct dl *dl)
2905 {
2906 struct nlmsghdr *nlh;
2907 int err;
2908
2909 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
2910 NLM_F_REQUEST | NLM_F_ACK);
2911
2912 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
2913 if (err)
2914 return err;
2915
2916 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2917 }
2918
2919 static int cmd_port_split(struct dl *dl)
2920 {
2921 struct nlmsghdr *nlh;
2922 int err;
2923
2924 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
2925 NLM_F_REQUEST | NLM_F_ACK);
2926
2927 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
2928 if (err)
2929 return err;
2930
2931 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2932 }
2933
2934 static int cmd_port_unsplit(struct dl *dl)
2935 {
2936 struct nlmsghdr *nlh;
2937 int err;
2938
2939 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
2940 NLM_F_REQUEST | NLM_F_ACK);
2941
2942 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
2943 if (err)
2944 return err;
2945
2946 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2947 }
2948
2949 static int cmd_port(struct dl *dl)
2950 {
2951 if (dl_argv_match(dl, "help")) {
2952 cmd_port_help();
2953 return 0;
2954 } else if (dl_argv_match(dl, "show") ||
2955 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2956 dl_arg_inc(dl);
2957 return cmd_port_show(dl);
2958 } else if (dl_argv_match(dl, "set")) {
2959 dl_arg_inc(dl);
2960 return cmd_port_set(dl);
2961 } else if (dl_argv_match(dl, "split")) {
2962 dl_arg_inc(dl);
2963 return cmd_port_split(dl);
2964 } else if (dl_argv_match(dl, "unsplit")) {
2965 dl_arg_inc(dl);
2966 return cmd_port_unsplit(dl);
2967 }
2968 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2969 return -ENOENT;
2970 }
2971
2972 static void cmd_sb_help(void)
2973 {
2974 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
2975 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
2976 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
2977 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
2978 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
2979 pr_err(" pool POOL_INDEX ]\n");
2980 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
2981 pr_err(" pool POOL_INDEX th THRESHOLD\n");
2982 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
2983 pr_err(" type { ingress | egress } ]\n");
2984 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
2985 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
2986 pr_err(" th THRESHOLD\n");
2987 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
2988 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
2989 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
2990 }
2991
2992 static void pr_out_sb(struct dl *dl, struct nlattr **tb)
2993 {
2994 pr_out_handle_start_arr(dl, tb);
2995 pr_out_uint(dl, "sb",
2996 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
2997 pr_out_uint(dl, "size",
2998 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
2999 pr_out_uint(dl, "ing_pools",
3000 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
3001 pr_out_uint(dl, "eg_pools",
3002 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
3003 pr_out_uint(dl, "ing_tcs",
3004 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
3005 pr_out_uint(dl, "eg_tcs",
3006 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
3007 pr_out_handle_end(dl);
3008 }
3009
3010 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
3011 {
3012 struct dl *dl = data;
3013 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3014 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3015
3016 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3017 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3018 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
3019 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
3020 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
3021 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
3022 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
3023 return MNL_CB_ERROR;
3024 pr_out_sb(dl, tb);
3025 return MNL_CB_OK;
3026 }
3027
3028 static int cmd_sb_show(struct dl *dl)
3029 {
3030 struct nlmsghdr *nlh;
3031 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3032 int err;
3033
3034 if (dl_argc(dl) == 0)
3035 flags |= NLM_F_DUMP;
3036
3037 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
3038
3039 if (dl_argc(dl) > 0) {
3040 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
3041 if (err)
3042 return err;
3043 }
3044
3045 pr_out_section_start(dl, "sb");
3046 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl);
3047 pr_out_section_end(dl);
3048 return err;
3049 }
3050
3051 static const char *pool_type_name(uint8_t type)
3052 {
3053 switch (type) {
3054 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
3055 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
3056 default: return "<unknown type>";
3057 }
3058 }
3059
3060 static const char *threshold_type_name(uint8_t type)
3061 {
3062 switch (type) {
3063 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
3064 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
3065 default: return "<unknown type>";
3066 }
3067 }
3068
3069 static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
3070 {
3071 pr_out_handle_start_arr(dl, tb);
3072 pr_out_uint(dl, "sb",
3073 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
3074 pr_out_uint(dl, "pool",
3075 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
3076 pr_out_str(dl, "type",
3077 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
3078 pr_out_uint(dl, "size",
3079 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
3080 pr_out_str(dl, "thtype",
3081 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
3082 if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
3083 pr_out_uint(dl, "cell_size",
3084 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
3085 pr_out_handle_end(dl);
3086 }
3087
3088 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
3089 {
3090 struct dl *dl = data;
3091 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3092 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3093
3094 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3095 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3096 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
3097 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
3098 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
3099 return MNL_CB_ERROR;
3100 pr_out_sb_pool(dl, tb);
3101 return MNL_CB_OK;
3102 }
3103
3104 static int cmd_sb_pool_show(struct dl *dl)
3105 {
3106 struct nlmsghdr *nlh;
3107 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3108 int err;
3109
3110 if (dl_argc(dl) == 0)
3111 flags |= NLM_F_DUMP;
3112
3113 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
3114
3115 if (dl_argc(dl) > 0) {
3116 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
3117 DL_OPT_SB);
3118 if (err)
3119 return err;
3120 }
3121
3122 pr_out_section_start(dl, "pool");
3123 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
3124 pr_out_section_end(dl);
3125 return err;
3126 }
3127
3128 static int cmd_sb_pool_set(struct dl *dl)
3129 {
3130 struct nlmsghdr *nlh;
3131 int err;
3132
3133 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
3134 NLM_F_REQUEST | NLM_F_ACK);
3135
3136 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
3137 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
3138 if (err)
3139 return err;
3140
3141 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3142 }
3143
3144 static int cmd_sb_pool(struct dl *dl)
3145 {
3146 if (dl_argv_match(dl, "help")) {
3147 cmd_sb_help();
3148 return 0;
3149 } else if (dl_argv_match(dl, "show") ||
3150 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3151 dl_arg_inc(dl);
3152 return cmd_sb_pool_show(dl);
3153 } else if (dl_argv_match(dl, "set")) {
3154 dl_arg_inc(dl);
3155 return cmd_sb_pool_set(dl);
3156 }
3157 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3158 return -ENOENT;
3159 }
3160
3161 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
3162 {
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, "pool",
3167 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
3168 pr_out_uint(dl, "threshold",
3169 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
3170 pr_out_port_handle_end(dl);
3171 }
3172
3173 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
3174 {
3175 struct dl *dl = data;
3176 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3177 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3178
3179 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3180 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3181 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3182 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
3183 return MNL_CB_ERROR;
3184 pr_out_sb_port_pool(dl, tb);
3185 return MNL_CB_OK;
3186 }
3187
3188 static int cmd_sb_port_pool_show(struct dl *dl)
3189 {
3190 struct nlmsghdr *nlh;
3191 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3192 int err;
3193
3194 if (dl_argc(dl) == 0)
3195 flags |= NLM_F_DUMP;
3196
3197 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
3198
3199 if (dl_argc(dl) > 0) {
3200 err = dl_argv_parse_put(nlh, dl,
3201 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
3202 DL_OPT_SB);
3203 if (err)
3204 return err;
3205 }
3206
3207 pr_out_section_start(dl, "port_pool");
3208 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
3209 pr_out_section_end(dl);
3210 return 0;
3211 }
3212
3213 static int cmd_sb_port_pool_set(struct dl *dl)
3214 {
3215 struct nlmsghdr *nlh;
3216 int err;
3217
3218 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
3219 NLM_F_REQUEST | NLM_F_ACK);
3220
3221 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
3222 DL_OPT_SB_TH, DL_OPT_SB);
3223 if (err)
3224 return err;
3225
3226 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3227 }
3228
3229 static int cmd_sb_port_pool(struct dl *dl)
3230 {
3231 if (dl_argv_match(dl, "help")) {
3232 cmd_sb_help();
3233 return 0;
3234 } else if (dl_argv_match(dl, "show") ||
3235 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3236 dl_arg_inc(dl);
3237 return cmd_sb_port_pool_show(dl);
3238 } else if (dl_argv_match(dl, "set")) {
3239 dl_arg_inc(dl);
3240 return cmd_sb_port_pool_set(dl);
3241 }
3242 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3243 return -ENOENT;
3244 }
3245
3246 static int cmd_sb_port(struct dl *dl)
3247 {
3248 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3249 cmd_sb_help();
3250 return 0;
3251 } else if (dl_argv_match(dl, "pool")) {
3252 dl_arg_inc(dl);
3253 return cmd_sb_port_pool(dl);
3254 }
3255 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3256 return -ENOENT;
3257 }
3258
3259 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
3260 {
3261 pr_out_port_handle_start_arr(dl, tb, true);
3262 pr_out_uint(dl, "sb",
3263 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
3264 pr_out_uint(dl, "tc",
3265 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
3266 pr_out_str(dl, "type",
3267 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
3268 pr_out_uint(dl, "pool",
3269 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
3270 pr_out_uint(dl, "threshold",
3271 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
3272 pr_out_port_handle_end(dl);
3273 }
3274
3275 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
3276 {
3277 struct dl *dl = data;
3278 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3279 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3280
3281 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3282 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3283 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3284 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
3285 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
3286 return MNL_CB_ERROR;
3287 pr_out_sb_tc_bind(dl, tb);
3288 return MNL_CB_OK;
3289 }
3290
3291 static int cmd_sb_tc_bind_show(struct dl *dl)
3292 {
3293 struct nlmsghdr *nlh;
3294 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3295 int err;
3296
3297 if (dl_argc(dl) == 0)
3298 flags |= NLM_F_DUMP;
3299
3300 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
3301
3302 if (dl_argc(dl) > 0) {
3303 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
3304 DL_OPT_SB_TYPE, DL_OPT_SB);
3305 if (err)
3306 return err;
3307 }
3308
3309 pr_out_section_start(dl, "tc_bind");
3310 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
3311 pr_out_section_end(dl);
3312 return err;
3313 }
3314
3315 static int cmd_sb_tc_bind_set(struct dl *dl)
3316 {
3317 struct nlmsghdr *nlh;
3318 int err;
3319
3320 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
3321 NLM_F_REQUEST | NLM_F_ACK);
3322
3323 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
3324 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
3325 DL_OPT_SB);
3326 if (err)
3327 return err;
3328
3329 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3330 }
3331
3332 static int cmd_sb_tc_bind(struct dl *dl)
3333 {
3334 if (dl_argv_match(dl, "help")) {
3335 cmd_sb_help();
3336 return 0;
3337 } else if (dl_argv_match(dl, "show") ||
3338 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3339 dl_arg_inc(dl);
3340 return cmd_sb_tc_bind_show(dl);
3341 } else if (dl_argv_match(dl, "set")) {
3342 dl_arg_inc(dl);
3343 return cmd_sb_tc_bind_set(dl);
3344 }
3345 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3346 return -ENOENT;
3347 }
3348
3349 static int cmd_sb_tc(struct dl *dl)
3350 {
3351 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3352 cmd_sb_help();
3353 return 0;
3354 } else if (dl_argv_match(dl, "bind")) {
3355 dl_arg_inc(dl);
3356 return cmd_sb_tc_bind(dl);
3357 }
3358 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3359 return -ENOENT;
3360 }
3361
3362 struct occ_item {
3363 struct list_head list;
3364 uint32_t index;
3365 uint32_t cur;
3366 uint32_t max;
3367 uint32_t bound_pool_index;
3368 };
3369
3370 struct occ_port {
3371 struct list_head list;
3372 char *bus_name;
3373 char *dev_name;
3374 uint32_t port_index;
3375 uint32_t sb_index;
3376 struct list_head pool_list;
3377 struct list_head ing_tc_list;
3378 struct list_head eg_tc_list;
3379 };
3380
3381 struct occ_show {
3382 struct dl *dl;
3383 int err;
3384 struct list_head port_list;
3385 };
3386
3387 static struct occ_item *occ_item_alloc(void)
3388 {
3389 return calloc(1, sizeof(struct occ_item));
3390 }
3391
3392 static void occ_item_free(struct occ_item *occ_item)
3393 {
3394 free(occ_item);
3395 }
3396
3397 static struct occ_port *occ_port_alloc(uint32_t port_index)
3398 {
3399 struct occ_port *occ_port;
3400
3401 occ_port = calloc(1, sizeof(*occ_port));
3402 if (!occ_port)
3403 return NULL;
3404 occ_port->port_index = port_index;
3405 INIT_LIST_HEAD(&occ_port->pool_list);
3406 INIT_LIST_HEAD(&occ_port->ing_tc_list);
3407 INIT_LIST_HEAD(&occ_port->eg_tc_list);
3408 return occ_port;
3409 }
3410
3411 static void occ_port_free(struct occ_port *occ_port)
3412 {
3413 struct occ_item *occ_item, *tmp;
3414
3415 list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
3416 occ_item_free(occ_item);
3417 list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
3418 occ_item_free(occ_item);
3419 list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
3420 occ_item_free(occ_item);
3421 }
3422
3423 static struct occ_show *occ_show_alloc(struct dl *dl)
3424 {
3425 struct occ_show *occ_show;
3426
3427 occ_show = calloc(1, sizeof(*occ_show));
3428 if (!occ_show)
3429 return NULL;
3430 occ_show->dl = dl;
3431 INIT_LIST_HEAD(&occ_show->port_list);
3432 return occ_show;
3433 }
3434
3435 static void occ_show_free(struct occ_show *occ_show)
3436 {
3437 struct occ_port *occ_port, *tmp;
3438
3439 list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
3440 occ_port_free(occ_port);
3441 }
3442
3443 static struct occ_port *occ_port_get(struct occ_show *occ_show,
3444 struct nlattr **tb)
3445 {
3446 struct occ_port *occ_port;
3447 uint32_t port_index;
3448
3449 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
3450
3451 list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
3452 if (occ_port->port_index == port_index)
3453 return occ_port;
3454 }
3455 occ_port = occ_port_alloc(port_index);
3456 if (!occ_port)
3457 return NULL;
3458 list_add_tail(&occ_port->list, &occ_show->port_list);
3459 return occ_port;
3460 }
3461
3462 static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
3463 bool bound_pool)
3464 {
3465 struct occ_item *occ_item;
3466 int i = 1;
3467
3468 pr_out_sp(7, " %s:", label);
3469 list_for_each_entry(occ_item, list, list) {
3470 if ((i - 1) % 4 == 0 && i != 1)
3471 pr_out_sp(7, " ");
3472 if (bound_pool)
3473 pr_out_sp(7, "%2u(%u):", occ_item->index,
3474 occ_item->bound_pool_index);
3475 else
3476 pr_out_sp(7, "%2u:", occ_item->index);
3477 pr_out_sp(21, "%10u/%u", occ_item->cur, occ_item->max);
3478 if (i++ % 4 == 0)
3479 pr_out("\n");
3480 }
3481 if ((i - 1) % 4 != 0)
3482 pr_out("\n");
3483 }
3484
3485 static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
3486 struct list_head *list,
3487 bool bound_pool)
3488 {
3489 struct occ_item *occ_item;
3490 char buf[32];
3491
3492 jsonw_name(dl->jw, label);
3493 jsonw_start_object(dl->jw);
3494 list_for_each_entry(occ_item, list, list) {
3495 sprintf(buf, "%u", occ_item->index);
3496 jsonw_name(dl->jw, buf);
3497 jsonw_start_object(dl->jw);
3498 if (bound_pool)
3499 jsonw_uint_field(dl->jw, "bound_pool",
3500 occ_item->bound_pool_index);
3501 jsonw_uint_field(dl->jw, "current", occ_item->cur);
3502 jsonw_uint_field(dl->jw, "max", occ_item->max);
3503 jsonw_end_object(dl->jw);
3504 }
3505 jsonw_end_object(dl->jw);
3506 }
3507
3508 static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
3509 {
3510 if (dl->json_output) {
3511 pr_out_json_occ_show_item_list(dl, "pool",
3512 &occ_port->pool_list, false);
3513 pr_out_json_occ_show_item_list(dl, "itc",
3514 &occ_port->ing_tc_list, true);
3515 pr_out_json_occ_show_item_list(dl, "etc",
3516 &occ_port->eg_tc_list, true);
3517 } else {
3518 pr_out("\n");
3519 pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
3520 pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
3521 pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
3522 }
3523 }
3524
3525 static void pr_out_occ_show(struct occ_show *occ_show)
3526 {
3527 struct dl *dl = occ_show->dl;
3528 struct dl_opts *opts = &dl->opts;
3529 struct occ_port *occ_port;
3530
3531 list_for_each_entry(occ_port, &occ_show->port_list, list) {
3532 __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
3533 occ_port->port_index, true, false);
3534 pr_out_occ_show_port(dl, occ_port);
3535 pr_out_port_handle_end(dl);
3536 }
3537 }
3538
3539 static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
3540 struct nlattr **tb)
3541 {
3542 struct occ_port *occ_port;
3543 struct occ_item *occ_item;
3544
3545 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
3546 return;
3547
3548 occ_port = occ_port_get(occ_show, tb);
3549 if (!occ_port) {
3550 occ_show->err = -ENOMEM;
3551 return;
3552 }
3553
3554 occ_item = occ_item_alloc();
3555 if (!occ_item) {
3556 occ_show->err = -ENOMEM;
3557 return;
3558 }
3559 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
3560 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
3561 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
3562 list_add_tail(&occ_item->list, &occ_port->pool_list);
3563 }
3564
3565 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
3566 {
3567 struct occ_show *occ_show = data;
3568 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3569 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3570
3571 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3572 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3573 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3574 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
3575 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
3576 return MNL_CB_ERROR;
3577 cmd_sb_occ_port_pool_process(occ_show, tb);
3578 return MNL_CB_OK;
3579 }
3580
3581 static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
3582 struct nlattr **tb)
3583 {
3584 struct occ_port *occ_port;
3585 struct occ_item *occ_item;
3586 uint8_t pool_type;
3587
3588 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
3589 return;
3590
3591 occ_port = occ_port_get(occ_show, tb);
3592 if (!occ_port) {
3593 occ_show->err = -ENOMEM;
3594 return;
3595 }
3596
3597 occ_item = occ_item_alloc();
3598 if (!occ_item) {
3599 occ_show->err = -ENOMEM;
3600 return;
3601 }
3602 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
3603 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
3604 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
3605 occ_item->bound_pool_index =
3606 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
3607 pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
3608 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
3609 list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
3610 else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
3611 list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
3612 else
3613 occ_item_free(occ_item);
3614 }
3615
3616 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
3617 {
3618 struct occ_show *occ_show = data;
3619 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3620 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3621
3622 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3623 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3624 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3625 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
3626 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
3627 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
3628 return MNL_CB_ERROR;
3629 cmd_sb_occ_tc_pool_process(occ_show, tb);
3630 return MNL_CB_OK;
3631 }
3632
3633 static int cmd_sb_occ_show(struct dl *dl)
3634 {
3635 struct nlmsghdr *nlh;
3636 struct occ_show *occ_show;
3637 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
3638 int err;
3639
3640 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
3641 if (err)
3642 return err;
3643
3644 occ_show = occ_show_alloc(dl);
3645 if (!occ_show)
3646 return -ENOMEM;
3647
3648 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
3649
3650 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
3651 cmd_sb_occ_port_pool_process_cb, occ_show);
3652 if (err)
3653 goto out;
3654
3655 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
3656
3657 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
3658 cmd_sb_occ_tc_pool_process_cb, occ_show);
3659 if (err)
3660 goto out;
3661
3662 pr_out_section_start(dl, "occupancy");
3663 pr_out_occ_show(occ_show);
3664 pr_out_section_end(dl);
3665
3666 out:
3667 occ_show_free(occ_show);
3668 return err;
3669 }
3670
3671 static int cmd_sb_occ_snapshot(struct dl *dl)
3672 {
3673 struct nlmsghdr *nlh;
3674 int err;
3675
3676 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
3677 NLM_F_REQUEST | NLM_F_ACK);
3678
3679 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
3680 if (err)
3681 return err;
3682
3683 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3684 }
3685
3686 static int cmd_sb_occ_clearmax(struct dl *dl)
3687 {
3688 struct nlmsghdr *nlh;
3689 int err;
3690
3691 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
3692 NLM_F_REQUEST | NLM_F_ACK);
3693
3694 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
3695 if (err)
3696 return err;
3697
3698 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3699 }
3700
3701 static int cmd_sb_occ(struct dl *dl)
3702 {
3703 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3704 cmd_sb_help();
3705 return 0;
3706 } else if (dl_argv_match(dl, "show") ||
3707 dl_argv_match(dl, "list")) {
3708 dl_arg_inc(dl);
3709 return cmd_sb_occ_show(dl);
3710 } else if (dl_argv_match(dl, "snapshot")) {
3711 dl_arg_inc(dl);
3712 return cmd_sb_occ_snapshot(dl);
3713 } else if (dl_argv_match(dl, "clearmax")) {
3714 dl_arg_inc(dl);
3715 return cmd_sb_occ_clearmax(dl);
3716 }
3717 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3718 return -ENOENT;
3719 }
3720
3721 static int cmd_sb(struct dl *dl)
3722 {
3723 if (dl_argv_match(dl, "help")) {
3724 cmd_sb_help();
3725 return 0;
3726 } else if (dl_argv_match(dl, "show") ||
3727 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3728 dl_arg_inc(dl);
3729 return cmd_sb_show(dl);
3730 } else if (dl_argv_match(dl, "pool")) {
3731 dl_arg_inc(dl);
3732 return cmd_sb_pool(dl);
3733 } else if (dl_argv_match(dl, "port")) {
3734 dl_arg_inc(dl);
3735 return cmd_sb_port(dl);
3736 } else if (dl_argv_match(dl, "tc")) {
3737 dl_arg_inc(dl);
3738 return cmd_sb_tc(dl);
3739 } else if (dl_argv_match(dl, "occupancy")) {
3740 dl_arg_inc(dl);
3741 return cmd_sb_occ(dl);
3742 }
3743 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3744 return -ENOENT;
3745 }
3746
3747 static const char *cmd_name(uint8_t cmd)
3748 {
3749 switch (cmd) {
3750 case DEVLINK_CMD_UNSPEC: return "unspec";
3751 case DEVLINK_CMD_GET: return "get";
3752 case DEVLINK_CMD_SET: return "set";
3753 case DEVLINK_CMD_NEW: return "new";
3754 case DEVLINK_CMD_DEL: return "del";
3755 case DEVLINK_CMD_PORT_GET: return "get";
3756 case DEVLINK_CMD_PORT_SET: return "set";
3757 case DEVLINK_CMD_PORT_NEW: return "new";
3758 case DEVLINK_CMD_PORT_DEL: return "del";
3759 case DEVLINK_CMD_PARAM_GET: return "get";
3760 case DEVLINK_CMD_PARAM_SET: return "set";
3761 case DEVLINK_CMD_PARAM_NEW: return "new";
3762 case DEVLINK_CMD_PARAM_DEL: return "del";
3763 case DEVLINK_CMD_REGION_GET: return "get";
3764 case DEVLINK_CMD_REGION_SET: return "set";
3765 case DEVLINK_CMD_REGION_NEW: return "new";
3766 case DEVLINK_CMD_REGION_DEL: return "del";
3767 default: return "<unknown cmd>";
3768 }
3769 }
3770
3771 static const char *cmd_obj(uint8_t cmd)
3772 {
3773 switch (cmd) {
3774 case DEVLINK_CMD_UNSPEC: return "unspec";
3775 case DEVLINK_CMD_GET:
3776 case DEVLINK_CMD_SET:
3777 case DEVLINK_CMD_NEW:
3778 case DEVLINK_CMD_DEL:
3779 return "dev";
3780 case DEVLINK_CMD_PORT_GET:
3781 case DEVLINK_CMD_PORT_SET:
3782 case DEVLINK_CMD_PORT_NEW:
3783 case DEVLINK_CMD_PORT_DEL:
3784 return "port";
3785 case DEVLINK_CMD_PARAM_GET:
3786 case DEVLINK_CMD_PARAM_SET:
3787 case DEVLINK_CMD_PARAM_NEW:
3788 case DEVLINK_CMD_PARAM_DEL:
3789 return "param";
3790 case DEVLINK_CMD_REGION_GET:
3791 case DEVLINK_CMD_REGION_SET:
3792 case DEVLINK_CMD_REGION_NEW:
3793 case DEVLINK_CMD_REGION_DEL:
3794 return "region";
3795 default: return "<unknown obj>";
3796 }
3797 }
3798
3799 static void pr_out_mon_header(uint8_t cmd)
3800 {
3801 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
3802 }
3803
3804 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
3805 {
3806 const char *obj = cmd_obj(cmd);
3807 unsigned int index = 0;
3808 const char *cur_obj;
3809
3810 if (dl_no_arg(dl))
3811 return true;
3812 while ((cur_obj = dl_argv_index(dl, index++))) {
3813 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
3814 return true;
3815 }
3816 return false;
3817 }
3818
3819 static void pr_out_region(struct dl *dl, struct nlattr **tb);
3820
3821 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
3822 {
3823 struct dl *dl = data;
3824 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3825 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3826 uint8_t cmd = genl->cmd;
3827
3828 if (!cmd_filter_check(dl, cmd))
3829 return MNL_CB_OK;
3830
3831 switch (cmd) {
3832 case DEVLINK_CMD_GET: /* fall through */
3833 case DEVLINK_CMD_SET: /* fall through */
3834 case DEVLINK_CMD_NEW: /* fall through */
3835 case DEVLINK_CMD_DEL:
3836 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3837 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3838 return MNL_CB_ERROR;
3839 pr_out_mon_header(genl->cmd);
3840 pr_out_dev(dl, tb);
3841 break;
3842 case DEVLINK_CMD_PORT_GET: /* fall through */
3843 case DEVLINK_CMD_PORT_SET: /* fall through */
3844 case DEVLINK_CMD_PORT_NEW: /* fall through */
3845 case DEVLINK_CMD_PORT_DEL:
3846 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3847 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3848 !tb[DEVLINK_ATTR_PORT_INDEX])
3849 return MNL_CB_ERROR;
3850 pr_out_mon_header(genl->cmd);
3851 pr_out_port(dl, tb);
3852 break;
3853 case DEVLINK_CMD_PARAM_GET: /* fall through */
3854 case DEVLINK_CMD_PARAM_SET: /* fall through */
3855 case DEVLINK_CMD_PARAM_NEW: /* fall through */
3856 case DEVLINK_CMD_PARAM_DEL:
3857 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3858 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3859 !tb[DEVLINK_ATTR_PARAM])
3860 return MNL_CB_ERROR;
3861 pr_out_mon_header(genl->cmd);
3862 pr_out_param(dl, tb, false);
3863 break;
3864 case DEVLINK_CMD_REGION_GET: /* fall through */
3865 case DEVLINK_CMD_REGION_SET: /* fall through */
3866 case DEVLINK_CMD_REGION_NEW: /* fall through */
3867 case DEVLINK_CMD_REGION_DEL:
3868 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3869 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3870 !tb[DEVLINK_ATTR_REGION_NAME])
3871 return MNL_CB_ERROR;
3872 pr_out_mon_header(genl->cmd);
3873 pr_out_region(dl, tb);
3874 break;
3875 }
3876 return MNL_CB_OK;
3877 }
3878
3879 static int cmd_mon_show(struct dl *dl)
3880 {
3881 int err;
3882 unsigned int index = 0;
3883 const char *cur_obj;
3884
3885 while ((cur_obj = dl_argv_index(dl, index++))) {
3886 if (strcmp(cur_obj, "all") != 0 &&
3887 strcmp(cur_obj, "dev") != 0 &&
3888 strcmp(cur_obj, "port") != 0) {
3889 pr_err("Unknown object \"%s\"\n", cur_obj);
3890 return -EINVAL;
3891 }
3892 }
3893 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
3894 if (err)
3895 return err;
3896 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
3897 if (err)
3898 return err;
3899 return 0;
3900 }
3901
3902 static void cmd_mon_help(void)
3903 {
3904 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
3905 "where OBJECT-LIST := { dev | port }\n");
3906 }
3907
3908 static int cmd_mon(struct dl *dl)
3909 {
3910 if (dl_argv_match(dl, "help")) {
3911 cmd_mon_help();
3912 return 0;
3913 }
3914 return cmd_mon_show(dl);
3915 }
3916
3917 struct dpipe_field {
3918 char *name;
3919 unsigned int id;
3920 unsigned int bitwidth;
3921 enum devlink_dpipe_field_mapping_type mapping_type;
3922 };
3923
3924 struct dpipe_header {
3925 struct list_head list;
3926 char *name;
3927 unsigned int id;
3928 struct dpipe_field *fields;
3929 unsigned int fields_count;
3930 };
3931
3932 struct dpipe_table {
3933 struct list_head list;
3934 char *name;
3935 unsigned int resource_id;
3936 bool resource_valid;
3937 };
3938
3939 struct dpipe_tables {
3940 struct list_head table_list;
3941 };
3942
3943 struct resource {
3944 char *name;
3945 uint64_t size;
3946 uint64_t size_new;
3947 uint64_t size_min;
3948 uint64_t size_max;
3949 uint64_t size_gran;
3950 enum devlink_resource_unit unit;
3951 bool size_valid;
3952 uint64_t size_occ;
3953 bool occ_valid;
3954 uint64_t id;
3955 struct list_head list;
3956 struct list_head resource_list;
3957 struct resource *parent;
3958 };
3959
3960 struct resources {
3961 struct list_head resource_list;
3962 };
3963
3964 struct resource_ctx {
3965 struct dl *dl;
3966 int err;
3967 struct resources *resources;
3968 struct dpipe_tables *tables;
3969 bool print_resources;
3970 bool pending_change;
3971 };
3972
3973 static struct resource *resource_alloc(void)
3974 {
3975 struct resource *resource;
3976
3977 resource = calloc(1, sizeof(struct resource));
3978 if (!resource)
3979 return NULL;
3980 INIT_LIST_HEAD(&resource->resource_list);
3981 return resource;
3982 }
3983
3984 static void resource_free(struct resource *resource)
3985 {
3986 struct resource *child_resource, *tmp;
3987
3988 list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
3989 list) {
3990 free(child_resource->name);
3991 resource_free(child_resource);
3992 }
3993 free(resource);
3994 }
3995
3996 static struct resources *resources_alloc(void)
3997 {
3998 struct resources *resources;
3999
4000 resources = calloc(1, sizeof(struct resources));
4001 if (!resources)
4002 return NULL;
4003 INIT_LIST_HEAD(&resources->resource_list);
4004 return resources;
4005 }
4006
4007 static void resources_free(struct resources *resources)
4008 {
4009 struct resource *resource, *tmp;
4010
4011 list_for_each_entry_safe(resource, tmp, &resources->resource_list, list)
4012 resource_free(resource);
4013 }
4014
4015 static int resource_ctx_init(struct resource_ctx *ctx, struct dl *dl)
4016 {
4017 ctx->resources = resources_alloc();
4018 if (!ctx->resources)
4019 return -ENOMEM;
4020 ctx->dl = dl;
4021 return 0;
4022 }
4023
4024 static void resource_ctx_fini(struct resource_ctx *ctx)
4025 {
4026 resources_free(ctx->resources);
4027 }
4028
4029 struct dpipe_ctx {
4030 struct dl *dl;
4031 int err;
4032 struct list_head global_headers;
4033 struct list_head local_headers;
4034 struct dpipe_tables *tables;
4035 struct resources *resources;
4036 bool print_headers;
4037 bool print_tables;
4038 };
4039
4040 static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
4041 {
4042 struct dpipe_header *header;
4043
4044 header = calloc(1, sizeof(struct dpipe_header));
4045 if (!header)
4046 return NULL;
4047 header->fields = calloc(fields_count, sizeof(struct dpipe_field));
4048 if (!header->fields)
4049 goto err_fields_alloc;
4050 header->fields_count = fields_count;
4051 return header;
4052
4053 err_fields_alloc:
4054 free(header);
4055 return NULL;
4056 }
4057
4058 static void dpipe_header_free(struct dpipe_header *header)
4059 {
4060 free(header->fields);
4061 free(header);
4062 }
4063
4064 static void dpipe_header_clear(struct dpipe_header *header)
4065 {
4066 struct dpipe_field *field;
4067 int i;
4068
4069 for (i = 0; i < header->fields_count; i++) {
4070 field = &header->fields[i];
4071 free(field->name);
4072 }
4073 free(header->name);
4074 }
4075
4076 static void dpipe_header_add(struct dpipe_ctx *ctx,
4077 struct dpipe_header *header, bool global)
4078 {
4079 if (global)
4080 list_add(&header->list, &ctx->global_headers);
4081 else
4082 list_add(&header->list, &ctx->local_headers);
4083 }
4084
4085 static void dpipe_header_del(struct dpipe_header *header)
4086 {
4087 list_del(&header->list);
4088 }
4089
4090 static struct dpipe_table *dpipe_table_alloc(void)
4091 {
4092 return calloc(1, sizeof(struct dpipe_table));
4093 }
4094
4095 static void dpipe_table_free(struct dpipe_table *table)
4096 {
4097 free(table);
4098 }
4099
4100 static struct dpipe_tables *dpipe_tables_alloc(void)
4101 {
4102 struct dpipe_tables *tables;
4103
4104 tables = calloc(1, sizeof(struct dpipe_tables));
4105 if (!tables)
4106 return NULL;
4107 INIT_LIST_HEAD(&tables->table_list);
4108 return tables;
4109 }
4110
4111 static void dpipe_tables_free(struct dpipe_tables *tables)
4112 {
4113 struct dpipe_table *table, *tmp;
4114
4115 list_for_each_entry_safe(table, tmp, &tables->table_list, list)
4116 dpipe_table_free(table);
4117 free(tables);
4118 }
4119
4120 static int dpipe_ctx_init(struct dpipe_ctx *ctx, struct dl *dl)
4121 {
4122 ctx->tables = dpipe_tables_alloc();
4123 if (!ctx->tables)
4124 return -ENOMEM;
4125
4126 ctx->dl = dl;
4127 INIT_LIST_HEAD(&ctx->global_headers);
4128 INIT_LIST_HEAD(&ctx->local_headers);
4129 return 0;
4130 }
4131
4132 static void dpipe_ctx_fini(struct dpipe_ctx *ctx)
4133 {
4134 struct dpipe_header *header, *tmp;
4135
4136 list_for_each_entry_safe(header, tmp, &ctx->global_headers,
4137 list) {
4138 dpipe_header_del(header);
4139 dpipe_header_clear(header);
4140 dpipe_header_free(header);
4141 }
4142 list_for_each_entry_safe(header, tmp, &ctx->local_headers,
4143 list) {
4144 dpipe_header_del(header);
4145 dpipe_header_clear(header);
4146 dpipe_header_free(header);
4147 }
4148 dpipe_tables_free(ctx->tables);
4149 }
4150
4151 static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
4152 uint32_t header_id, bool global)
4153 {
4154 struct list_head *header_list;
4155 struct dpipe_header *header;
4156
4157 if (global)
4158 header_list = &ctx->global_headers;
4159 else
4160 header_list = &ctx->local_headers;
4161 list_for_each_entry(header, header_list, list) {
4162 if (header->id != header_id)
4163 continue;
4164 return header->name;
4165 }
4166 return NULL;
4167 }
4168
4169 static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
4170 uint32_t header_id,
4171 uint32_t field_id, bool global)
4172 {
4173 struct list_head *header_list;
4174 struct dpipe_header *header;
4175
4176 if (global)
4177 header_list = &ctx->global_headers;
4178 else
4179 header_list = &ctx->local_headers;
4180 list_for_each_entry(header, header_list, list) {
4181 if (header->id != header_id)
4182 continue;
4183 return header->fields[field_id].name;
4184 }
4185 return NULL;
4186 }
4187
4188 static const char *
4189 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
4190 {
4191 switch (mapping_type) {
4192 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
4193 return NULL;
4194 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
4195 return "ifindex";
4196 default:
4197 return "<unknown>";
4198 }
4199 }
4200
4201 static const char *
4202 dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
4203 uint32_t field_id, bool global)
4204 {
4205 enum devlink_dpipe_field_mapping_type mapping_type;
4206 struct list_head *header_list;
4207 struct dpipe_header *header;
4208
4209 if (global)
4210 header_list = &ctx->global_headers;
4211 else
4212 header_list = &ctx->local_headers;
4213 list_for_each_entry(header, header_list, list) {
4214 if (header->id != header_id)
4215 continue;
4216 mapping_type = header->fields[field_id].mapping_type;
4217 return dpipe_field_mapping_e2s(mapping_type);
4218 }
4219 return NULL;
4220 }
4221
4222 static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
4223 struct dpipe_field *fields,
4224 unsigned int field_count)
4225 {
4226 struct dpipe_field *field;
4227 int i;
4228
4229 for (i = 0; i < field_count; i++) {
4230 field = &fields[i];
4231 pr_out_entry_start(ctx->dl);
4232 pr_out_str(ctx->dl, "name", field->name);
4233 if (ctx->dl->verbose)
4234 pr_out_uint(ctx->dl, "id", field->id);
4235 pr_out_uint(ctx->dl, "bitwidth", field->bitwidth);
4236 if (field->mapping_type)
4237 pr_out_str(ctx->dl, "mapping_type",
4238 dpipe_field_mapping_e2s(field->mapping_type));
4239 pr_out_entry_end(ctx->dl);
4240 }
4241 }
4242
4243 static void
4244 pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
4245 struct dpipe_header *header, bool global)
4246 {
4247 pr_out_handle_start_arr(ctx->dl, tb);
4248 pr_out_str(ctx->dl, "name", header->name);
4249 if (ctx->dl->verbose) {
4250 pr_out_uint(ctx->dl, "id", header->id);
4251 pr_out_str(ctx->dl, "global",
4252 global ? "true" : "false");
4253 }
4254 pr_out_array_start(ctx->dl, "field");
4255 pr_out_dpipe_fields(ctx, header->fields,
4256 header->fields_count);
4257 pr_out_array_end(ctx->dl);
4258 pr_out_handle_end(ctx->dl);
4259 }
4260
4261 static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
4262 struct nlattr **tb)
4263 {
4264 struct dpipe_header *header;
4265
4266 list_for_each_entry(header, &ctx->local_headers, list)
4267 pr_out_dpipe_header(ctx, tb, header, false);
4268
4269 list_for_each_entry(header, &ctx->global_headers, list)
4270 pr_out_dpipe_header(ctx, tb, header, true);
4271 }
4272
4273 static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
4274 {
4275 struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
4276 const char *name;
4277 int err;
4278
4279 err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
4280 if (err != MNL_CB_OK)
4281 return -EINVAL;
4282 if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
4283 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
4284 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
4285 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
4286 return -EINVAL;
4287
4288 name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
4289 field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
4290 field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
4291 field->name = strdup(name);
4292 if (!field->name)
4293 return -ENOMEM;
4294 field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
4295 return 0;
4296 }
4297
4298 static int dpipe_header_fields_get(struct nlattr *nla_fields,
4299 struct dpipe_field *fields)
4300 {
4301 struct nlattr *nla_field;
4302 int count = 0;
4303 int err;
4304
4305 mnl_attr_for_each_nested(nla_field, nla_fields) {
4306 err = dpipe_header_field_get(nla_field, &fields[count]);
4307 if (err)
4308 return err;
4309 count++;
4310 }
4311 return 0;
4312 }
4313
4314 static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
4315 {
4316 struct nlattr *nla_field;
4317 unsigned int count = 0;
4318
4319 mnl_attr_for_each_nested(nla_field, nla_fields)
4320 count++;
4321 return count;
4322 }
4323
4324 static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
4325 {
4326 struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
4327 struct dpipe_header *header;
4328 unsigned int fields_count;
4329 const char *header_name;
4330 bool global;
4331 int err;
4332
4333 err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
4334 if (err != MNL_CB_OK)
4335 return -EINVAL;
4336
4337 if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
4338 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
4339 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
4340 return -EINVAL;
4341
4342 fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
4343 header = dpipe_header_alloc(fields_count);
4344 if (!header)
4345 return -ENOMEM;
4346
4347 header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
4348 header->name = strdup(header_name);
4349 header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
4350 header->fields_count = fields_count;
4351 global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
4352
4353 err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
4354 header->fields);
4355 if (err)
4356 goto err_field_get;
4357 dpipe_header_add(ctx, header, global);
4358 return 0;
4359
4360 err_field_get:
4361 dpipe_header_free(header);
4362 return err;
4363 }
4364
4365 static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
4366 {
4367 struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
4368 struct nlattr *nla_header;
4369 int err;
4370
4371 mnl_attr_for_each_nested(nla_header, nla_headers) {
4372 err = dpipe_header_get(ctx, nla_header);
4373 if (err)
4374 return err;
4375 }
4376 return 0;
4377 }
4378
4379 static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
4380 {
4381 struct dpipe_ctx *ctx = data;
4382 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4383 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4384 int err;
4385
4386 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4387 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4388 !tb[DEVLINK_ATTR_DPIPE_HEADERS])
4389 return MNL_CB_ERROR;
4390 err = dpipe_headers_get(ctx, tb);
4391 if (err) {
4392 ctx->err = err;
4393 return MNL_CB_ERROR;
4394 }
4395
4396 if (ctx->print_headers)
4397 pr_out_dpipe_headers(ctx, tb);
4398 return MNL_CB_OK;
4399 }
4400
4401 static int cmd_dpipe_headers_show(struct dl *dl)
4402 {
4403 struct nlmsghdr *nlh;
4404 struct dpipe_ctx ctx = {};
4405 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4406 int err;
4407
4408 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
4409
4410 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
4411 if (err)
4412 return err;
4413
4414 err = dpipe_ctx_init(&ctx, dl);
4415 if (err)
4416 return err;
4417
4418 ctx.print_headers = true;
4419
4420 pr_out_section_start(dl, "header");
4421 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
4422 if (err)
4423 pr_err("error get headers %s\n", strerror(ctx.err));
4424 pr_out_section_end(dl);
4425
4426 dpipe_ctx_fini(&ctx);
4427 return err;
4428 }
4429
4430 static void cmd_dpipe_header_help(void)
4431 {
4432 pr_err("Usage: devlink dpipe headers show DEV\n");
4433 }
4434
4435 static int cmd_dpipe_header(struct dl *dl)
4436 {
4437 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4438 cmd_dpipe_header_help();
4439 return 0;
4440 } else if (dl_argv_match(dl, "show")) {
4441 dl_arg_inc(dl);
4442 return cmd_dpipe_headers_show(dl);
4443 }
4444 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4445 return -ENOENT;
4446 }
4447
4448 static const char
4449 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
4450 {
4451 switch (action_type) {
4452 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
4453 return "field_modify";
4454 default:
4455 return "<unknown>";
4456 }
4457 }
4458
4459 struct dpipe_op_info {
4460 uint32_t header_id;
4461 uint32_t field_id;
4462 bool header_global;
4463 };
4464
4465 struct dpipe_action {
4466 struct dpipe_op_info info;
4467 uint32_t type;
4468 };
4469
4470 static void pr_out_dpipe_action(struct dpipe_action *action,
4471 struct dpipe_ctx *ctx)
4472 {
4473 struct dpipe_op_info *op_info = &action->info;
4474 const char *mapping;
4475
4476 pr_out_str(ctx->dl, "type",
4477 dpipe_action_type_e2s(action->type));
4478 pr_out_str(ctx->dl, "header",
4479 dpipe_header_id2s(ctx, op_info->header_id,
4480 op_info->header_global));
4481 pr_out_str(ctx->dl, "field",
4482 dpipe_field_id2s(ctx, op_info->header_id,
4483 op_info->field_id,
4484 op_info->header_global));
4485 mapping = dpipe_mapping_get(ctx, op_info->header_id,
4486 op_info->field_id,
4487 op_info->header_global);
4488 if (mapping)
4489 pr_out_str(ctx->dl, "mapping", mapping);
4490 }
4491
4492 static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
4493 {
4494 struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
4495 int err;
4496
4497 err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
4498 if (err != MNL_CB_OK)
4499 return -EINVAL;
4500
4501 if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
4502 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
4503 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
4504 !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
4505 return -EINVAL;
4506 }
4507
4508 action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
4509 action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
4510 action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
4511 action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
4512
4513 return 0;
4514 }
4515
4516 static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
4517 struct nlattr *nla_actions)
4518 {
4519 struct nlattr *nla_action;
4520 struct dpipe_action action;
4521
4522 mnl_attr_for_each_nested(nla_action, nla_actions) {
4523 pr_out_entry_start(ctx->dl);
4524 if (dpipe_action_parse(&action, nla_action))
4525 goto err_action_parse;
4526 pr_out_dpipe_action(&action, ctx);
4527 pr_out_entry_end(ctx->dl);
4528 }
4529 return 0;
4530
4531 err_action_parse:
4532 pr_out_entry_end(ctx->dl);
4533 return -EINVAL;
4534 }
4535
4536 static const char *
4537 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
4538 {
4539 switch (match_type) {
4540 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
4541 return "field_exact";
4542 default:
4543 return "<unknown>";
4544 }
4545 }
4546
4547 struct dpipe_match {
4548 struct dpipe_op_info info;
4549 uint32_t type;
4550 };
4551
4552 static void pr_out_dpipe_match(struct dpipe_match *match,
4553 struct dpipe_ctx *ctx)
4554 {
4555 struct dpipe_op_info *op_info = &match->info;
4556 const char *mapping;
4557
4558 pr_out_str(ctx->dl, "type",
4559 dpipe_match_type_e2s(match->type));
4560 pr_out_str(ctx->dl, "header",
4561 dpipe_header_id2s(ctx, op_info->header_id,
4562 op_info->header_global));
4563 pr_out_str(ctx->dl, "field",
4564 dpipe_field_id2s(ctx, op_info->header_id,
4565 op_info->field_id,
4566 op_info->header_global));
4567 mapping = dpipe_mapping_get(ctx, op_info->header_id,
4568 op_info->field_id,
4569 op_info->header_global);
4570 if (mapping)
4571 pr_out_str(ctx->dl, "mapping", mapping);
4572 }
4573
4574 static int dpipe_match_parse(struct dpipe_match *match,
4575 struct nlattr *nl)
4576
4577 {
4578 struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
4579 int err;
4580
4581 err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
4582 if (err != MNL_CB_OK)
4583 return -EINVAL;
4584
4585 if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
4586 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
4587 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
4588 !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
4589 return -EINVAL;
4590 }
4591
4592 match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
4593 match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
4594 match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
4595 match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
4596
4597 return 0;
4598 }
4599
4600 static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
4601 struct nlattr *nla_matches)
4602 {
4603 struct nlattr *nla_match;
4604 struct dpipe_match match;
4605
4606 mnl_attr_for_each_nested(nla_match, nla_matches) {
4607 pr_out_entry_start(ctx->dl);
4608 if (dpipe_match_parse(&match, nla_match))
4609 goto err_match_parse;
4610 pr_out_dpipe_match(&match, ctx);
4611 pr_out_entry_end(ctx->dl);
4612 }
4613 return 0;
4614
4615 err_match_parse:
4616 pr_out_entry_end(ctx->dl);
4617 return -EINVAL;
4618 }
4619
4620 static struct resource *
4621 resource_find(struct resources *resources, struct resource *resource,
4622 uint64_t resource_id)
4623 {
4624 struct list_head *list_head;
4625
4626 if (!resource)
4627 list_head = &resources->resource_list;
4628 else
4629 list_head = &resource->resource_list;
4630
4631 list_for_each_entry(resource, list_head, list) {
4632 struct resource *child_resource;
4633
4634 if (resource->id == resource_id)
4635 return resource;
4636
4637 child_resource = resource_find(resources, resource,
4638 resource_id);
4639 if (child_resource)
4640 return child_resource;
4641 }
4642 return NULL;
4643 }
4644
4645 static void
4646 resource_path_print(struct dl *dl, struct resources *resources,
4647 uint64_t resource_id)
4648 {
4649 struct resource *resource, *parent_resource;
4650 const char del[] = "/";
4651 int path_len = 0;
4652 char *path;
4653
4654 resource = resource_find(resources, NULL, resource_id);
4655 if (!resource)
4656 return;
4657
4658 for (parent_resource = resource; parent_resource;
4659 parent_resource = parent_resource->parent)
4660 path_len += strlen(parent_resource->name) + 1;
4661
4662 path_len++;
4663 path = calloc(1, path_len);
4664 if (!path)
4665 return;
4666
4667 path += path_len - 1;
4668 for (parent_resource = resource; parent_resource;
4669 parent_resource = parent_resource->parent) {
4670 path -= strlen(parent_resource->name);
4671 memcpy(path, parent_resource->name,
4672 strlen(parent_resource->name));
4673 path -= strlen(del);
4674 memcpy(path, del, strlen(del));
4675 }
4676 pr_out_str(dl, "resource_path", path);
4677 free(path);
4678 }
4679
4680 static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
4681 {
4682 struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
4683 struct dpipe_table *table;
4684 uint32_t resource_units;
4685 bool counters_enabled;
4686 bool resource_valid;
4687 uint32_t size;
4688 int err;
4689
4690 err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
4691 if (err != MNL_CB_OK)
4692 return -EINVAL;
4693
4694 if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
4695 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
4696 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
4697 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
4698 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
4699 return -EINVAL;
4700 }
4701
4702 table = dpipe_table_alloc();
4703 if (!table)
4704 return -ENOMEM;
4705
4706 table->name = strdup(mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]));
4707 size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
4708 counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
4709
4710 resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
4711 ctx->resources;
4712 if (resource_valid) {
4713 table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
4714 table->resource_valid = true;
4715 }
4716
4717 list_add_tail(&table->list, &ctx->tables->table_list);
4718 if (!ctx->print_tables)
4719 return 0;
4720
4721 pr_out_str(ctx->dl, "name", table->name);
4722 pr_out_uint(ctx->dl, "size", size);
4723 pr_out_str(ctx->dl, "counters_enabled",
4724 counters_enabled ? "true" : "false");
4725
4726 if (resource_valid) {
4727 resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
4728 resource_path_print(ctx->dl, ctx->resources,
4729 table->resource_id);
4730 pr_out_uint(ctx->dl, "resource_units", resource_units);
4731 }
4732
4733 pr_out_array_start(ctx->dl, "match");
4734 if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
4735 goto err_matches_show;
4736 pr_out_array_end(ctx->dl);
4737
4738 pr_out_array_start(ctx->dl, "action");
4739 if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
4740 goto err_actions_show;
4741 pr_out_array_end(ctx->dl);
4742
4743 return 0;
4744
4745 err_actions_show:
4746 err_matches_show:
4747 pr_out_array_end(ctx->dl);
4748 return -EINVAL;
4749 }
4750
4751 static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
4752 {
4753 struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
4754 struct nlattr *nla_table;
4755
4756 mnl_attr_for_each_nested(nla_table, nla_tables) {
4757 if (ctx->print_tables)
4758 pr_out_handle_start_arr(ctx->dl, tb);
4759 if (dpipe_table_show(ctx, nla_table))
4760 goto err_table_show;
4761 if (ctx->print_tables)
4762 pr_out_handle_end(ctx->dl);
4763 }
4764 return 0;
4765
4766 err_table_show:
4767 if (ctx->print_tables)
4768 pr_out_handle_end(ctx->dl);
4769 return -EINVAL;
4770 }
4771
4772 static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
4773 {
4774 struct dpipe_ctx *ctx = data;
4775 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4776 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4777
4778 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4779 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4780 !tb[DEVLINK_ATTR_DPIPE_TABLES])
4781 return MNL_CB_ERROR;
4782
4783 if (dpipe_tables_show(ctx, tb))
4784 return MNL_CB_ERROR;
4785 return MNL_CB_OK;
4786 }
4787
4788 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data);
4789
4790 static int cmd_dpipe_table_show(struct dl *dl)
4791 {
4792 struct nlmsghdr *nlh;
4793 struct dpipe_ctx dpipe_ctx = {};
4794 struct resource_ctx resource_ctx = {};
4795 uint16_t flags = NLM_F_REQUEST;
4796 int err;
4797
4798 err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
4799 if (err)
4800 return err;
4801
4802 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
4803
4804 err = dpipe_ctx_init(&dpipe_ctx, dl);
4805 if (err)
4806 return err;
4807
4808 dpipe_ctx.print_tables = true;
4809
4810 dl_opts_put(nlh, dl);
4811 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb,
4812 &dpipe_ctx);
4813 if (err) {
4814 pr_err("error get headers %s\n", strerror(dpipe_ctx.err));
4815 goto err_headers_get;
4816 }
4817
4818 err = resource_ctx_init(&resource_ctx, dl);
4819 if (err)
4820 goto err_resource_ctx_init;
4821
4822 resource_ctx.print_resources = false;
4823 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags);
4824 dl_opts_put(nlh, dl);
4825 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
4826 &resource_ctx);
4827 if (!err)
4828 dpipe_ctx.resources = resource_ctx.resources;
4829
4830 flags = NLM_F_REQUEST | NLM_F_ACK;
4831 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
4832 dl_opts_put(nlh, dl);
4833
4834 pr_out_section_start(dl, "table");
4835 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx);
4836 pr_out_section_end(dl);
4837
4838 resource_ctx_fini(&resource_ctx);
4839 dpipe_ctx_fini(&dpipe_ctx);
4840 return 0;
4841
4842 err_resource_ctx_init:
4843 err_headers_get:
4844 dpipe_ctx_fini(&dpipe_ctx);
4845 return err;
4846 }
4847
4848 static int cmd_dpipe_table_set(struct dl *dl)
4849 {
4850 struct nlmsghdr *nlh;
4851 int err;
4852
4853 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
4854 NLM_F_REQUEST | NLM_F_ACK);
4855
4856 err = dl_argv_parse_put(nlh, dl,
4857 DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
4858 DL_OPT_DPIPE_TABLE_COUNTERS, 0);
4859 if (err)
4860 return err;
4861
4862 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4863 }
4864
4865 enum dpipe_value_type {
4866 DPIPE_VALUE_TYPE_VALUE,
4867 DPIPE_VALUE_TYPE_MASK,
4868 };
4869
4870 static const char *
4871 dpipe_value_type_e2s(enum dpipe_value_type type)
4872 {
4873 switch (type) {
4874 case DPIPE_VALUE_TYPE_VALUE:
4875 return "value";
4876 case DPIPE_VALUE_TYPE_MASK:
4877 return "value_mask";
4878 default:
4879 return "<unknown>";
4880 }
4881 }
4882
4883 struct dpipe_field_printer {
4884 unsigned int field_id;
4885 void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
4886 };
4887
4888 struct dpipe_header_printer {
4889 struct dpipe_field_printer *printers;
4890 unsigned int printers_count;
4891 unsigned int header_id;
4892 };
4893
4894 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
4895 enum dpipe_value_type type,
4896 void *value)
4897 {
4898 struct in_addr ip_addr;
4899
4900 ip_addr.s_addr = htonl(*(uint32_t *)value);
4901 pr_out_str(ctx->dl, dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
4902 }
4903
4904 static void
4905 dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
4906 enum dpipe_value_type type,
4907 void *value)
4908 {
4909 pr_out_str(ctx->dl, dpipe_value_type_e2s(type),
4910 ether_ntoa((struct ether_addr *)value));
4911 }
4912
4913 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
4914 enum dpipe_value_type type,
4915 void *value)
4916 {
4917 char str[INET6_ADDRSTRLEN];
4918
4919 inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
4920 pr_out_str(ctx->dl, dpipe_value_type_e2s(type), str);
4921 }
4922
4923 static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
4924 {
4925 .printer = dpipe_field_printer_ipv4_addr,
4926 .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
4927 }
4928 };
4929
4930 static struct dpipe_header_printer dpipe_header_printer_ipv4 = {
4931 .printers = dpipe_field_printers_ipv4,
4932 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
4933 .header_id = DEVLINK_DPIPE_HEADER_IPV4,
4934 };
4935
4936 static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
4937 {
4938 .printer = dpipe_field_printer_ethernet_addr,
4939 .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
4940 },
4941 };
4942
4943 static struct dpipe_header_printer dpipe_header_printer_ethernet = {
4944 .printers = dpipe_field_printers_ethernet,
4945 .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
4946 .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
4947 };
4948
4949 static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
4950 {
4951 .printer = dpipe_field_printer_ipv6_addr,
4952 .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
4953 }
4954 };
4955
4956 static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
4957 .printers = dpipe_field_printers_ipv6,
4958 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
4959 .header_id = DEVLINK_DPIPE_HEADER_IPV6,
4960 };
4961
4962 static struct dpipe_header_printer *dpipe_header_printers[] = {
4963 &dpipe_header_printer_ipv4,
4964 &dpipe_header_printer_ethernet,
4965 &dpipe_header_printer_ipv6,
4966 };
4967
4968 static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
4969 struct dpipe_op_info *info,
4970 enum dpipe_value_type type,
4971 void *value)
4972 {
4973 unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
4974 struct dpipe_header_printer *header_printer;
4975 struct dpipe_field_printer *field_printer;
4976 unsigned int field_printers_count;
4977 int j;
4978 int i;
4979
4980 for (i = 0; i < header_printers_count; i++) {
4981 header_printer = dpipe_header_printers[i];
4982 if (header_printer->header_id != info->header_id)
4983 continue;
4984 field_printers_count = header_printer->printers_count;
4985 for (j = 0; j < field_printers_count; j++) {
4986 field_printer = &header_printer->printers[j];
4987 if (field_printer->field_id != info->field_id)
4988 continue;
4989 field_printer->printer(ctx, type, value);
4990 return 0;
4991 }
4992 }
4993
4994 return -EINVAL;
4995 }
4996
4997 static void __pr_out_entry_value(struct dpipe_ctx *ctx,
4998 void *value,
4999 unsigned int value_len,
5000 struct dpipe_op_info *info,
5001 enum dpipe_value_type type)
5002 {
5003 if (info->header_global &&
5004 !dpipe_print_prot_header(ctx, info, type, value))
5005 return;
5006
5007 if (value_len == sizeof(uint32_t)) {
5008 uint32_t *value_32 = value;
5009
5010 pr_out_uint(ctx->dl, dpipe_value_type_e2s(type), *value_32);
5011 }
5012 }
5013
5014 static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
5015 struct nlattr **nla_match_value,
5016 struct dpipe_op_info *info)
5017 {
5018 void *value, *value_mask;
5019 uint32_t value_mapping;
5020 uint16_t value_len;
5021 bool mask, mapping;
5022
5023 mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
5024 mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
5025
5026 value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
5027 value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
5028
5029 if (mapping) {
5030 value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
5031 pr_out_uint(ctx->dl, "mapping_value", value_mapping);
5032 }
5033
5034 if (mask) {
5035 value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
5036 __pr_out_entry_value(ctx, value_mask, value_len, info,
5037 DPIPE_VALUE_TYPE_MASK);
5038 }
5039
5040 __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
5041 }
5042
5043 static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
5044 struct nlattr *nl)
5045 {
5046 struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
5047 struct dpipe_match match;
5048 int err;
5049
5050 err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
5051 if (err != MNL_CB_OK)
5052 return -EINVAL;
5053
5054 if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
5055 !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
5056 return -EINVAL;
5057 }
5058
5059 pr_out_entry_start(ctx->dl);
5060 if (dpipe_match_parse(&match,
5061 nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
5062 goto err_match_parse;
5063 pr_out_dpipe_match(&match, ctx);
5064 pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
5065 pr_out_entry_end(ctx->dl);
5066
5067 return 0;
5068
5069 err_match_parse:
5070 pr_out_entry_end(ctx->dl);
5071 return -EINVAL;
5072 }
5073
5074 static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
5075 struct nlattr *nl)
5076 {
5077 struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
5078 struct dpipe_action action;
5079 int err;
5080
5081 err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
5082 if (err != MNL_CB_OK)
5083 return -EINVAL;
5084
5085 if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
5086 !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
5087 return -EINVAL;
5088 }
5089
5090 pr_out_entry_start(ctx->dl);
5091 if (dpipe_action_parse(&action,
5092 nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
5093 goto err_action_parse;
5094 pr_out_dpipe_action(&action, ctx);
5095 pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
5096 pr_out_entry_end(ctx->dl);
5097
5098 return 0;
5099
5100 err_action_parse:
5101 pr_out_entry_end(ctx->dl);
5102 return -EINVAL;
5103 }
5104
5105 static int
5106 dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
5107 struct nlattr *nla_action_values)
5108 {
5109 struct nlattr *nla_action_value;
5110
5111 mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
5112 if (dpipe_entry_action_value_show(ctx, nla_action_value))
5113 return -EINVAL;
5114 }
5115 return 0;
5116 }
5117
5118 static int
5119 dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
5120 struct nlattr *nla_match_values)
5121 {
5122 struct nlattr *nla_match_value;
5123
5124 mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
5125 if (dpipe_entry_match_value_show(ctx, nla_match_value))
5126 return -EINVAL;
5127 }
5128 return 0;
5129 }
5130
5131 static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
5132 {
5133 struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
5134 uint32_t entry_index;
5135 uint64_t counter;
5136 int err;
5137
5138 err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
5139 if (err != MNL_CB_OK)
5140 return -EINVAL;
5141
5142 if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
5143 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
5144 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
5145 return -EINVAL;
5146 }
5147
5148 entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
5149 pr_out_uint(ctx->dl, "index", entry_index);
5150
5151 if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
5152 counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
5153 pr_out_uint(ctx->dl, "counter", counter);
5154 }
5155
5156 pr_out_array_start(ctx->dl, "match_value");
5157 if (dpipe_tables_match_values_show(ctx,
5158 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
5159 goto err_match_values_show;
5160 pr_out_array_end(ctx->dl);
5161
5162 pr_out_array_start(ctx->dl, "action_value");
5163 if (dpipe_tables_action_values_show(ctx,
5164 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
5165 goto err_action_values_show;
5166 pr_out_array_end(ctx->dl);
5167 return 0;
5168
5169 err_action_values_show:
5170 err_match_values_show:
5171 pr_out_array_end(ctx->dl);
5172 return -EINVAL;
5173 }
5174
5175 static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
5176 {
5177 struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
5178 struct nlattr *nla_entry;
5179
5180 mnl_attr_for_each_nested(nla_entry, nla_entries) {
5181 pr_out_handle_start_arr(ctx->dl, tb);
5182 if (dpipe_entry_show(ctx, nla_entry))
5183 goto err_entry_show;
5184 pr_out_handle_end(ctx->dl);
5185 }
5186 return 0;
5187
5188 err_entry_show:
5189 pr_out_handle_end(ctx->dl);
5190 return -EINVAL;
5191 }
5192
5193 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
5194 {
5195 struct dpipe_ctx *ctx = data;
5196 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5197 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5198
5199 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5200 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5201 !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
5202 return MNL_CB_ERROR;
5203
5204 if (dpipe_table_entries_show(ctx, tb))
5205 return MNL_CB_ERROR;
5206 return MNL_CB_OK;
5207 }
5208
5209 static int cmd_dpipe_table_dump(struct dl *dl)
5210 {
5211 struct nlmsghdr *nlh;
5212 struct dpipe_ctx ctx = {};
5213 uint16_t flags = NLM_F_REQUEST;
5214 int err;
5215
5216 err = dpipe_ctx_init(&ctx, dl);
5217 if (err)
5218 return err;
5219
5220 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
5221 if (err)
5222 goto out;
5223
5224 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
5225 dl_opts_put(nlh, dl);
5226 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
5227 if (err) {
5228 pr_err("error get headers %s\n", strerror(ctx.err));
5229 goto out;
5230 }
5231
5232 flags = NLM_F_REQUEST | NLM_F_ACK;
5233 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
5234 dl_opts_put(nlh, dl);
5235
5236 pr_out_section_start(dl, "table_entry");
5237 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx);
5238 pr_out_section_end(dl);
5239 out:
5240 dpipe_ctx_fini(&ctx);
5241 return err;
5242 }
5243
5244 static void cmd_dpipe_table_help(void)
5245 {
5246 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
5247 "where OBJECT-LIST := { show | set | dump }\n");
5248 }
5249
5250 static int cmd_dpipe_table(struct dl *dl)
5251 {
5252 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5253 cmd_dpipe_table_help();
5254 return 0;
5255 } else if (dl_argv_match(dl, "show")) {
5256 dl_arg_inc(dl);
5257 return cmd_dpipe_table_show(dl);
5258 } else if (dl_argv_match(dl, "set")) {
5259 dl_arg_inc(dl);
5260 return cmd_dpipe_table_set(dl);
5261 } else if (dl_argv_match(dl, "dump")) {
5262 dl_arg_inc(dl);
5263 return cmd_dpipe_table_dump(dl);
5264 }
5265 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5266 return -ENOENT;
5267 }
5268
5269 static void cmd_dpipe_help(void)
5270 {
5271 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
5272 "where OBJECT-LIST := { header | table }\n");
5273 }
5274
5275 static int cmd_dpipe(struct dl *dl)
5276 {
5277 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5278 cmd_dpipe_help();
5279 return 0;
5280 } else if (dl_argv_match(dl, "header")) {
5281 dl_arg_inc(dl);
5282 return cmd_dpipe_header(dl);
5283 } else if (dl_argv_match(dl, "table")) {
5284 dl_arg_inc(dl);
5285 return cmd_dpipe_table(dl);
5286 }
5287 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5288 return -ENOENT;
5289 }
5290
5291 static int
5292 resource_parse(struct resource_ctx *ctx, struct resource *resource,
5293 struct nlattr **nla_resource)
5294 {
5295 if (!nla_resource[DEVLINK_ATTR_RESOURCE_NAME] ||
5296 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE] ||
5297 !nla_resource[DEVLINK_ATTR_RESOURCE_ID] ||
5298 !nla_resource[DEVLINK_ATTR_RESOURCE_UNIT] ||
5299 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN] ||
5300 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX] ||
5301 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]) {
5302 return -EINVAL;
5303 }
5304
5305 resource->name = strdup(mnl_attr_get_str(nla_resource[DEVLINK_ATTR_RESOURCE_NAME]));
5306 resource->size = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE]);
5307 resource->id = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_ID]);
5308 resource->unit = mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_UNIT]);
5309 resource->size_min = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN]);
5310 resource->size_max = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX]);
5311 resource->size_gran = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]);
5312
5313 if (nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW])
5314 resource->size_new = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW]);
5315 else
5316 resource->size_new = resource->size;
5317
5318 if (nla_resource[DEVLINK_ATTR_RESOURCE_OCC]) {
5319 resource->size_occ = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_OCC]);
5320 resource->occ_valid = true;
5321 }
5322
5323 if (resource->size_new != resource->size)
5324 ctx->pending_change = true;
5325
5326 return 0;
5327 }
5328
5329 static int
5330 resource_get(struct resource_ctx *ctx, struct resource *resource,
5331 struct resource *parent_resource, struct nlattr *nl)
5332 {
5333 struct nlattr *nla_resource[DEVLINK_ATTR_MAX + 1] = {};
5334 struct nlattr *nla_child_resource;
5335 struct nlattr *nla_resources;
5336 bool top = false;
5337 int err;
5338
5339 if (!resource) {
5340 nla_resources = nl;
5341 top = true;
5342 goto out;
5343 }
5344
5345 err = mnl_attr_parse_nested(nl, attr_cb, nla_resource);
5346 if (err != MNL_CB_OK)
5347 return -EINVAL;
5348
5349 err = resource_parse(ctx, resource, nla_resource);
5350 if (err)
5351 return err;
5352
5353 resource->parent = parent_resource;
5354 if (!nla_resource[DEVLINK_ATTR_RESOURCE_LIST])
5355 return 0;
5356
5357 resource->size_valid = !!mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_VALID]);
5358 nla_resources = nla_resource[DEVLINK_ATTR_RESOURCE_LIST];
5359 out:
5360 mnl_attr_for_each_nested(nla_child_resource, nla_resources) {
5361 struct resource *child_resource;
5362 struct list_head *list;
5363
5364 child_resource = resource_alloc();
5365 if (!child_resource)
5366 return -ENOMEM;
5367
5368 if (top)
5369 list = &ctx->resources->resource_list;
5370 else
5371 list = &resource->resource_list;
5372
5373 list_add_tail(&child_resource->list, list);
5374 err = resource_get(ctx, child_resource, resource,
5375 nla_child_resource);
5376 if (err)
5377 return err;
5378 }
5379
5380 return 0;
5381 }
5382
5383 static const char *resource_unit_str_get(enum devlink_resource_unit unit)
5384 {
5385 switch (unit) {
5386 case DEVLINK_RESOURCE_UNIT_ENTRY: return "entry";
5387 default: return "<unknown unit>";
5388 }
5389 }
5390
5391 static void resource_show(struct resource *resource,
5392 struct resource_ctx *ctx)
5393 {
5394 struct resource *child_resource;
5395 struct dpipe_table *table;
5396 struct dl *dl = ctx->dl;
5397 bool array = false;
5398
5399 pr_out_str(dl, "name", resource->name);
5400 if (dl->verbose)
5401 resource_path_print(dl, ctx->resources, resource->id);
5402 pr_out_u64(dl, "size", resource->size);
5403 if (resource->size != resource->size_new)
5404 pr_out_u64(dl, "size_new", resource->size_new);
5405 if (resource->occ_valid)
5406 pr_out_uint(dl, "occ", resource->size_occ);
5407 pr_out_str(dl, "unit", resource_unit_str_get(resource->unit));
5408
5409 if (resource->size_min != resource->size_max) {
5410 pr_out_uint(dl, "size_min", resource->size_min);
5411 pr_out_u64(dl, "size_max", resource->size_max);
5412 pr_out_uint(dl, "size_gran", resource->size_gran);
5413 }
5414
5415 list_for_each_entry(table, &ctx->tables->table_list, list)
5416 if (table->resource_id == resource->id &&
5417 table->resource_valid)
5418 array = true;
5419
5420 if (array)
5421 pr_out_array_start(dl, "dpipe_tables");
5422 else
5423 pr_out_str(dl, "dpipe_tables", "none");
5424
5425 list_for_each_entry(table, &ctx->tables->table_list, list) {
5426 if (table->resource_id != resource->id ||
5427 !table->resource_valid)
5428 continue;
5429 pr_out_entry_start(dl);
5430 pr_out_str(dl, "table_name", table->name);
5431 pr_out_entry_end(dl);
5432 }
5433 if (array)
5434 pr_out_array_end(dl);
5435
5436 if (list_empty(&resource->resource_list))
5437 return;
5438
5439 if (ctx->pending_change)
5440 pr_out_str(dl, "size_valid", resource->size_valid ?
5441 "true" : "false");
5442 pr_out_array_start(dl, "resources");
5443 list_for_each_entry(child_resource, &resource->resource_list, list) {
5444 pr_out_entry_start(dl);
5445 resource_show(child_resource, ctx);
5446 pr_out_entry_end(dl);
5447 }
5448 pr_out_array_end(dl);
5449 }
5450
5451 static void
5452 resources_show(struct resource_ctx *ctx, struct nlattr **tb)
5453 {
5454 struct resources *resources = ctx->resources;
5455 struct resource *resource;
5456
5457 list_for_each_entry(resource, &resources->resource_list, list) {
5458 pr_out_handle_start_arr(ctx->dl, tb);
5459 resource_show(resource, ctx);
5460 pr_out_handle_end(ctx->dl);
5461 }
5462 }
5463
5464 static int resources_get(struct resource_ctx *ctx, struct nlattr **tb)
5465 {
5466 return resource_get(ctx, NULL, NULL, tb[DEVLINK_ATTR_RESOURCE_LIST]);
5467 }
5468
5469 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data)
5470 {
5471 struct resource_ctx *ctx = data;
5472 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5473 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5474 int err;
5475
5476 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5477 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5478 !tb[DEVLINK_ATTR_RESOURCE_LIST])
5479 return MNL_CB_ERROR;
5480
5481 err = resources_get(ctx, tb);
5482 if (err) {
5483 ctx->err = err;
5484 return MNL_CB_ERROR;
5485 }
5486
5487 if (ctx->print_resources)
5488 resources_show(ctx, tb);
5489
5490 return MNL_CB_OK;
5491 }
5492
5493 static int cmd_resource_show(struct dl *dl)
5494 {
5495 struct nlmsghdr *nlh;
5496 struct dpipe_ctx dpipe_ctx = {};
5497 struct resource_ctx resource_ctx = {};
5498 int err;
5499
5500 err = dl_argv_parse(dl, DL_OPT_HANDLE, 0);
5501 if (err)
5502 return err;
5503
5504 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET,
5505 NLM_F_REQUEST);
5506 dl_opts_put(nlh, dl);
5507
5508 err = dpipe_ctx_init(&dpipe_ctx, dl);
5509 if (err)
5510 return err;
5511
5512 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb,
5513 &dpipe_ctx);
5514 if (err) {
5515 pr_err("error get tables %s\n", strerror(dpipe_ctx.err));
5516 goto out;
5517 }
5518
5519 err = resource_ctx_init(&resource_ctx, dl);
5520 if (err)
5521 goto out;
5522
5523 resource_ctx.print_resources = true;
5524 resource_ctx.tables = dpipe_ctx.tables;
5525 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
5526 NLM_F_REQUEST | NLM_F_ACK);
5527 dl_opts_put(nlh, dl);
5528 pr_out_section_start(dl, "resources");
5529 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
5530 &resource_ctx);
5531 pr_out_section_end(dl);
5532 resource_ctx_fini(&resource_ctx);
5533 out:
5534 dpipe_ctx_fini(&dpipe_ctx);
5535 return err;
5536 }
5537
5538 static void cmd_resource_help(void)
5539 {
5540 pr_err("Usage: devlink resource show DEV\n"
5541 " devlink resource set DEV path PATH size SIZE\n");
5542 }
5543
5544 static struct resource *
5545 resource_find_by_name(struct list_head *list, char *name)
5546 {
5547 struct resource *resource;
5548
5549 list_for_each_entry(resource, list, list) {
5550 if (!strcmp(resource->name, name))
5551 return resource;
5552 }
5553 return NULL;
5554 }
5555
5556 static int
5557 resource_path_parse(struct resource_ctx *ctx, const char *resource_path,
5558 uint32_t *p_resource_id, bool *p_resource_valid)
5559 {
5560 struct resource *resource;
5561 uint32_t resource_id = 0;
5562 char *resource_path_dup;
5563 struct list_head *list;
5564 const char del[] = "/";
5565 char *resource_name;
5566
5567 resource_path_dup = strdup(resource_path);
5568 list = &ctx->resources->resource_list;
5569 resource_name = strtok(resource_path_dup, del);
5570 while (resource_name != NULL) {
5571 resource = resource_find_by_name(list, resource_name);
5572 if (!resource)
5573 goto err_resource_lookup;
5574
5575 list = &resource->resource_list;
5576 resource_name = strtok(NULL, del);
5577 resource_id = resource->id;
5578 }
5579 free(resource_path_dup);
5580 *p_resource_valid = true;
5581 *p_resource_id = resource_id;
5582 return 0;
5583
5584 err_resource_lookup:
5585 free(resource_path_dup);
5586 return -EINVAL;
5587 }
5588
5589 static int cmd_resource_set(struct dl *dl)
5590 {
5591 struct nlmsghdr *nlh;
5592 struct resource_ctx ctx = {};
5593 int err;
5594
5595 err = resource_ctx_init(&ctx, dl);
5596 if (err)
5597 return err;
5598
5599 ctx.print_resources = false;
5600 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_RESOURCE_PATH |
5601 DL_OPT_RESOURCE_SIZE, 0);
5602 if (err)
5603 goto out;
5604
5605 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
5606 NLM_F_REQUEST);
5607 dl_opts_put(nlh, dl);
5608 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, &ctx);
5609 if (err) {
5610 pr_err("error getting resources %s\n", strerror(ctx.err));
5611 goto out;
5612 }
5613
5614 err = resource_path_parse(&ctx, dl->opts.resource_path,
5615 &dl->opts.resource_id,
5616 &dl->opts.resource_id_valid);
5617 if (err) {
5618 pr_err("error parsing resource path %s\n", strerror(-err));
5619 goto out;
5620 }
5621
5622 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_SET,
5623 NLM_F_REQUEST | NLM_F_ACK);
5624
5625 dl_opts_put(nlh, dl);
5626 err = _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
5627 out:
5628 resource_ctx_fini(&ctx);
5629 return err;
5630 }
5631
5632 static int cmd_resource(struct dl *dl)
5633 {
5634 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5635 cmd_resource_help();
5636 return 0;
5637 } else if (dl_argv_match(dl, "show")) {
5638 dl_arg_inc(dl);
5639 return cmd_resource_show(dl);
5640 } else if (dl_argv_match(dl, "set")) {
5641 dl_arg_inc(dl);
5642 return cmd_resource_set(dl);
5643 }
5644 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5645 return -ENOENT;
5646 }
5647
5648 static void pr_out_region_handle_start(struct dl *dl, struct nlattr **tb)
5649 {
5650 const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
5651 const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
5652 const char *region_name = mnl_attr_get_str(tb[DEVLINK_ATTR_REGION_NAME]);
5653 char buf[256];
5654
5655 sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name);
5656 if (dl->json_output) {
5657 jsonw_name(dl->jw, buf);
5658 jsonw_start_object(dl->jw);
5659 } else {
5660 pr_out("%s:", buf);
5661 }
5662 }
5663
5664 static void pr_out_region_handle_end(struct dl *dl)
5665 {
5666 if (dl->json_output)
5667 jsonw_end_object(dl->jw);
5668 else
5669 pr_out("\n");
5670 }
5671
5672 static void pr_out_region_snapshots_start(struct dl *dl, bool array)
5673 {
5674 if (dl->json_output) {
5675 jsonw_name(dl->jw, "snapshot");
5676 jsonw_start_array(dl->jw);
5677 } else {
5678 if (g_indent_newline)
5679 pr_out("snapshot %s", array ? "[" : "");
5680 else
5681 pr_out(" snapshot %s", array ? "[" : "");
5682 }
5683 }
5684
5685 static void pr_out_region_snapshots_end(struct dl *dl, bool array)
5686 {
5687 if (dl->json_output)
5688 jsonw_end_array(dl->jw);
5689 else if (array)
5690 pr_out("]");
5691 }
5692
5693 static void pr_out_region_snapshots_id(struct dl *dl, struct nlattr **tb, int index)
5694 {
5695 uint32_t snapshot_id;
5696
5697 if (!tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
5698 return;
5699
5700 snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
5701
5702 if (dl->json_output)
5703 jsonw_uint(dl->jw, snapshot_id);
5704 else
5705 pr_out("%s%u", index ? " " : "", snapshot_id);
5706 }
5707
5708 static void pr_out_snapshots(struct dl *dl, struct nlattr **tb)
5709 {
5710 struct nlattr *tb_snapshot[DEVLINK_ATTR_MAX + 1] = {};
5711 struct nlattr *nla_sanpshot;
5712 int err, index = 0;
5713
5714 pr_out_region_snapshots_start(dl, true);
5715 mnl_attr_for_each_nested(nla_sanpshot, tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) {
5716 err = mnl_attr_parse_nested(nla_sanpshot, attr_cb, tb_snapshot);
5717 if (err != MNL_CB_OK)
5718 return;
5719 pr_out_region_snapshots_id(dl, tb_snapshot, index++);
5720 }
5721 pr_out_region_snapshots_end(dl, true);
5722 }
5723
5724 static void pr_out_snapshot(struct dl *dl, struct nlattr **tb)
5725 {
5726 pr_out_region_snapshots_start(dl, false);
5727 pr_out_region_snapshots_id(dl, tb, 0);
5728 pr_out_region_snapshots_end(dl, false);
5729 }
5730
5731 static void pr_out_region(struct dl *dl, struct nlattr **tb)
5732 {
5733 pr_out_region_handle_start(dl, tb);
5734
5735 if (tb[DEVLINK_ATTR_REGION_SIZE])
5736 pr_out_u64(dl, "size",
5737 mnl_attr_get_u64(tb[DEVLINK_ATTR_REGION_SIZE]));
5738
5739 if (tb[DEVLINK_ATTR_REGION_SNAPSHOTS])
5740 pr_out_snapshots(dl, tb);
5741
5742 if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
5743 pr_out_snapshot(dl, tb);
5744
5745 pr_out_region_handle_end(dl);
5746 }
5747
5748 static int cmd_region_show_cb(const struct nlmsghdr *nlh, void *data)
5749 {
5750 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5751 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5752 struct dl *dl = data;
5753
5754 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5755 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5756 !tb[DEVLINK_ATTR_REGION_NAME] || !tb[DEVLINK_ATTR_REGION_SIZE])
5757 return MNL_CB_ERROR;
5758
5759 pr_out_region(dl, tb);
5760
5761 return MNL_CB_OK;
5762 }
5763
5764 static int cmd_region_show(struct dl *dl)
5765 {
5766 struct nlmsghdr *nlh;
5767 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5768 int err;
5769
5770 if (dl_argc(dl) == 0)
5771 flags |= NLM_F_DUMP;
5772
5773 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_GET, flags);
5774
5775 if (dl_argc(dl) > 0) {
5776 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0);
5777 if (err)
5778 return err;
5779 }
5780
5781 pr_out_section_start(dl, "regions");
5782 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_show_cb, dl);
5783 pr_out_section_end(dl);
5784 return err;
5785 }
5786
5787 static int cmd_region_snapshot_del(struct dl *dl)
5788 {
5789 struct nlmsghdr *nlh;
5790 int err;
5791
5792 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_DEL,
5793 NLM_F_REQUEST | NLM_F_ACK);
5794
5795 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
5796 DL_OPT_REGION_SNAPSHOT_ID, 0);
5797 if (err)
5798 return err;
5799
5800 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
5801 }
5802
5803 static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data)
5804 {
5805 struct nlattr *nla_entry, *nla_chunk_data, *nla_chunk_addr;
5806 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5807 struct nlattr *tb_field[DEVLINK_ATTR_MAX + 1] = {};
5808 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5809 struct dl *dl = data;
5810 int err;
5811
5812 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5813 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5814 !tb[DEVLINK_ATTR_REGION_CHUNKS])
5815 return MNL_CB_ERROR;
5816
5817 mnl_attr_for_each_nested(nla_entry, tb[DEVLINK_ATTR_REGION_CHUNKS]) {
5818 err = mnl_attr_parse_nested(nla_entry, attr_cb, tb_field);
5819 if (err != MNL_CB_OK)
5820 return MNL_CB_ERROR;
5821
5822 nla_chunk_data = tb_field[DEVLINK_ATTR_REGION_CHUNK_DATA];
5823 if (!nla_chunk_data)
5824 continue;
5825
5826 nla_chunk_addr = tb_field[DEVLINK_ATTR_REGION_CHUNK_ADDR];
5827 if (!nla_chunk_addr)
5828 continue;
5829
5830 pr_out_region_chunk(dl, mnl_attr_get_payload(nla_chunk_data),
5831 mnl_attr_get_payload_len(nla_chunk_data),
5832 mnl_attr_get_u64(nla_chunk_addr));
5833 }
5834 return MNL_CB_OK;
5835 }
5836
5837 static int cmd_region_dump(struct dl *dl)
5838 {
5839 struct nlmsghdr *nlh;
5840 int err;
5841
5842 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
5843 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
5844
5845 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
5846 DL_OPT_REGION_SNAPSHOT_ID, 0);
5847 if (err)
5848 return err;
5849
5850 pr_out_section_start(dl, "dump");
5851 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
5852 pr_out_section_end(dl);
5853 if (!dl->json_output)
5854 pr_out("\n");
5855 return err;
5856 }
5857
5858 static int cmd_region_read(struct dl *dl)
5859 {
5860 struct nlmsghdr *nlh;
5861 int err;
5862
5863 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
5864 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
5865
5866 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
5867 DL_OPT_REGION_ADDRESS | DL_OPT_REGION_LENGTH |
5868 DL_OPT_REGION_SNAPSHOT_ID, 0);
5869 if (err)
5870 return err;
5871
5872 pr_out_section_start(dl, "read");
5873 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
5874 pr_out_section_end(dl);
5875 if (!dl->json_output)
5876 pr_out("\n");
5877 return err;
5878 }
5879
5880 static void cmd_region_help(void)
5881 {
5882 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
5883 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
5884 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
5885 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
5886 }
5887
5888 static int cmd_region(struct dl *dl)
5889 {
5890 if (dl_no_arg(dl)) {
5891 return cmd_region_show(dl);
5892 } else if (dl_argv_match(dl, "help")) {
5893 cmd_region_help();
5894 return 0;
5895 } else if (dl_argv_match(dl, "show")) {
5896 dl_arg_inc(dl);
5897 return cmd_region_show(dl);
5898 } else if (dl_argv_match(dl, "del")) {
5899 dl_arg_inc(dl);
5900 return cmd_region_snapshot_del(dl);
5901 } else if (dl_argv_match(dl, "dump")) {
5902 dl_arg_inc(dl);
5903 return cmd_region_dump(dl);
5904 } else if (dl_argv_match(dl, "read")) {
5905 dl_arg_inc(dl);
5906 return cmd_region_read(dl);
5907 }
5908 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5909 return -ENOENT;
5910 }
5911
5912 static int cmd_health_set_params(struct dl *dl)
5913 {
5914 struct nlmsghdr *nlh;
5915 int err;
5916
5917 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET,
5918 NLM_F_REQUEST | NLM_F_ACK);
5919 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME,
5920 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD |
5921 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER);
5922 if (err)
5923 return err;
5924
5925 dl_opts_put(nlh, dl);
5926 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
5927 }
5928
5929 static int cmd_health_dump_clear(struct dl *dl)
5930 {
5931 struct nlmsghdr *nlh;
5932 int err;
5933
5934 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
5935 NLM_F_REQUEST | NLM_F_ACK);
5936
5937 err = dl_argv_parse_put(nlh, dl,
5938 DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
5939 if (err)
5940 return err;
5941
5942 dl_opts_put(nlh, dl);
5943 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
5944 }
5945
5946 static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
5947 {
5948 uint8_t *data;
5949 uint32_t len;
5950
5951 switch (type) {
5952 case MNL_TYPE_FLAG:
5953 pr_out_bool_value(dl, mnl_attr_get_u8(nl_data));
5954 break;
5955 case MNL_TYPE_U8:
5956 pr_out_uint_value(dl, mnl_attr_get_u8(nl_data));
5957 break;
5958 case MNL_TYPE_U16:
5959 pr_out_uint_value(dl, mnl_attr_get_u16(nl_data));
5960 break;
5961 case MNL_TYPE_U32:
5962 pr_out_uint_value(dl, mnl_attr_get_u32(nl_data));
5963 break;
5964 case MNL_TYPE_U64:
5965 pr_out_uint64_value(dl, mnl_attr_get_u64(nl_data));
5966 break;
5967 case MNL_TYPE_NUL_STRING:
5968 pr_out_str_value(dl, mnl_attr_get_str(nl_data));
5969 break;
5970 case MNL_TYPE_BINARY:
5971 len = mnl_attr_get_payload_len(nl_data);
5972 data = mnl_attr_get_payload(nl_data);
5973 pr_out_binary_value(dl, data, len);
5974 break;
5975 default:
5976 return -EINVAL;
5977 }
5978 return MNL_CB_OK;
5979 }
5980
5981 struct nest_entry {
5982 int attr_type;
5983 struct list_head list;
5984 };
5985
5986 struct fmsg_cb_data {
5987 struct dl *dl;
5988 uint8_t value_type;
5989 struct list_head entry_list;
5990 };
5991
5992 static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
5993 uint8_t *attr_value, bool insert)
5994 {
5995 struct nest_entry *entry;
5996
5997 if (insert) {
5998 entry = malloc(sizeof(struct nest_entry));
5999 if (!entry)
6000 return -ENOMEM;
6001
6002 entry->attr_type = *attr_value;
6003 list_add(&entry->list, &fmsg_data->entry_list);
6004 } else {
6005 if (list_empty(&fmsg_data->entry_list))
6006 return MNL_CB_ERROR;
6007 entry = list_first_entry(&fmsg_data->entry_list,
6008 struct nest_entry, list);
6009 *attr_value = entry->attr_type;
6010 list_del(&entry->list);
6011 free(entry);
6012 }
6013 return MNL_CB_OK;
6014 }
6015
6016 static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value,
6017 bool start)
6018 {
6019 struct dl *dl = fmsg_data->dl;
6020 uint8_t value = nest_value;
6021 int err;
6022
6023 err = cmd_fmsg_nest_queue(fmsg_data, &value, start);
6024 if (err != MNL_CB_OK)
6025 return err;
6026
6027 switch (value) {
6028 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
6029 if (start)
6030 pr_out_entry_start(dl);
6031 else
6032 pr_out_entry_end(dl);
6033 break;
6034 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
6035 break;
6036 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
6037 if (dl->json_output) {
6038 if (start)
6039 jsonw_start_array(dl->jw);
6040 else
6041 jsonw_end_array(dl->jw);
6042 } else {
6043 if (start) {
6044 __pr_out_newline();
6045 __pr_out_indent_inc();
6046 } else {
6047 __pr_out_indent_dec();
6048 }
6049 }
6050 break;
6051 default:
6052 return -EINVAL;
6053 }
6054 return MNL_CB_OK;
6055 }
6056
6057 static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data)
6058 {
6059 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6060 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6061 struct fmsg_cb_data *fmsg_data = data;
6062 struct dl *dl = fmsg_data->dl;
6063 struct nlattr *nla_object;
6064 int attr_type;
6065 int err;
6066
6067 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6068 if (!tb[DEVLINK_ATTR_FMSG])
6069 return MNL_CB_ERROR;
6070
6071 mnl_attr_for_each_nested(nla_object, tb[DEVLINK_ATTR_FMSG]) {
6072 attr_type = mnl_attr_get_type(nla_object);
6073 switch (attr_type) {
6074 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
6075 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
6076 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
6077 err = cmd_fmsg_nest(fmsg_data, attr_type, true);
6078 if (err != MNL_CB_OK)
6079 return err;
6080 break;
6081 case DEVLINK_ATTR_FMSG_NEST_END:
6082 err = cmd_fmsg_nest(fmsg_data, attr_type, false);
6083 if (err != MNL_CB_OK)
6084 return err;
6085 break;
6086 case DEVLINK_ATTR_FMSG_OBJ_NAME:
6087 pr_out_name(dl, mnl_attr_get_str(nla_object));
6088 break;
6089 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE:
6090 fmsg_data->value_type = mnl_attr_get_u8(nla_object);
6091 break;
6092 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
6093 err = fmsg_value_show(dl, fmsg_data->value_type,
6094 nla_object);
6095 if (err != MNL_CB_OK)
6096 return err;
6097 break;
6098 default:
6099 return -EINVAL;
6100 }
6101 }
6102 return MNL_CB_OK;
6103 }
6104
6105 static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
6106 {
6107 struct fmsg_cb_data data;
6108 struct nlmsghdr *nlh;
6109 int err;
6110
6111 nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
6112
6113 err = dl_argv_parse_put(nlh, dl,
6114 DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
6115 if (err)
6116 return err;
6117
6118 data.dl = dl;
6119 INIT_LIST_HEAD(&data.entry_list);
6120 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data);
6121 return err;
6122 }
6123
6124 static int cmd_health_dump_show(struct dl *dl)
6125 {
6126 return cmd_health_object_common(dl,
6127 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
6128 NLM_F_DUMP);
6129 }
6130
6131 static int cmd_health_diagnose(struct dl *dl)
6132 {
6133 return cmd_health_object_common(dl,
6134 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
6135 0);
6136 }
6137
6138 static int cmd_health_recover(struct dl *dl)
6139 {
6140 struct nlmsghdr *nlh;
6141 int err;
6142
6143 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
6144 NLM_F_REQUEST | NLM_F_ACK);
6145
6146 err = dl_argv_parse_put(nlh, dl,
6147 DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
6148 if (err)
6149 return err;
6150
6151 dl_opts_put(nlh, dl);
6152 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6153 }
6154
6155 enum devlink_health_reporter_state {
6156 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
6157 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
6158 };
6159
6160 static const char *health_state_name(uint8_t state)
6161 {
6162 switch (state) {
6163 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY:
6164 return HEALTH_REPORTER_STATE_HEALTHY_STR;
6165 case DEVLINK_HEALTH_REPORTER_STATE_ERROR:
6166 return HEALTH_REPORTER_STATE_ERROR_STR;
6167 default:
6168 return "<unknown state>";
6169 }
6170 }
6171
6172 static void format_logtime(uint64_t time_ms, char *ts_date, char *ts_time)
6173 {
6174 struct sysinfo s_info;
6175 struct tm *info;
6176 time_t now, sec;
6177 int err;
6178
6179 time(&now);
6180 info = localtime(&now);
6181 err = sysinfo(&s_info);
6182 if (err)
6183 goto out;
6184 /* Subtract uptime in sec from now yields the time of system
6185 * uptime. To this, add time_ms which is the amount of
6186 * milliseconds elapsed between uptime and the dump taken.
6187 */
6188 sec = now - s_info.uptime + time_ms / 1000;
6189 info = localtime(&sec);
6190 out:
6191 strftime(ts_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
6192 strftime(ts_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
6193 }
6194
6195 static void pr_out_health(struct dl *dl, struct nlattr **tb_health)
6196 {
6197 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6198 enum devlink_health_reporter_state state;
6199 const struct nlattr *attr;
6200 uint64_t time_ms;
6201 int err;
6202
6203 err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER],
6204 attr_cb, tb);
6205 if (err != MNL_CB_OK)
6206 return;
6207
6208 if (!tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME] ||
6209 !tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] ||
6210 !tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] ||
6211 !tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE])
6212 return;
6213
6214 pr_out_handle_start_arr(dl, tb_health);
6215
6216 pr_out_str(dl, "name",
6217 mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
6218 if (!dl->json_output) {
6219 __pr_out_newline();
6220 __pr_out_indent_inc();
6221 }
6222 state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]);
6223 pr_out_str(dl, "state", health_state_name(state));
6224 pr_out_u64(dl, "error",
6225 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT]));
6226 pr_out_u64(dl, "recover",
6227 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT]));
6228 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]) {
6229 char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
6230 char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
6231
6232 attr = tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS];
6233 time_ms = mnl_attr_get_u64(attr);
6234 format_logtime(time_ms, dump_date, dump_time);
6235
6236 pr_out_str(dl, "last_dump_date", dump_date);
6237 pr_out_str(dl, "last_dump_time", dump_time);
6238 }
6239 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
6240 pr_out_u64(dl, "grace_period",
6241 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]));
6242 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
6243 pr_out_bool(dl, "auto_recover",
6244 mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]));
6245
6246 __pr_out_indent_dec();
6247 pr_out_handle_end(dl);
6248 }
6249
6250 static int cmd_health_show_cb(const struct nlmsghdr *nlh, void *data)
6251 {
6252 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6253 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6254 struct dl *dl = data;
6255
6256 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6257 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6258 !tb[DEVLINK_ATTR_HEALTH_REPORTER])
6259 return MNL_CB_ERROR;
6260
6261 pr_out_health(dl, tb);
6262
6263 return MNL_CB_OK;
6264 }
6265
6266 static int cmd_health_show(struct dl *dl)
6267 {
6268 struct nlmsghdr *nlh;
6269 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6270 int err;
6271
6272 if (dl_argc(dl) == 0)
6273 flags |= NLM_F_DUMP;
6274 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET,
6275 flags);
6276
6277 if (dl_argc(dl) > 0) {
6278 err = dl_argv_parse_put(nlh, dl,
6279 DL_OPT_HANDLE |
6280 DL_OPT_HEALTH_REPORTER_NAME, 0);
6281 if (err)
6282 return err;
6283 }
6284 pr_out_section_start(dl, "health");
6285
6286 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_health_show_cb, dl);
6287 pr_out_section_end(dl);
6288 return err;
6289 }
6290
6291 static void cmd_health_help(void)
6292 {
6293 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
6294 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
6295 pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n");
6296 pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n");
6297 pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n");
6298 pr_err(" devlink health set DEV reporter REPORTER_NAME { grace_period | auto_recover } { msec | boolean }\n");
6299 }
6300
6301 static int cmd_health(struct dl *dl)
6302 {
6303 if (dl_argv_match(dl, "help")) {
6304 cmd_health_help();
6305 return 0;
6306 } else if (dl_argv_match(dl, "show") ||
6307 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
6308 dl_arg_inc(dl);
6309 return cmd_health_show(dl);
6310 } else if (dl_argv_match(dl, "recover")) {
6311 dl_arg_inc(dl);
6312 return cmd_health_recover(dl);
6313 } else if (dl_argv_match(dl, "diagnose")) {
6314 dl_arg_inc(dl);
6315 return cmd_health_diagnose(dl);
6316 } else if (dl_argv_match(dl, "dump")) {
6317 dl_arg_inc(dl);
6318 if (dl_argv_match(dl, "show")) {
6319 dl_arg_inc(dl);
6320 return cmd_health_dump_show(dl);
6321 } else if (dl_argv_match(dl, "clear")) {
6322 dl_arg_inc(dl);
6323 return cmd_health_dump_clear(dl);
6324 }
6325 } else if (dl_argv_match(dl, "set")) {
6326 dl_arg_inc(dl);
6327 return cmd_health_set_params(dl);
6328 }
6329 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6330 return -ENOENT;
6331 }
6332
6333 static void help(void)
6334 {
6335 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
6336 " devlink [ -f[orce] ] -b[atch] filename\n"
6337 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health }\n"
6338 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] }\n");
6339 }
6340
6341 static int dl_cmd(struct dl *dl, int argc, char **argv)
6342 {
6343 dl->argc = argc;
6344 dl->argv = argv;
6345
6346 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6347 help();
6348 return 0;
6349 } else if (dl_argv_match(dl, "dev")) {
6350 dl_arg_inc(dl);
6351 return cmd_dev(dl);
6352 } else if (dl_argv_match(dl, "port")) {
6353 dl_arg_inc(dl);
6354 return cmd_port(dl);
6355 } else if (dl_argv_match(dl, "sb")) {
6356 dl_arg_inc(dl);
6357 return cmd_sb(dl);
6358 } else if (dl_argv_match(dl, "monitor")) {
6359 dl_arg_inc(dl);
6360 return cmd_mon(dl);
6361 } else if (dl_argv_match(dl, "dpipe")) {
6362 dl_arg_inc(dl);
6363 return cmd_dpipe(dl);
6364 } else if (dl_argv_match(dl, "resource")) {
6365 dl_arg_inc(dl);
6366 return cmd_resource(dl);
6367 } else if (dl_argv_match(dl, "region")) {
6368 dl_arg_inc(dl);
6369 return cmd_region(dl);
6370 } else if (dl_argv_match(dl, "health")) {
6371 dl_arg_inc(dl);
6372 return cmd_health(dl);
6373 }
6374 pr_err("Object \"%s\" not found\n", dl_argv(dl));
6375 return -ENOENT;
6376 }
6377
6378 static int dl_init(struct dl *dl)
6379 {
6380 int err;
6381
6382 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
6383 if (!dl->nlg) {
6384 pr_err("Failed to connect to devlink Netlink\n");
6385 return -errno;
6386 }
6387
6388 err = ifname_map_init(dl);
6389 if (err) {
6390 pr_err("Failed to create index map\n");
6391 goto err_ifname_map_create;
6392 }
6393 if (dl->json_output) {
6394 dl->jw = jsonw_new(stdout);
6395 if (!dl->jw) {
6396 pr_err("Failed to create JSON writer\n");
6397 goto err_json_new;
6398 }
6399 jsonw_pretty(dl->jw, dl->pretty_output);
6400 }
6401 return 0;
6402
6403 err_json_new:
6404 ifname_map_fini(dl);
6405 err_ifname_map_create:
6406 mnlg_socket_close(dl->nlg);
6407 return err;
6408 }
6409
6410 static void dl_fini(struct dl *dl)
6411 {
6412 if (dl->json_output)
6413 jsonw_destroy(&dl->jw);
6414 ifname_map_fini(dl);
6415 mnlg_socket_close(dl->nlg);
6416 }
6417
6418 static struct dl *dl_alloc(void)
6419 {
6420 struct dl *dl;
6421
6422 dl = calloc(1, sizeof(*dl));
6423 if (!dl)
6424 return NULL;
6425 return dl;
6426 }
6427
6428 static void dl_free(struct dl *dl)
6429 {
6430 free(dl);
6431 }
6432
6433 static int dl_batch(struct dl *dl, const char *name, bool force)
6434 {
6435 char *line = NULL;
6436 size_t len = 0;
6437 int ret = EXIT_SUCCESS;
6438
6439 if (name && strcmp(name, "-") != 0) {
6440 if (freopen(name, "r", stdin) == NULL) {
6441 fprintf(stderr,
6442 "Cannot open file \"%s\" for reading: %s\n",
6443 name, strerror(errno));
6444 return EXIT_FAILURE;
6445 }
6446 }
6447
6448 cmdlineno = 0;
6449 while (getcmdline(&line, &len, stdin) != -1) {
6450 char *largv[100];
6451 int largc;
6452
6453 largc = makeargs(line, largv, 100);
6454 if (!largc)
6455 continue; /* blank line */
6456
6457 if (dl_cmd(dl, largc, largv)) {
6458 fprintf(stderr, "Command failed %s:%d\n",
6459 name, cmdlineno);
6460 ret = EXIT_FAILURE;
6461 if (!force)
6462 break;
6463 }
6464 }
6465
6466 if (line)
6467 free(line);
6468
6469 return ret;
6470 }
6471
6472 int main(int argc, char **argv)
6473 {
6474 static const struct option long_options[] = {
6475 { "Version", no_argument, NULL, 'V' },
6476 { "force", no_argument, NULL, 'f' },
6477 { "batch", required_argument, NULL, 'b' },
6478 { "no-nice-names", no_argument, NULL, 'n' },
6479 { "json", no_argument, NULL, 'j' },
6480 { "pretty", no_argument, NULL, 'p' },
6481 { "verbose", no_argument, NULL, 'v' },
6482 { NULL, 0, NULL, 0 }
6483 };
6484 const char *batch_file = NULL;
6485 bool force = false;
6486 struct dl *dl;
6487 int opt;
6488 int err;
6489 int ret;
6490
6491 dl = dl_alloc();
6492 if (!dl) {
6493 pr_err("Failed to allocate memory for devlink\n");
6494 return EXIT_FAILURE;
6495 }
6496
6497 while ((opt = getopt_long(argc, argv, "Vfb:njpv",
6498 long_options, NULL)) >= 0) {
6499
6500 switch (opt) {
6501 case 'V':
6502 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
6503 ret = EXIT_SUCCESS;
6504 goto dl_free;
6505 case 'f':
6506 force = true;
6507 break;
6508 case 'b':
6509 batch_file = optarg;
6510 break;
6511 case 'n':
6512 dl->no_nice_names = true;
6513 break;
6514 case 'j':
6515 dl->json_output = true;
6516 break;
6517 case 'p':
6518 dl->pretty_output = true;
6519 break;
6520 case 'v':
6521 dl->verbose = true;
6522 break;
6523 default:
6524 pr_err("Unknown option.\n");
6525 help();
6526 ret = EXIT_FAILURE;
6527 goto dl_free;
6528 }
6529 }
6530
6531 argc -= optind;
6532 argv += optind;
6533
6534 err = dl_init(dl);
6535 if (err) {
6536 ret = EXIT_FAILURE;
6537 goto dl_free;
6538 }
6539
6540 if (batch_file)
6541 err = dl_batch(dl, batch_file, force);
6542 else
6543 err = dl_cmd(dl, argc, argv);
6544
6545 if (err) {
6546 ret = EXIT_FAILURE;
6547 goto dl_fini;
6548 }
6549
6550 ret = EXIT_SUCCESS;
6551
6552 dl_fini:
6553 dl_fini(dl);
6554 dl_free:
6555 dl_free(dl);
6556
6557 return ret;
6558 }