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