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