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