]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
devlink: Change empty line indication with indentations
[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 <linux/genetlink.h>
21 #include <linux/devlink.h>
22 #include <libmnl/libmnl.h>
23 #include <netinet/ether.h>
24
25 #include "SNAPSHOT.h"
26 #include "list.h"
27 #include "mnlg.h"
28 #include "json_writer.h"
29 #include "utils.h"
30
31 #define ESWITCH_MODE_LEGACY "legacy"
32 #define ESWITCH_MODE_SWITCHDEV "switchdev"
33 #define ESWITCH_INLINE_MODE_NONE "none"
34 #define ESWITCH_INLINE_MODE_LINK "link"
35 #define ESWITCH_INLINE_MODE_NETWORK "network"
36 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
37
38 static int g_new_line_count;
39
40 #define pr_err(args...) fprintf(stderr, ##args)
41 #define pr_out(args...) \
42 do { \
43 if (g_indent_newline) { \
44 fprintf(stdout, "%s", g_indent_str); \
45 g_indent_newline = false; \
46 } \
47 fprintf(stdout, ##args); \
48 g_new_line_count = 0; \
49 } while (0)
50
51 #define pr_out_sp(num, args...) \
52 do { \
53 int ret = fprintf(stdout, ##args); \
54 if (ret < num) \
55 fprintf(stdout, "%*s", num - ret, ""); \
56 g_new_line_count = 0; \
57 } while (0)
58
59 static int g_indent_level;
60 static bool g_indent_newline;
61 #define INDENT_STR_STEP 2
62 #define INDENT_STR_MAXLEN 32
63 static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
64
65 static void __pr_out_indent_inc(void)
66 {
67 if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
68 return;
69 g_indent_level += INDENT_STR_STEP;
70 memset(g_indent_str, ' ', sizeof(g_indent_str));
71 g_indent_str[g_indent_level] = '\0';
72 }
73
74 static void __pr_out_indent_dec(void)
75 {
76 if (g_indent_level - INDENT_STR_STEP < 0)
77 return;
78 g_indent_level -= INDENT_STR_STEP;
79 g_indent_str[g_indent_level] = '\0';
80 }
81
82 static void __pr_out_newline(void)
83 {
84 if (g_new_line_count < 1) {
85 pr_out("\n");
86 g_indent_newline = true;
87 }
88 g_new_line_count++;
89 }
90
91 static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
92 mnl_cb_t data_cb, void *data)
93 {
94 int err;
95
96 err = mnlg_socket_recv_run(nlg, data_cb, data);
97 if (err < 0) {
98 pr_err("devlink answers: %s\n", strerror(errno));
99 return -errno;
100 }
101 return 0;
102 }
103
104 static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
105 const struct nlmsghdr *nlh,
106 mnl_cb_t data_cb, void *data)
107 {
108 int err;
109
110 err = mnlg_socket_send(nlg, nlh);
111 if (err < 0) {
112 pr_err("Failed to call mnlg_socket_send\n");
113 return -errno;
114 }
115 return _mnlg_socket_recv_run(nlg, data_cb, data);
116 }
117
118 static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
119 const char *group_name)
120 {
121 int err;
122
123 err = mnlg_socket_group_add(nlg, group_name);
124 if (err < 0) {
125 pr_err("Failed to call mnlg_socket_group_add\n");
126 return -errno;
127 }
128 return 0;
129 }
130
131 struct ifname_map {
132 struct list_head list;
133 char *bus_name;
134 char *dev_name;
135 uint32_t port_index;
136 char *ifname;
137 };
138
139 static struct ifname_map *ifname_map_alloc(const char *bus_name,
140 const char *dev_name,
141 uint32_t port_index,
142 const char *ifname)
143 {
144 struct ifname_map *ifname_map;
145
146 ifname_map = calloc(1, sizeof(*ifname_map));
147 if (!ifname_map)
148 return NULL;
149 ifname_map->bus_name = strdup(bus_name);
150 ifname_map->dev_name = strdup(dev_name);
151 ifname_map->port_index = port_index;
152 ifname_map->ifname = strdup(ifname);
153 if (!ifname_map->bus_name || !ifname_map->dev_name ||
154 !ifname_map->ifname) {
155 free(ifname_map->ifname);
156 free(ifname_map->dev_name);
157 free(ifname_map->bus_name);
158 free(ifname_map);
159 return NULL;
160 }
161 return ifname_map;
162 }
163
164 static void ifname_map_free(struct ifname_map *ifname_map)
165 {
166 free(ifname_map->ifname);
167 free(ifname_map->dev_name);
168 free(ifname_map->bus_name);
169 free(ifname_map);
170 }
171
172 #define DL_OPT_HANDLE BIT(0)
173 #define DL_OPT_HANDLEP BIT(1)
174 #define DL_OPT_PORT_TYPE BIT(2)
175 #define DL_OPT_PORT_COUNT BIT(3)
176 #define DL_OPT_SB BIT(4)
177 #define DL_OPT_SB_POOL BIT(5)
178 #define DL_OPT_SB_SIZE BIT(6)
179 #define DL_OPT_SB_TYPE BIT(7)
180 #define DL_OPT_SB_THTYPE BIT(8)
181 #define DL_OPT_SB_TH BIT(9)
182 #define DL_OPT_SB_TC BIT(10)
183 #define DL_OPT_ESWITCH_MODE BIT(11)
184 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
185 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
186 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
187 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
188
189 struct dl_opts {
190 uint32_t present; /* flags of present items */
191 char *bus_name;
192 char *dev_name;
193 uint32_t port_index;
194 enum devlink_port_type port_type;
195 uint32_t port_count;
196 uint32_t sb_index;
197 uint16_t sb_pool_index;
198 uint32_t sb_pool_size;
199 enum devlink_sb_pool_type sb_pool_type;
200 enum devlink_sb_threshold_type sb_pool_thtype;
201 uint32_t sb_threshold;
202 uint16_t sb_tc_index;
203 enum devlink_eswitch_mode eswitch_mode;
204 enum devlink_eswitch_inline_mode eswitch_inline_mode;
205 const char *dpipe_table_name;
206 bool dpipe_counters_enable;
207 bool eswitch_encap_mode;
208 };
209
210 struct dl {
211 struct mnlg_socket *nlg;
212 struct list_head ifname_map_list;
213 int argc;
214 char **argv;
215 bool no_nice_names;
216 struct dl_opts opts;
217 json_writer_t *jw;
218 bool json_output;
219 bool pretty_output;
220 bool verbose;
221 struct {
222 bool present;
223 char *bus_name;
224 char *dev_name;
225 uint32_t port_index;
226 } arr_last;
227 };
228
229 static int dl_argc(struct dl *dl)
230 {
231 return dl->argc;
232 }
233
234 static char *dl_argv(struct dl *dl)
235 {
236 if (dl_argc(dl) == 0)
237 return NULL;
238 return *dl->argv;
239 }
240
241 static void dl_arg_inc(struct dl *dl)
242 {
243 if (dl_argc(dl) == 0)
244 return;
245 dl->argc--;
246 dl->argv++;
247 }
248
249 static char *dl_argv_next(struct dl *dl)
250 {
251 char *ret;
252
253 if (dl_argc(dl) == 0)
254 return NULL;
255
256 ret = *dl->argv;
257 dl_arg_inc(dl);
258 return ret;
259 }
260
261 static char *dl_argv_index(struct dl *dl, unsigned int index)
262 {
263 if (index >= dl_argc(dl))
264 return NULL;
265 return dl->argv[index];
266 }
267
268 static int strcmpx(const char *str1, const char *str2)
269 {
270 if (strlen(str1) > strlen(str2))
271 return -1;
272 return strncmp(str1, str2, strlen(str1));
273 }
274
275 static bool dl_argv_match(struct dl *dl, const char *pattern)
276 {
277 if (dl_argc(dl) == 0)
278 return false;
279 return strcmpx(dl_argv(dl), pattern) == 0;
280 }
281
282 static bool dl_no_arg(struct dl *dl)
283 {
284 return dl_argc(dl) == 0;
285 }
286
287 static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
288 [DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
289 [DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
290 [DEVLINK_ATTR_PORT_INDEX] = MNL_TYPE_U32,
291 [DEVLINK_ATTR_PORT_TYPE] = MNL_TYPE_U16,
292 [DEVLINK_ATTR_PORT_DESIRED_TYPE] = MNL_TYPE_U16,
293 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX] = MNL_TYPE_U32,
294 [DEVLINK_ATTR_PORT_NETDEV_NAME] = MNL_TYPE_NUL_STRING,
295 [DEVLINK_ATTR_PORT_IBDEV_NAME] = MNL_TYPE_NUL_STRING,
296 [DEVLINK_ATTR_SB_INDEX] = MNL_TYPE_U32,
297 [DEVLINK_ATTR_SB_SIZE] = MNL_TYPE_U32,
298 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] = MNL_TYPE_U16,
299 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] = MNL_TYPE_U16,
300 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT] = MNL_TYPE_U16,
301 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT] = MNL_TYPE_U16,
302 [DEVLINK_ATTR_SB_POOL_INDEX] = MNL_TYPE_U16,
303 [DEVLINK_ATTR_SB_POOL_TYPE] = MNL_TYPE_U8,
304 [DEVLINK_ATTR_SB_POOL_SIZE] = MNL_TYPE_U32,
305 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = MNL_TYPE_U8,
306 [DEVLINK_ATTR_SB_THRESHOLD] = MNL_TYPE_U32,
307 [DEVLINK_ATTR_SB_TC_INDEX] = MNL_TYPE_U16,
308 [DEVLINK_ATTR_SB_OCC_CUR] = MNL_TYPE_U32,
309 [DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
310 [DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
311 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
312 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = MNL_TYPE_U8,
313 [DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED,
314 [DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED,
315 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING,
316 [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = MNL_TYPE_U64,
317 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = MNL_TYPE_NESTED,
318 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = MNL_TYPE_NESTED,
319 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = MNL_TYPE_U8,
320 [DEVLINK_ATTR_DPIPE_ENTRIES] = MNL_TYPE_NESTED,
321 [DEVLINK_ATTR_DPIPE_ENTRY] = MNL_TYPE_NESTED,
322 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = MNL_TYPE_U64,
323 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = MNL_TYPE_NESTED,
324 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = MNL_TYPE_NESTED,
325 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = MNL_TYPE_U64,
326 [DEVLINK_ATTR_DPIPE_MATCH] = MNL_TYPE_NESTED,
327 [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = MNL_TYPE_NESTED,
328 [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = MNL_TYPE_U32,
329 [DEVLINK_ATTR_DPIPE_ACTION] = MNL_TYPE_NESTED,
330 [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = MNL_TYPE_NESTED,
331 [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = MNL_TYPE_U32,
332 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = MNL_TYPE_U32,
333 [DEVLINK_ATTR_DPIPE_HEADERS] = MNL_TYPE_NESTED,
334 [DEVLINK_ATTR_DPIPE_HEADER] = MNL_TYPE_NESTED,
335 [DEVLINK_ATTR_DPIPE_HEADER_NAME] = MNL_TYPE_STRING,
336 [DEVLINK_ATTR_DPIPE_HEADER_ID] = MNL_TYPE_U32,
337 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = MNL_TYPE_NESTED,
338 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = MNL_TYPE_U8,
339 [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = MNL_TYPE_U32,
340 [DEVLINK_ATTR_DPIPE_FIELD] = MNL_TYPE_NESTED,
341 [DEVLINK_ATTR_DPIPE_FIELD_NAME] = MNL_TYPE_STRING,
342 [DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
343 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
344 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
345 };
346
347 static int attr_cb(const struct nlattr *attr, void *data)
348 {
349 const struct nlattr **tb = data;
350 int type;
351
352 if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
353 return MNL_CB_OK;
354
355 type = mnl_attr_get_type(attr);
356 if (mnl_attr_validate(attr, devlink_policy[type]) < 0)
357 return MNL_CB_ERROR;
358
359 tb[type] = attr;
360 return MNL_CB_OK;
361 }
362
363 static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
364 {
365 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
366 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
367 struct dl *dl = data;
368 struct ifname_map *ifname_map;
369 const char *bus_name;
370 const char *dev_name;
371 uint32_t port_ifindex;
372 const char *port_ifname;
373
374 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
375 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
376 !tb[DEVLINK_ATTR_PORT_INDEX])
377 return MNL_CB_ERROR;
378
379 if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
380 return MNL_CB_OK;
381
382 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
383 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
384 port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
385 port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
386 ifname_map = ifname_map_alloc(bus_name, dev_name,
387 port_ifindex, port_ifname);
388 if (!ifname_map)
389 return MNL_CB_ERROR;
390 list_add(&ifname_map->list, &dl->ifname_map_list);
391
392 return MNL_CB_OK;
393 }
394
395 static void ifname_map_fini(struct dl *dl)
396 {
397 struct ifname_map *ifname_map, *tmp;
398
399 list_for_each_entry_safe(ifname_map, tmp,
400 &dl->ifname_map_list, list) {
401 list_del(&ifname_map->list);
402 ifname_map_free(ifname_map);
403 }
404 }
405
406 static int ifname_map_init(struct dl *dl)
407 {
408 struct nlmsghdr *nlh;
409 int err;
410
411 INIT_LIST_HEAD(&dl->ifname_map_list);
412
413 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
414 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
415
416 err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl);
417 if (err) {
418 ifname_map_fini(dl);
419 return err;
420 }
421 return 0;
422 }
423
424 static int ifname_map_lookup(struct dl *dl, const char *ifname,
425 char **p_bus_name, char **p_dev_name,
426 uint32_t *p_port_index)
427 {
428 struct ifname_map *ifname_map;
429
430 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
431 if (strcmp(ifname, ifname_map->ifname) == 0) {
432 *p_bus_name = ifname_map->bus_name;
433 *p_dev_name = ifname_map->dev_name;
434 *p_port_index = ifname_map->port_index;
435 return 0;
436 }
437 }
438 return -ENOENT;
439 }
440
441 static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name,
442 const char *dev_name, uint32_t port_index,
443 char **p_ifname)
444 {
445 struct ifname_map *ifname_map;
446
447 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
448 if (strcmp(bus_name, ifname_map->bus_name) == 0 &&
449 strcmp(dev_name, ifname_map->dev_name) == 0 &&
450 port_index == ifname_map->port_index) {
451 *p_ifname = ifname_map->ifname;
452 return 0;
453 }
454 }
455 return -ENOENT;
456 }
457
458 static unsigned int strslashcount(char *str)
459 {
460 unsigned int count = 0;
461 char *pos = str;
462
463 while ((pos = strchr(pos, '/'))) {
464 count++;
465 pos++;
466 }
467 return count;
468 }
469
470 static int strslashrsplit(char *str, char **before, char **after)
471 {
472 char *slash;
473
474 slash = strrchr(str, '/');
475 if (!slash)
476 return -EINVAL;
477 *slash = '\0';
478 *before = str;
479 *after = slash + 1;
480 return 0;
481 }
482
483 static int strtouint32_t(const char *str, uint32_t *p_val)
484 {
485 char *endptr;
486 unsigned long int val;
487
488 val = strtoul(str, &endptr, 10);
489 if (endptr == str || *endptr != '\0')
490 return -EINVAL;
491 if (val > UINT_MAX)
492 return -ERANGE;
493 *p_val = val;
494 return 0;
495 }
496
497 static int strtouint16_t(const char *str, uint16_t *p_val)
498 {
499 char *endptr;
500 unsigned long int val;
501
502 val = strtoul(str, &endptr, 10);
503 if (endptr == str || *endptr != '\0')
504 return -EINVAL;
505 if (val > USHRT_MAX)
506 return -ERANGE;
507 *p_val = val;
508 return 0;
509 }
510
511 static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
512 {
513 strslashrsplit(str, p_bus_name, p_dev_name);
514 return 0;
515 }
516
517 static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
518 {
519 char *str = dl_argv_next(dl);
520
521 if (!str) {
522 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
523 return -EINVAL;
524 }
525 if (strslashcount(str) != 1) {
526 pr_err("Wrong devlink identification string format.\n");
527 pr_err("Expected \"bus_name/dev_name\".\n");
528 return -EINVAL;
529 }
530 return __dl_argv_handle(str, p_bus_name, p_dev_name);
531 }
532
533 static int __dl_argv_handle_port(char *str,
534 char **p_bus_name, char **p_dev_name,
535 uint32_t *p_port_index)
536 {
537 char *handlestr;
538 char *portstr;
539 int err;
540
541 err = strslashrsplit(str, &handlestr, &portstr);
542 if (err) {
543 pr_err("Port identification \"%s\" is invalid\n", str);
544 return err;
545 }
546 err = strtouint32_t(portstr, p_port_index);
547 if (err) {
548 pr_err("Port index \"%s\" is not a number or not within range\n",
549 portstr);
550 return err;
551 }
552 err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
553 if (err) {
554 pr_err("Port identification \"%s\" is invalid\n", str);
555 return err;
556 }
557 return 0;
558 }
559
560 static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
561 char **p_bus_name, char **p_dev_name,
562 uint32_t *p_port_index)
563 {
564 int err;
565
566 err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
567 p_port_index);
568 if (err) {
569 pr_err("Netdevice \"%s\" not found\n", str);
570 return err;
571 }
572 return 0;
573 }
574
575 static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
576 char **p_dev_name, uint32_t *p_port_index)
577 {
578 char *str = dl_argv_next(dl);
579 unsigned int slash_count;
580
581 if (!str) {
582 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
583 return -EINVAL;
584 }
585 slash_count = strslashcount(str);
586 switch (slash_count) {
587 case 0:
588 return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
589 p_dev_name, p_port_index);
590 case 2:
591 return __dl_argv_handle_port(str, p_bus_name,
592 p_dev_name, p_port_index);
593 default:
594 pr_err("Wrong port identification string format.\n");
595 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
596 return -EINVAL;
597 }
598 }
599
600 static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
601 char **p_dev_name, uint32_t *p_port_index,
602 uint32_t *p_handle_bit)
603 {
604 char *str = dl_argv_next(dl);
605 unsigned int slash_count;
606 int err;
607
608 if (!str) {
609 pr_err("One of following identifications expected:\n"
610 "Devlink identification (\"bus_name/dev_name\")\n"
611 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
612 return -EINVAL;
613 }
614 slash_count = strslashcount(str);
615 if (slash_count == 1) {
616 err = __dl_argv_handle(str, p_bus_name, p_dev_name);
617 if (err)
618 return err;
619 *p_handle_bit = DL_OPT_HANDLE;
620 } else if (slash_count == 2) {
621 err = __dl_argv_handle_port(str, p_bus_name,
622 p_dev_name, p_port_index);
623 if (err)
624 return err;
625 *p_handle_bit = DL_OPT_HANDLEP;
626 } else if (slash_count == 0) {
627 err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
628 p_dev_name, p_port_index);
629 if (err)
630 return err;
631 *p_handle_bit = DL_OPT_HANDLEP;
632 } else {
633 pr_err("Wrong port identification string format.\n");
634 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
635 return -EINVAL;
636 }
637 return 0;
638 }
639
640 static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
641 {
642 char *str = dl_argv_next(dl);
643 int err;
644
645 if (!str) {
646 pr_err("Unsigned number argument expected\n");
647 return -EINVAL;
648 }
649
650 err = strtouint32_t(str, p_val);
651 if (err) {
652 pr_err("\"%s\" is not a number or not within range\n", str);
653 return err;
654 }
655 return 0;
656 }
657
658 static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val)
659 {
660 char *str = dl_argv_next(dl);
661 int err;
662
663 if (!str) {
664 pr_err("Unsigned number argument expected\n");
665 return -EINVAL;
666 }
667
668 err = strtouint16_t(str, p_val);
669 if (err) {
670 pr_err("\"%s\" is not a number or not within range\n", str);
671 return err;
672 }
673 return 0;
674 }
675
676 static int dl_argv_str(struct dl *dl, const char **p_str)
677 {
678 const char *str = dl_argv_next(dl);
679
680 if (!str) {
681 pr_err("String parameter expected\n");
682 return -EINVAL;
683 }
684 *p_str = str;
685 return 0;
686 }
687
688 static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
689 {
690 if (strcmp(typestr, "auto") == 0) {
691 *p_type = DEVLINK_PORT_TYPE_AUTO;
692 } else if (strcmp(typestr, "eth") == 0) {
693 *p_type = DEVLINK_PORT_TYPE_ETH;
694 } else if (strcmp(typestr, "ib") == 0) {
695 *p_type = DEVLINK_PORT_TYPE_IB;
696 } else {
697 pr_err("Unknown port type \"%s\"\n", typestr);
698 return -EINVAL;
699 }
700 return 0;
701 }
702
703 static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type)
704 {
705 if (strcmp(typestr, "ingress") == 0) {
706 *p_type = DEVLINK_SB_POOL_TYPE_INGRESS;
707 } else if (strcmp(typestr, "egress") == 0) {
708 *p_type = DEVLINK_SB_POOL_TYPE_EGRESS;
709 } else {
710 pr_err("Unknown pool type \"%s\"\n", typestr);
711 return -EINVAL;
712 }
713 return 0;
714 }
715
716 static int threshold_type_get(const char *typestr,
717 enum devlink_sb_threshold_type *p_type)
718 {
719 if (strcmp(typestr, "static") == 0) {
720 *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC;
721 } else if (strcmp(typestr, "dynamic") == 0) {
722 *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC;
723 } else {
724 pr_err("Unknown threshold type \"%s\"\n", typestr);
725 return -EINVAL;
726 }
727 return 0;
728 }
729
730 static int eswitch_mode_get(const char *typestr,
731 enum devlink_eswitch_mode *p_mode)
732 {
733 if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) {
734 *p_mode = DEVLINK_ESWITCH_MODE_LEGACY;
735 } else if (strcmp(typestr, ESWITCH_MODE_SWITCHDEV) == 0) {
736 *p_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
737 } else {
738 pr_err("Unknown eswitch mode \"%s\"\n", typestr);
739 return -EINVAL;
740 }
741 return 0;
742 }
743
744 static int eswitch_inline_mode_get(const char *typestr,
745 enum devlink_eswitch_inline_mode *p_mode)
746 {
747 if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) {
748 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
749 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) {
750 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
751 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) {
752 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
753 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) {
754 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
755 } else {
756 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr);
757 return -EINVAL;
758 }
759 return 0;
760 }
761
762 static int dpipe_counters_enable_get(const char *typestr,
763 bool *counters_enable)
764 {
765 if (strcmp(typestr, "enable") == 0) {
766 *counters_enable = 1;
767 } else if (strcmp(typestr, "disable") == 0) {
768 *counters_enable = 0;
769 } else {
770 pr_err("Unknown counter_state \"%s\"\n", typestr);
771 return -EINVAL;
772 }
773 return 0;
774 }
775
776 static int eswitch_encap_mode_get(const char *typestr, bool *p_mode)
777 {
778 if (strcmp(typestr, "enable") == 0) {
779 *p_mode = true;
780 } else if (strcmp(typestr, "disable") == 0) {
781 *p_mode = false;
782 } else {
783 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr);
784 return -EINVAL;
785 }
786 return 0;
787 }
788
789 static int dl_argv_parse(struct dl *dl, uint32_t o_required,
790 uint32_t o_optional)
791 {
792 struct dl_opts *opts = &dl->opts;
793 uint32_t o_all = o_required | o_optional;
794 uint32_t o_found = 0;
795 int err;
796
797 if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
798 uint32_t handle_bit;
799
800 err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
801 &opts->port_index, &handle_bit);
802 if (err)
803 return err;
804 o_found |= handle_bit;
805 } else if (o_required & DL_OPT_HANDLE) {
806 err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
807 if (err)
808 return err;
809 o_found |= DL_OPT_HANDLE;
810 } else if (o_required & DL_OPT_HANDLEP) {
811 err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
812 &opts->port_index);
813 if (err)
814 return err;
815 o_found |= DL_OPT_HANDLEP;
816 }
817
818 while (dl_argc(dl)) {
819 if (dl_argv_match(dl, "type") &&
820 (o_all & DL_OPT_PORT_TYPE)) {
821 const char *typestr;
822
823 dl_arg_inc(dl);
824 err = dl_argv_str(dl, &typestr);
825 if (err)
826 return err;
827 err = port_type_get(typestr, &opts->port_type);
828 if (err)
829 return err;
830 o_found |= DL_OPT_PORT_TYPE;
831 } else if (dl_argv_match(dl, "count") &&
832 (o_all & DL_OPT_PORT_COUNT)) {
833 dl_arg_inc(dl);
834 err = dl_argv_uint32_t(dl, &opts->port_count);
835 if (err)
836 return err;
837 o_found |= DL_OPT_PORT_COUNT;
838 } else if (dl_argv_match(dl, "sb") &&
839 (o_all & DL_OPT_SB)) {
840 dl_arg_inc(dl);
841 err = dl_argv_uint32_t(dl, &opts->sb_index);
842 if (err)
843 return err;
844 o_found |= DL_OPT_SB;
845 } else if (dl_argv_match(dl, "pool") &&
846 (o_all & DL_OPT_SB_POOL)) {
847 dl_arg_inc(dl);
848 err = dl_argv_uint16_t(dl, &opts->sb_pool_index);
849 if (err)
850 return err;
851 o_found |= DL_OPT_SB_POOL;
852 } else if (dl_argv_match(dl, "size") &&
853 (o_all & DL_OPT_SB_SIZE)) {
854 dl_arg_inc(dl);
855 err = dl_argv_uint32_t(dl, &opts->sb_pool_size);
856 if (err)
857 return err;
858 o_found |= DL_OPT_SB_SIZE;
859 } else if (dl_argv_match(dl, "type") &&
860 (o_all & DL_OPT_SB_TYPE)) {
861 const char *typestr;
862
863 dl_arg_inc(dl);
864 err = dl_argv_str(dl, &typestr);
865 if (err)
866 return err;
867 err = pool_type_get(typestr, &opts->sb_pool_type);
868 if (err)
869 return err;
870 o_found |= DL_OPT_SB_TYPE;
871 } else if (dl_argv_match(dl, "thtype") &&
872 (o_all & DL_OPT_SB_THTYPE)) {
873 const char *typestr;
874
875 dl_arg_inc(dl);
876 err = dl_argv_str(dl, &typestr);
877 if (err)
878 return err;
879 err = threshold_type_get(typestr,
880 &opts->sb_pool_thtype);
881 if (err)
882 return err;
883 o_found |= DL_OPT_SB_THTYPE;
884 } else if (dl_argv_match(dl, "th") &&
885 (o_all & DL_OPT_SB_TH)) {
886 dl_arg_inc(dl);
887 err = dl_argv_uint32_t(dl, &opts->sb_threshold);
888 if (err)
889 return err;
890 o_found |= DL_OPT_SB_TH;
891 } else if (dl_argv_match(dl, "tc") &&
892 (o_all & DL_OPT_SB_TC)) {
893 dl_arg_inc(dl);
894 err = dl_argv_uint16_t(dl, &opts->sb_tc_index);
895 if (err)
896 return err;
897 o_found |= DL_OPT_SB_TC;
898 } else if (dl_argv_match(dl, "mode") &&
899 (o_all & DL_OPT_ESWITCH_MODE)) {
900 const char *typestr;
901
902 dl_arg_inc(dl);
903 err = dl_argv_str(dl, &typestr);
904 if (err)
905 return err;
906 err = eswitch_mode_get(typestr, &opts->eswitch_mode);
907 if (err)
908 return err;
909 o_found |= DL_OPT_ESWITCH_MODE;
910 } else if (dl_argv_match(dl, "inline-mode") &&
911 (o_all & DL_OPT_ESWITCH_INLINE_MODE)) {
912 const char *typestr;
913
914 dl_arg_inc(dl);
915 err = dl_argv_str(dl, &typestr);
916 if (err)
917 return err;
918 err = eswitch_inline_mode_get(
919 typestr, &opts->eswitch_inline_mode);
920 if (err)
921 return err;
922 o_found |= DL_OPT_ESWITCH_INLINE_MODE;
923 } else if (dl_argv_match(dl, "name") &&
924 (o_all & DL_OPT_DPIPE_TABLE_NAME)) {
925 dl_arg_inc(dl);
926 err = dl_argv_str(dl, &opts->dpipe_table_name);
927 if (err)
928 return err;
929 o_found |= DL_OPT_DPIPE_TABLE_NAME;
930 } else if (dl_argv_match(dl, "counters") &&
931 (o_all & DL_OPT_DPIPE_TABLE_COUNTERS)) {
932 const char *typestr;
933
934 dl_arg_inc(dl);
935 err = dl_argv_str(dl, &typestr);
936 if (err)
937 return err;
938 err = dpipe_counters_enable_get(typestr,
939 &opts->dpipe_counters_enable);
940 if (err)
941 return err;
942 o_found |= DL_OPT_DPIPE_TABLE_COUNTERS;
943 } else if (dl_argv_match(dl, "encap") &&
944 (o_all & DL_OPT_ESWITCH_ENCAP_MODE)) {
945 const char *typestr;
946
947 dl_arg_inc(dl);
948 err = dl_argv_str(dl, &typestr);
949 if (err)
950 return err;
951 err = eswitch_encap_mode_get(typestr,
952 &opts->eswitch_encap_mode);
953 if (err)
954 return err;
955 o_found |= DL_OPT_ESWITCH_ENCAP_MODE;
956 } else {
957 pr_err("Unknown option \"%s\"\n", dl_argv(dl));
958 return -EINVAL;
959 }
960 }
961
962 opts->present = o_found;
963
964 if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) {
965 opts->sb_index = 0;
966 opts->present |= DL_OPT_SB;
967 }
968
969 if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) {
970 pr_err("Port type option expected.\n");
971 return -EINVAL;
972 }
973
974 if ((o_required & DL_OPT_PORT_COUNT) &&
975 !(o_found & DL_OPT_PORT_COUNT)) {
976 pr_err("Port split count option expected.\n");
977 return -EINVAL;
978 }
979
980 if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) {
981 pr_err("Pool index option expected.\n");
982 return -EINVAL;
983 }
984
985 if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) {
986 pr_err("Pool size option expected.\n");
987 return -EINVAL;
988 }
989
990 if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) {
991 pr_err("Pool type option expected.\n");
992 return -EINVAL;
993 }
994
995 if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) {
996 pr_err("Pool threshold type option expected.\n");
997 return -EINVAL;
998 }
999
1000 if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) {
1001 pr_err("Threshold option expected.\n");
1002 return -EINVAL;
1003 }
1004
1005 if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) {
1006 pr_err("TC index option expected.\n");
1007 return -EINVAL;
1008 }
1009
1010 if ((o_required & DL_OPT_ESWITCH_MODE) &&
1011 !(o_found & DL_OPT_ESWITCH_MODE)) {
1012 pr_err("E-Switch mode option expected.\n");
1013 return -EINVAL;
1014 }
1015
1016 if ((o_required & DL_OPT_ESWITCH_INLINE_MODE) &&
1017 !(o_found & DL_OPT_ESWITCH_INLINE_MODE)) {
1018 pr_err("E-Switch inline-mode option expected.\n");
1019 return -EINVAL;
1020 }
1021
1022 if ((o_required & DL_OPT_DPIPE_TABLE_NAME) &&
1023 !(o_found & DL_OPT_DPIPE_TABLE_NAME)) {
1024 pr_err("Dpipe table name expected\n");
1025 return -EINVAL;
1026 }
1027
1028 if ((o_required & DL_OPT_DPIPE_TABLE_COUNTERS) &&
1029 !(o_found & DL_OPT_DPIPE_TABLE_COUNTERS)) {
1030 pr_err("Dpipe table counter state expected\n");
1031 return -EINVAL;
1032 }
1033
1034 if ((o_required & DL_OPT_ESWITCH_ENCAP_MODE) &&
1035 !(o_found & DL_OPT_ESWITCH_ENCAP_MODE)) {
1036 pr_err("E-Switch encapsulation option expected.\n");
1037 return -EINVAL;
1038 }
1039
1040 return 0;
1041 }
1042
1043 static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
1044 {
1045 struct dl_opts *opts = &dl->opts;
1046
1047 if (opts->present & DL_OPT_HANDLE) {
1048 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1049 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1050 } else if (opts->present & DL_OPT_HANDLEP) {
1051 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1052 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1053 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
1054 opts->port_index);
1055 }
1056 if (opts->present & DL_OPT_PORT_TYPE)
1057 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
1058 opts->port_type);
1059 if (opts->present & DL_OPT_PORT_COUNT)
1060 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
1061 opts->port_count);
1062 if (opts->present & DL_OPT_SB)
1063 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX,
1064 opts->sb_index);
1065 if (opts->present & DL_OPT_SB_POOL)
1066 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX,
1067 opts->sb_pool_index);
1068 if (opts->present & DL_OPT_SB_SIZE)
1069 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE,
1070 opts->sb_pool_size);
1071 if (opts->present & DL_OPT_SB_TYPE)
1072 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE,
1073 opts->sb_pool_type);
1074 if (opts->present & DL_OPT_SB_THTYPE)
1075 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1076 opts->sb_pool_thtype);
1077 if (opts->present & DL_OPT_SB_TH)
1078 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD,
1079 opts->sb_threshold);
1080 if (opts->present & DL_OPT_SB_TC)
1081 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX,
1082 opts->sb_tc_index);
1083 if (opts->present & DL_OPT_ESWITCH_MODE)
1084 mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
1085 opts->eswitch_mode);
1086 if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
1087 mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1088 opts->eswitch_inline_mode);
1089 if (opts->present & DL_OPT_DPIPE_TABLE_NAME)
1090 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME,
1091 opts->dpipe_table_name);
1092 if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS)
1093 mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1094 opts->dpipe_counters_enable);
1095 if (opts->present & DL_OPT_ESWITCH_ENCAP_MODE)
1096 mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE,
1097 opts->eswitch_encap_mode);
1098 }
1099
1100 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
1101 uint32_t o_required, uint32_t o_optional)
1102 {
1103 int err;
1104
1105 err = dl_argv_parse(dl, o_required, o_optional);
1106 if (err)
1107 return err;
1108 dl_opts_put(nlh, dl);
1109 return 0;
1110 }
1111
1112 static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
1113 {
1114 struct dl_opts *opts = &dl->opts;
1115 struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME];
1116 struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME];
1117 struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX];
1118 struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX];
1119
1120 if (opts->present & DL_OPT_HANDLE &&
1121 attr_bus_name && attr_dev_name) {
1122 const char *bus_name = mnl_attr_get_str(attr_bus_name);
1123 const char *dev_name = mnl_attr_get_str(attr_dev_name);
1124
1125 if (strcmp(bus_name, opts->bus_name) != 0 ||
1126 strcmp(dev_name, opts->dev_name) != 0)
1127 return false;
1128 }
1129 if (opts->present & DL_OPT_HANDLEP &&
1130 attr_bus_name && attr_dev_name && attr_port_index) {
1131 const char *bus_name = mnl_attr_get_str(attr_bus_name);
1132 const char *dev_name = mnl_attr_get_str(attr_dev_name);
1133 uint32_t port_index = mnl_attr_get_u32(attr_port_index);
1134
1135 if (strcmp(bus_name, opts->bus_name) != 0 ||
1136 strcmp(dev_name, opts->dev_name) != 0 ||
1137 port_index != opts->port_index)
1138 return false;
1139 }
1140 if (opts->present & DL_OPT_SB && attr_sb_index) {
1141 uint32_t sb_index = mnl_attr_get_u32(attr_sb_index);
1142
1143 if (sb_index != opts->sb_index)
1144 return false;
1145 }
1146 return true;
1147 }
1148
1149 static void cmd_dev_help(void)
1150 {
1151 pr_err("Usage: devlink dev show [ DEV ]\n");
1152 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1153 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
1154 pr_err(" [ encap { disable | enable } ]\n");
1155 pr_err(" devlink dev eswitch show DEV\n");
1156 }
1157
1158 static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
1159 const char *dev_name)
1160 {
1161 if (!dl->arr_last.present)
1162 return false;
1163 return strcmp(dl->arr_last.bus_name, bus_name) == 0 &&
1164 strcmp(dl->arr_last.dev_name, dev_name) == 0;
1165 }
1166
1167 static void arr_last_handle_set(struct dl *dl, const char *bus_name,
1168 const char *dev_name)
1169 {
1170 dl->arr_last.present = true;
1171 free(dl->arr_last.dev_name);
1172 free(dl->arr_last.bus_name);
1173 dl->arr_last.bus_name = strdup(bus_name);
1174 dl->arr_last.dev_name = strdup(dev_name);
1175 }
1176
1177 static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name,
1178 const char *dev_name)
1179 {
1180 return !cmp_arr_last_handle(dl, bus_name, dev_name);
1181 }
1182
1183 static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name,
1184 const char *dev_name)
1185 {
1186 return dl->arr_last.present &&
1187 !cmp_arr_last_handle(dl, bus_name, dev_name);
1188 }
1189
1190 static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb,
1191 bool content, bool array)
1192 {
1193 const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1194 const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1195 char buf[32];
1196
1197 sprintf(buf, "%s/%s", bus_name, dev_name);
1198
1199 if (dl->json_output) {
1200 if (array) {
1201 if (should_arr_last_handle_end(dl, bus_name, dev_name))
1202 jsonw_end_array(dl->jw);
1203 if (should_arr_last_handle_start(dl, bus_name,
1204 dev_name)) {
1205 jsonw_name(dl->jw, buf);
1206 jsonw_start_array(dl->jw);
1207 jsonw_start_object(dl->jw);
1208 arr_last_handle_set(dl, bus_name, dev_name);
1209 } else {
1210 jsonw_start_object(dl->jw);
1211 }
1212 } else {
1213 jsonw_name(dl->jw, buf);
1214 jsonw_start_object(dl->jw);
1215 }
1216 } else {
1217 if (array) {
1218 if (should_arr_last_handle_end(dl, bus_name, dev_name))
1219 __pr_out_indent_dec();
1220 if (should_arr_last_handle_start(dl, bus_name,
1221 dev_name)) {
1222 pr_out("%s%s", buf, content ? ":" : "");
1223 __pr_out_newline();
1224 __pr_out_indent_inc();
1225 arr_last_handle_set(dl, bus_name, dev_name);
1226 }
1227 } else {
1228 pr_out("%s%s", buf, content ? ":" : "");
1229 }
1230 }
1231 }
1232
1233 static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb)
1234 {
1235 __pr_out_handle_start(dl, tb, true, true);
1236 }
1237
1238 static void pr_out_handle_end(struct dl *dl)
1239 {
1240 if (dl->json_output)
1241 jsonw_end_object(dl->jw);
1242 else
1243 __pr_out_newline();
1244 }
1245
1246 static void pr_out_handle(struct dl *dl, struct nlattr **tb)
1247 {
1248 __pr_out_handle_start(dl, tb, false, false);
1249 pr_out_handle_end(dl);
1250 }
1251
1252 static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name,
1253 const char *dev_name, uint32_t port_index)
1254 {
1255 return cmp_arr_last_handle(dl, bus_name, dev_name) &&
1256 dl->arr_last.port_index == port_index;
1257 }
1258
1259 static void arr_last_port_handle_set(struct dl *dl, const char *bus_name,
1260 const char *dev_name, uint32_t port_index)
1261 {
1262 arr_last_handle_set(dl, bus_name, dev_name);
1263 dl->arr_last.port_index = port_index;
1264 }
1265
1266 static bool should_arr_last_port_handle_start(struct dl *dl,
1267 const char *bus_name,
1268 const char *dev_name,
1269 uint32_t port_index)
1270 {
1271 return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
1272 }
1273
1274 static bool should_arr_last_port_handle_end(struct dl *dl,
1275 const char *bus_name,
1276 const char *dev_name,
1277 uint32_t port_index)
1278 {
1279 return dl->arr_last.present &&
1280 !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
1281 }
1282
1283 static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name,
1284 const char *dev_name,
1285 uint32_t port_index, bool try_nice,
1286 bool array)
1287 {
1288 static char buf[32];
1289 char *ifname = NULL;
1290
1291 if (dl->no_nice_names || !try_nice ||
1292 ifname_map_rev_lookup(dl, bus_name, dev_name,
1293 port_index, &ifname) != 0)
1294 sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index);
1295 else
1296 sprintf(buf, "%s", ifname);
1297
1298 if (dl->json_output) {
1299 if (array) {
1300 if (should_arr_last_port_handle_end(dl, bus_name,
1301 dev_name,
1302 port_index))
1303 jsonw_end_array(dl->jw);
1304 if (should_arr_last_port_handle_start(dl, bus_name,
1305 dev_name,
1306 port_index)) {
1307 jsonw_name(dl->jw, buf);
1308 jsonw_start_array(dl->jw);
1309 jsonw_start_object(dl->jw);
1310 arr_last_port_handle_set(dl, bus_name, dev_name,
1311 port_index);
1312 } else {
1313 jsonw_start_object(dl->jw);
1314 }
1315 } else {
1316 jsonw_name(dl->jw, buf);
1317 jsonw_start_object(dl->jw);
1318 }
1319 } else {
1320 pr_out("%s:", buf);
1321 }
1322 }
1323
1324 static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
1325 {
1326 const char *bus_name;
1327 const char *dev_name;
1328 uint32_t port_index;
1329
1330 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1331 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1332 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
1333 __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false);
1334 }
1335
1336 static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice)
1337 {
1338 const char *bus_name;
1339 const char *dev_name;
1340 uint32_t port_index;
1341
1342 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1343 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1344 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
1345 __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true);
1346 }
1347
1348 static void pr_out_port_handle_end(struct dl *dl)
1349 {
1350 if (dl->json_output)
1351 jsonw_end_object(dl->jw);
1352 else
1353 pr_out("\n");
1354 }
1355
1356
1357 static void pr_out_str(struct dl *dl, const char *name, const char *val)
1358 {
1359 if (dl->json_output) {
1360 jsonw_string_field(dl->jw, name, val);
1361 } else {
1362 if (g_indent_newline)
1363 pr_out("%s %s", name, val);
1364 else
1365 pr_out(" %s %s", name, val);
1366 }
1367 }
1368
1369 static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
1370 {
1371 if (dl->json_output) {
1372 jsonw_uint_field(dl->jw, name, val);
1373 } else {
1374 if (g_indent_newline)
1375 pr_out("%s %u", name, val);
1376 else
1377 pr_out(" %s %u", name, val);
1378 }
1379 }
1380
1381 static void pr_out_dev(struct dl *dl, struct nlattr **tb)
1382 {
1383 pr_out_handle(dl, tb);
1384 }
1385
1386 static void pr_out_section_start(struct dl *dl, const char *name)
1387 {
1388 if (dl->json_output) {
1389 jsonw_start_object(dl->jw);
1390 jsonw_name(dl->jw, name);
1391 jsonw_start_object(dl->jw);
1392 }
1393 }
1394
1395 static void pr_out_section_end(struct dl *dl)
1396 {
1397 if (dl->json_output) {
1398 if (dl->arr_last.present)
1399 jsonw_end_array(dl->jw);
1400 jsonw_end_object(dl->jw);
1401 jsonw_end_object(dl->jw);
1402 }
1403 }
1404
1405 static void pr_out_array_start(struct dl *dl, const char *name)
1406 {
1407 if (dl->json_output) {
1408 jsonw_name(dl->jw, name);
1409 jsonw_start_array(dl->jw);
1410 } else {
1411 __pr_out_indent_inc();
1412 __pr_out_newline();
1413 pr_out("%s:", name);
1414 __pr_out_indent_inc();
1415 __pr_out_newline();
1416 }
1417 }
1418
1419 static void pr_out_array_end(struct dl *dl)
1420 {
1421 if (dl->json_output) {
1422 jsonw_end_array(dl->jw);
1423 } else {
1424 __pr_out_indent_dec();
1425 __pr_out_indent_dec();
1426 }
1427 }
1428
1429 static void pr_out_entry_start(struct dl *dl)
1430 {
1431 if (dl->json_output)
1432 jsonw_start_object(dl->jw);
1433 }
1434
1435 static void pr_out_entry_end(struct dl *dl)
1436 {
1437 if (dl->json_output)
1438 jsonw_end_object(dl->jw);
1439 else
1440 __pr_out_newline();
1441 }
1442
1443 static const char *eswitch_mode_name(uint32_t mode)
1444 {
1445 switch (mode) {
1446 case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY;
1447 case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV;
1448 default: return "<unknown mode>";
1449 }
1450 }
1451
1452 static const char *eswitch_inline_mode_name(uint32_t mode)
1453 {
1454 switch (mode) {
1455 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1456 return ESWITCH_INLINE_MODE_NONE;
1457 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1458 return ESWITCH_INLINE_MODE_LINK;
1459 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1460 return ESWITCH_INLINE_MODE_NETWORK;
1461 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1462 return ESWITCH_INLINE_MODE_TRANSPORT;
1463 default:
1464 return "<unknown mode>";
1465 }
1466 }
1467
1468 static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
1469 {
1470 __pr_out_handle_start(dl, tb, true, false);
1471
1472 if (tb[DEVLINK_ATTR_ESWITCH_MODE])
1473 pr_out_str(dl, "mode",
1474 eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE])));
1475
1476 if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])
1477 pr_out_str(dl, "inline-mode",
1478 eswitch_inline_mode_name(mnl_attr_get_u8(
1479 tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
1480
1481 if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1482 bool encap_mode = !!mnl_attr_get_u8(tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
1483
1484 pr_out_str(dl, "encap", encap_mode ? "enable" : "disable");
1485 }
1486
1487 pr_out_handle_end(dl);
1488 }
1489
1490 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data)
1491 {
1492 struct dl *dl = data;
1493 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1494 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1495
1496 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1497 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
1498 return MNL_CB_ERROR;
1499 pr_out_eswitch(dl, tb);
1500 return MNL_CB_OK;
1501 }
1502
1503 static int cmd_dev_eswitch_show(struct dl *dl)
1504 {
1505 struct nlmsghdr *nlh;
1506 int err;
1507
1508 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_GET,
1509 NLM_F_REQUEST | NLM_F_ACK);
1510
1511 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
1512 if (err)
1513 return err;
1514
1515 pr_out_section_start(dl, "dev");
1516 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl);
1517 pr_out_section_end(dl);
1518 return err;
1519 }
1520
1521 static int cmd_dev_eswitch_set(struct dl *dl)
1522 {
1523 struct nlmsghdr *nlh;
1524 int err;
1525
1526 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_SET,
1527 NLM_F_REQUEST | NLM_F_ACK);
1528
1529 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
1530 DL_OPT_ESWITCH_MODE |
1531 DL_OPT_ESWITCH_INLINE_MODE |
1532 DL_OPT_ESWITCH_ENCAP_MODE);
1533
1534 if (err)
1535 return err;
1536
1537 if (dl->opts.present == 1) {
1538 pr_err("Need to set at least one option\n");
1539 return -ENOENT;
1540 }
1541
1542 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1543 }
1544
1545 static int cmd_dev_eswitch(struct dl *dl)
1546 {
1547 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1548 cmd_dev_help();
1549 return 0;
1550 } else if (dl_argv_match(dl, "set")) {
1551 dl_arg_inc(dl);
1552 return cmd_dev_eswitch_set(dl);
1553 } else if (dl_argv_match(dl, "show")) {
1554 dl_arg_inc(dl);
1555 return cmd_dev_eswitch_show(dl);
1556 }
1557 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1558 return -ENOENT;
1559 }
1560
1561 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
1562 {
1563 struct dl *dl = data;
1564 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1565 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1566
1567 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1568 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
1569 return MNL_CB_ERROR;
1570 pr_out_dev(dl, tb);
1571 return MNL_CB_OK;
1572 }
1573
1574 static int cmd_dev_show(struct dl *dl)
1575 {
1576 struct nlmsghdr *nlh;
1577 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1578 int err;
1579
1580 if (dl_argc(dl) == 0)
1581 flags |= NLM_F_DUMP;
1582
1583 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
1584
1585 if (dl_argc(dl) > 0) {
1586 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
1587 if (err)
1588 return err;
1589 }
1590
1591 pr_out_section_start(dl, "dev");
1592 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl);
1593 pr_out_section_end(dl);
1594 return err;
1595 }
1596
1597 static int cmd_dev(struct dl *dl)
1598 {
1599 if (dl_argv_match(dl, "help")) {
1600 cmd_dev_help();
1601 return 0;
1602 } else if (dl_argv_match(dl, "show") ||
1603 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1604 dl_arg_inc(dl);
1605 return cmd_dev_show(dl);
1606 } else if (dl_argv_match(dl, "eswitch")) {
1607 dl_arg_inc(dl);
1608 return cmd_dev_eswitch(dl);
1609 }
1610 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1611 return -ENOENT;
1612 }
1613
1614 static void cmd_port_help(void)
1615 {
1616 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
1617 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
1618 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
1619 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
1620 }
1621
1622 static const char *port_type_name(uint32_t type)
1623 {
1624 switch (type) {
1625 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
1626 case DEVLINK_PORT_TYPE_AUTO: return "auto";
1627 case DEVLINK_PORT_TYPE_ETH: return "eth";
1628 case DEVLINK_PORT_TYPE_IB: return "ib";
1629 default: return "<unknown type>";
1630 }
1631 }
1632
1633 static void pr_out_port(struct dl *dl, struct nlattr **tb)
1634 {
1635 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
1636 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
1637
1638 pr_out_port_handle_start(dl, tb, false);
1639 if (pt_attr) {
1640 uint16_t port_type = mnl_attr_get_u16(pt_attr);
1641
1642 pr_out_str(dl, "type", port_type_name(port_type));
1643 if (dpt_attr) {
1644 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
1645
1646 if (port_type != des_port_type)
1647 pr_out_str(dl, "des_type",
1648 port_type_name(des_port_type));
1649 }
1650 }
1651 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
1652 pr_out_str(dl, "netdev",
1653 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
1654 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
1655 pr_out_str(dl, "ibdev",
1656 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
1657 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
1658 pr_out_uint(dl, "split_group",
1659 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
1660 pr_out_port_handle_end(dl);
1661 }
1662
1663 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
1664 {
1665 struct dl *dl = data;
1666 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1667 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1668
1669 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1670 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1671 !tb[DEVLINK_ATTR_PORT_INDEX])
1672 return MNL_CB_ERROR;
1673 pr_out_port(dl, tb);
1674 return MNL_CB_OK;
1675 }
1676
1677 static int cmd_port_show(struct dl *dl)
1678 {
1679 struct nlmsghdr *nlh;
1680 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1681 int err;
1682
1683 if (dl_argc(dl) == 0)
1684 flags |= NLM_F_DUMP;
1685
1686 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
1687
1688 if (dl_argc(dl) > 0) {
1689 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1690 if (err)
1691 return err;
1692 }
1693
1694 pr_out_section_start(dl, "port");
1695 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
1696 pr_out_section_end(dl);
1697 return err;
1698 }
1699
1700 static int cmd_port_set(struct dl *dl)
1701 {
1702 struct nlmsghdr *nlh;
1703 int err;
1704
1705 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
1706 NLM_F_REQUEST | NLM_F_ACK);
1707
1708 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
1709 if (err)
1710 return err;
1711
1712 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1713 }
1714
1715 static int cmd_port_split(struct dl *dl)
1716 {
1717 struct nlmsghdr *nlh;
1718 int err;
1719
1720 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
1721 NLM_F_REQUEST | NLM_F_ACK);
1722
1723 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
1724 if (err)
1725 return err;
1726
1727 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1728 }
1729
1730 static int cmd_port_unsplit(struct dl *dl)
1731 {
1732 struct nlmsghdr *nlh;
1733 int err;
1734
1735 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
1736 NLM_F_REQUEST | NLM_F_ACK);
1737
1738 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1739 if (err)
1740 return err;
1741
1742 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1743 }
1744
1745 static int cmd_port(struct dl *dl)
1746 {
1747 if (dl_argv_match(dl, "help")) {
1748 cmd_port_help();
1749 return 0;
1750 } else if (dl_argv_match(dl, "show") ||
1751 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1752 dl_arg_inc(dl);
1753 return cmd_port_show(dl);
1754 } else if (dl_argv_match(dl, "set")) {
1755 dl_arg_inc(dl);
1756 return cmd_port_set(dl);
1757 } else if (dl_argv_match(dl, "split")) {
1758 dl_arg_inc(dl);
1759 return cmd_port_split(dl);
1760 } else if (dl_argv_match(dl, "unsplit")) {
1761 dl_arg_inc(dl);
1762 return cmd_port_unsplit(dl);
1763 }
1764 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1765 return -ENOENT;
1766 }
1767
1768 static void cmd_sb_help(void)
1769 {
1770 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
1771 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
1772 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
1773 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
1774 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1775 pr_err(" pool POOL_INDEX ]\n");
1776 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1777 pr_err(" pool POOL_INDEX th THRESHOLD\n");
1778 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1779 pr_err(" type { ingress | egress } ]\n");
1780 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1781 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
1782 pr_err(" th THRESHOLD\n");
1783 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
1784 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
1785 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
1786 }
1787
1788 static void pr_out_sb(struct dl *dl, struct nlattr **tb)
1789 {
1790 pr_out_handle_start_arr(dl, tb);
1791 pr_out_uint(dl, "sb",
1792 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1793 pr_out_uint(dl, "size",
1794 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
1795 pr_out_uint(dl, "ing_pools",
1796 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
1797 pr_out_uint(dl, "eg_pools",
1798 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
1799 pr_out_uint(dl, "ing_tcs",
1800 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
1801 pr_out_uint(dl, "eg_tcs",
1802 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
1803 pr_out_handle_end(dl);
1804 }
1805
1806 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
1807 {
1808 struct dl *dl = data;
1809 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1810 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1811
1812 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1813 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1814 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
1815 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
1816 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
1817 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
1818 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
1819 return MNL_CB_ERROR;
1820 pr_out_sb(dl, tb);
1821 return MNL_CB_OK;
1822 }
1823
1824 static int cmd_sb_show(struct dl *dl)
1825 {
1826 struct nlmsghdr *nlh;
1827 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1828 int err;
1829
1830 if (dl_argc(dl) == 0)
1831 flags |= NLM_F_DUMP;
1832
1833 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
1834
1835 if (dl_argc(dl) > 0) {
1836 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
1837 if (err)
1838 return err;
1839 }
1840
1841 pr_out_section_start(dl, "sb");
1842 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl);
1843 pr_out_section_end(dl);
1844 return err;
1845 }
1846
1847 static const char *pool_type_name(uint8_t type)
1848 {
1849 switch (type) {
1850 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
1851 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
1852 default: return "<unknown type>";
1853 }
1854 }
1855
1856 static const char *threshold_type_name(uint8_t type)
1857 {
1858 switch (type) {
1859 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
1860 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
1861 default: return "<unknown type>";
1862 }
1863 }
1864
1865 static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
1866 {
1867 pr_out_handle_start_arr(dl, tb);
1868 pr_out_uint(dl, "sb",
1869 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1870 pr_out_uint(dl, "pool",
1871 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
1872 pr_out_str(dl, "type",
1873 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
1874 pr_out_uint(dl, "size",
1875 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
1876 pr_out_str(dl, "thtype",
1877 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
1878 pr_out_handle_end(dl);
1879 }
1880
1881 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1882 {
1883 struct dl *dl = data;
1884 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1885 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1886
1887 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1888 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1889 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
1890 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
1891 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
1892 return MNL_CB_ERROR;
1893 pr_out_sb_pool(dl, tb);
1894 return MNL_CB_OK;
1895 }
1896
1897 static int cmd_sb_pool_show(struct dl *dl)
1898 {
1899 struct nlmsghdr *nlh;
1900 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1901 int err;
1902
1903 if (dl_argc(dl) == 0)
1904 flags |= NLM_F_DUMP;
1905
1906 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
1907
1908 if (dl_argc(dl) > 0) {
1909 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
1910 DL_OPT_SB);
1911 if (err)
1912 return err;
1913 }
1914
1915 pr_out_section_start(dl, "pool");
1916 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
1917 pr_out_section_end(dl);
1918 return err;
1919 }
1920
1921 static int cmd_sb_pool_set(struct dl *dl)
1922 {
1923 struct nlmsghdr *nlh;
1924 int err;
1925
1926 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
1927 NLM_F_REQUEST | NLM_F_ACK);
1928
1929 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
1930 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
1931 if (err)
1932 return err;
1933
1934 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1935 }
1936
1937 static int cmd_sb_pool(struct dl *dl)
1938 {
1939 if (dl_argv_match(dl, "help")) {
1940 cmd_sb_help();
1941 return 0;
1942 } else if (dl_argv_match(dl, "show") ||
1943 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1944 dl_arg_inc(dl);
1945 return cmd_sb_pool_show(dl);
1946 } else if (dl_argv_match(dl, "set")) {
1947 dl_arg_inc(dl);
1948 return cmd_sb_pool_set(dl);
1949 }
1950 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1951 return -ENOENT;
1952 }
1953
1954 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
1955 {
1956 pr_out_port_handle_start_arr(dl, tb, true);
1957 pr_out_uint(dl, "sb",
1958 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1959 pr_out_uint(dl, "pool",
1960 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
1961 pr_out_uint(dl, "threshold",
1962 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
1963 pr_out_port_handle_end(dl);
1964 }
1965
1966 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1967 {
1968 struct dl *dl = data;
1969 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1970 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1971
1972 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1973 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1974 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1975 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
1976 return MNL_CB_ERROR;
1977 pr_out_sb_port_pool(dl, tb);
1978 return MNL_CB_OK;
1979 }
1980
1981 static int cmd_sb_port_pool_show(struct dl *dl)
1982 {
1983 struct nlmsghdr *nlh;
1984 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1985 int err;
1986
1987 if (dl_argc(dl) == 0)
1988 flags |= NLM_F_DUMP;
1989
1990 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
1991
1992 if (dl_argc(dl) > 0) {
1993 err = dl_argv_parse_put(nlh, dl,
1994 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
1995 DL_OPT_SB);
1996 if (err)
1997 return err;
1998 }
1999
2000 pr_out_section_start(dl, "port_pool");
2001 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
2002 pr_out_section_end(dl);
2003 return 0;
2004 }
2005
2006 static int cmd_sb_port_pool_set(struct dl *dl)
2007 {
2008 struct nlmsghdr *nlh;
2009 int err;
2010
2011 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
2012 NLM_F_REQUEST | NLM_F_ACK);
2013
2014 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
2015 DL_OPT_SB_TH, DL_OPT_SB);
2016 if (err)
2017 return err;
2018
2019 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2020 }
2021
2022 static int cmd_sb_port_pool(struct dl *dl)
2023 {
2024 if (dl_argv_match(dl, "help")) {
2025 cmd_sb_help();
2026 return 0;
2027 } else if (dl_argv_match(dl, "show") ||
2028 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2029 dl_arg_inc(dl);
2030 return cmd_sb_port_pool_show(dl);
2031 } else if (dl_argv_match(dl, "set")) {
2032 dl_arg_inc(dl);
2033 return cmd_sb_port_pool_set(dl);
2034 }
2035 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2036 return -ENOENT;
2037 }
2038
2039 static int cmd_sb_port(struct dl *dl)
2040 {
2041 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2042 cmd_sb_help();
2043 return 0;
2044 } else if (dl_argv_match(dl, "pool")) {
2045 dl_arg_inc(dl);
2046 return cmd_sb_port_pool(dl);
2047 }
2048 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2049 return -ENOENT;
2050 }
2051
2052 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
2053 {
2054 pr_out_port_handle_start_arr(dl, tb, true);
2055 pr_out_uint(dl, "sb",
2056 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
2057 pr_out_uint(dl, "tc",
2058 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
2059 pr_out_str(dl, "type",
2060 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
2061 pr_out_uint(dl, "pool",
2062 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
2063 pr_out_uint(dl, "threshold",
2064 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
2065 pr_out_port_handle_end(dl);
2066 }
2067
2068 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
2069 {
2070 struct dl *dl = data;
2071 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2072 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2073
2074 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2075 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2076 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2077 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
2078 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
2079 return MNL_CB_ERROR;
2080 pr_out_sb_tc_bind(dl, tb);
2081 return MNL_CB_OK;
2082 }
2083
2084 static int cmd_sb_tc_bind_show(struct dl *dl)
2085 {
2086 struct nlmsghdr *nlh;
2087 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2088 int err;
2089
2090 if (dl_argc(dl) == 0)
2091 flags |= NLM_F_DUMP;
2092
2093 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
2094
2095 if (dl_argc(dl) > 0) {
2096 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
2097 DL_OPT_SB_TYPE, DL_OPT_SB);
2098 if (err)
2099 return err;
2100 }
2101
2102 pr_out_section_start(dl, "tc_bind");
2103 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
2104 pr_out_section_end(dl);
2105 return err;
2106 }
2107
2108 static int cmd_sb_tc_bind_set(struct dl *dl)
2109 {
2110 struct nlmsghdr *nlh;
2111 int err;
2112
2113 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
2114 NLM_F_REQUEST | NLM_F_ACK);
2115
2116 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
2117 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
2118 DL_OPT_SB);
2119 if (err)
2120 return err;
2121
2122 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2123 }
2124
2125 static int cmd_sb_tc_bind(struct dl *dl)
2126 {
2127 if (dl_argv_match(dl, "help")) {
2128 cmd_sb_help();
2129 return 0;
2130 } else if (dl_argv_match(dl, "show") ||
2131 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2132 dl_arg_inc(dl);
2133 return cmd_sb_tc_bind_show(dl);
2134 } else if (dl_argv_match(dl, "set")) {
2135 dl_arg_inc(dl);
2136 return cmd_sb_tc_bind_set(dl);
2137 }
2138 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2139 return -ENOENT;
2140 }
2141
2142 static int cmd_sb_tc(struct dl *dl)
2143 {
2144 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2145 cmd_sb_help();
2146 return 0;
2147 } else if (dl_argv_match(dl, "bind")) {
2148 dl_arg_inc(dl);
2149 return cmd_sb_tc_bind(dl);
2150 }
2151 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2152 return -ENOENT;
2153 }
2154
2155 struct occ_item {
2156 struct list_head list;
2157 uint32_t index;
2158 uint32_t cur;
2159 uint32_t max;
2160 uint32_t bound_pool_index;
2161 };
2162
2163 struct occ_port {
2164 struct list_head list;
2165 char *bus_name;
2166 char *dev_name;
2167 uint32_t port_index;
2168 uint32_t sb_index;
2169 struct list_head pool_list;
2170 struct list_head ing_tc_list;
2171 struct list_head eg_tc_list;
2172 };
2173
2174 struct occ_show {
2175 struct dl *dl;
2176 int err;
2177 struct list_head port_list;
2178 };
2179
2180 static struct occ_item *occ_item_alloc(void)
2181 {
2182 return calloc(1, sizeof(struct occ_item));
2183 }
2184
2185 static void occ_item_free(struct occ_item *occ_item)
2186 {
2187 free(occ_item);
2188 }
2189
2190 static struct occ_port *occ_port_alloc(uint32_t port_index)
2191 {
2192 struct occ_port *occ_port;
2193
2194 occ_port = calloc(1, sizeof(*occ_port));
2195 if (!occ_port)
2196 return NULL;
2197 occ_port->port_index = port_index;
2198 INIT_LIST_HEAD(&occ_port->pool_list);
2199 INIT_LIST_HEAD(&occ_port->ing_tc_list);
2200 INIT_LIST_HEAD(&occ_port->eg_tc_list);
2201 return occ_port;
2202 }
2203
2204 static void occ_port_free(struct occ_port *occ_port)
2205 {
2206 struct occ_item *occ_item, *tmp;
2207
2208 list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
2209 occ_item_free(occ_item);
2210 list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
2211 occ_item_free(occ_item);
2212 list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
2213 occ_item_free(occ_item);
2214 }
2215
2216 static struct occ_show *occ_show_alloc(struct dl *dl)
2217 {
2218 struct occ_show *occ_show;
2219
2220 occ_show = calloc(1, sizeof(*occ_show));
2221 if (!occ_show)
2222 return NULL;
2223 occ_show->dl = dl;
2224 INIT_LIST_HEAD(&occ_show->port_list);
2225 return occ_show;
2226 }
2227
2228 static void occ_show_free(struct occ_show *occ_show)
2229 {
2230 struct occ_port *occ_port, *tmp;
2231
2232 list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
2233 occ_port_free(occ_port);
2234 }
2235
2236 static struct occ_port *occ_port_get(struct occ_show *occ_show,
2237 struct nlattr **tb)
2238 {
2239 struct occ_port *occ_port;
2240 uint32_t port_index;
2241
2242 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2243
2244 list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
2245 if (occ_port->port_index == port_index)
2246 return occ_port;
2247 }
2248 occ_port = occ_port_alloc(port_index);
2249 if (!occ_port)
2250 return NULL;
2251 list_add_tail(&occ_port->list, &occ_show->port_list);
2252 return occ_port;
2253 }
2254
2255 static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
2256 bool bound_pool)
2257 {
2258 struct occ_item *occ_item;
2259 int i = 1;
2260
2261 pr_out_sp(7, " %s:", label);
2262 list_for_each_entry(occ_item, list, list) {
2263 if ((i - 1) % 4 == 0 && i != 1)
2264 pr_out_sp(7, " ");
2265 if (bound_pool)
2266 pr_out_sp(7, "%2u(%u):", occ_item->index,
2267 occ_item->bound_pool_index);
2268 else
2269 pr_out_sp(7, "%2u:", occ_item->index);
2270 pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max);
2271 if (i++ % 4 == 0)
2272 pr_out("\n");
2273 }
2274 if ((i - 1) % 4 != 0)
2275 pr_out("\n");
2276 }
2277
2278 static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
2279 struct list_head *list,
2280 bool bound_pool)
2281 {
2282 struct occ_item *occ_item;
2283 char buf[32];
2284
2285 jsonw_name(dl->jw, label);
2286 jsonw_start_object(dl->jw);
2287 list_for_each_entry(occ_item, list, list) {
2288 sprintf(buf, "%u", occ_item->index);
2289 jsonw_name(dl->jw, buf);
2290 jsonw_start_object(dl->jw);
2291 if (bound_pool)
2292 jsonw_uint_field(dl->jw, "bound_pool",
2293 occ_item->bound_pool_index);
2294 jsonw_uint_field(dl->jw, "current", occ_item->cur);
2295 jsonw_uint_field(dl->jw, "max", occ_item->max);
2296 jsonw_end_object(dl->jw);
2297 }
2298 jsonw_end_object(dl->jw);
2299 }
2300
2301 static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
2302 {
2303 if (dl->json_output) {
2304 pr_out_json_occ_show_item_list(dl, "pool",
2305 &occ_port->pool_list, false);
2306 pr_out_json_occ_show_item_list(dl, "itc",
2307 &occ_port->ing_tc_list, true);
2308 pr_out_json_occ_show_item_list(dl, "etc",
2309 &occ_port->eg_tc_list, true);
2310 } else {
2311 pr_out("\n");
2312 pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
2313 pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
2314 pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
2315 }
2316 }
2317
2318 static void pr_out_occ_show(struct occ_show *occ_show)
2319 {
2320 struct dl *dl = occ_show->dl;
2321 struct dl_opts *opts = &dl->opts;
2322 struct occ_port *occ_port;
2323
2324 list_for_each_entry(occ_port, &occ_show->port_list, list) {
2325 __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
2326 occ_port->port_index, true, false);
2327 pr_out_occ_show_port(dl, occ_port);
2328 pr_out_port_handle_end(dl);
2329 }
2330 }
2331
2332 static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
2333 struct nlattr **tb)
2334 {
2335 struct occ_port *occ_port;
2336 struct occ_item *occ_item;
2337
2338 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
2339 return;
2340
2341 occ_port = occ_port_get(occ_show, tb);
2342 if (!occ_port) {
2343 occ_show->err = -ENOMEM;
2344 return;
2345 }
2346
2347 occ_item = occ_item_alloc();
2348 if (!occ_item) {
2349 occ_show->err = -ENOMEM;
2350 return;
2351 }
2352 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
2353 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
2354 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
2355 list_add_tail(&occ_item->list, &occ_port->pool_list);
2356 }
2357
2358 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
2359 {
2360 struct occ_show *occ_show = data;
2361 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2362 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2363
2364 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2365 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2366 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2367 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
2368 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
2369 return MNL_CB_ERROR;
2370 cmd_sb_occ_port_pool_process(occ_show, tb);
2371 return MNL_CB_OK;
2372 }
2373
2374 static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
2375 struct nlattr **tb)
2376 {
2377 struct occ_port *occ_port;
2378 struct occ_item *occ_item;
2379 uint8_t pool_type;
2380
2381 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
2382 return;
2383
2384 occ_port = occ_port_get(occ_show, tb);
2385 if (!occ_port) {
2386 occ_show->err = -ENOMEM;
2387 return;
2388 }
2389
2390 occ_item = occ_item_alloc();
2391 if (!occ_item) {
2392 occ_show->err = -ENOMEM;
2393 return;
2394 }
2395 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
2396 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
2397 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
2398 occ_item->bound_pool_index =
2399 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
2400 pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
2401 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
2402 list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
2403 else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
2404 list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
2405 else
2406 occ_item_free(occ_item);
2407 }
2408
2409 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
2410 {
2411 struct occ_show *occ_show = data;
2412 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2413 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2414
2415 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2416 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2417 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2418 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
2419 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
2420 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
2421 return MNL_CB_ERROR;
2422 cmd_sb_occ_tc_pool_process(occ_show, tb);
2423 return MNL_CB_OK;
2424 }
2425
2426 static int cmd_sb_occ_show(struct dl *dl)
2427 {
2428 struct nlmsghdr *nlh;
2429 struct occ_show *occ_show;
2430 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
2431 int err;
2432
2433 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
2434 if (err)
2435 return err;
2436
2437 occ_show = occ_show_alloc(dl);
2438 if (!occ_show)
2439 return -ENOMEM;
2440
2441 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
2442
2443 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
2444 cmd_sb_occ_port_pool_process_cb, occ_show);
2445 if (err)
2446 goto out;
2447
2448 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
2449
2450 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
2451 cmd_sb_occ_tc_pool_process_cb, occ_show);
2452 if (err)
2453 goto out;
2454
2455 pr_out_section_start(dl, "occupancy");
2456 pr_out_occ_show(occ_show);
2457 pr_out_section_end(dl);
2458
2459 out:
2460 occ_show_free(occ_show);
2461 return err;
2462 }
2463
2464 static int cmd_sb_occ_snapshot(struct dl *dl)
2465 {
2466 struct nlmsghdr *nlh;
2467 int err;
2468
2469 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
2470 NLM_F_REQUEST | NLM_F_ACK);
2471
2472 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
2473 if (err)
2474 return err;
2475
2476 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2477 }
2478
2479 static int cmd_sb_occ_clearmax(struct dl *dl)
2480 {
2481 struct nlmsghdr *nlh;
2482 int err;
2483
2484 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
2485 NLM_F_REQUEST | NLM_F_ACK);
2486
2487 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
2488 if (err)
2489 return err;
2490
2491 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2492 }
2493
2494 static int cmd_sb_occ(struct dl *dl)
2495 {
2496 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2497 cmd_sb_help();
2498 return 0;
2499 } else if (dl_argv_match(dl, "show") ||
2500 dl_argv_match(dl, "list")) {
2501 dl_arg_inc(dl);
2502 return cmd_sb_occ_show(dl);
2503 } else if (dl_argv_match(dl, "snapshot")) {
2504 dl_arg_inc(dl);
2505 return cmd_sb_occ_snapshot(dl);
2506 } else if (dl_argv_match(dl, "clearmax")) {
2507 dl_arg_inc(dl);
2508 return cmd_sb_occ_clearmax(dl);
2509 }
2510 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2511 return -ENOENT;
2512 }
2513
2514 static int cmd_sb(struct dl *dl)
2515 {
2516 if (dl_argv_match(dl, "help")) {
2517 cmd_sb_help();
2518 return 0;
2519 } else if (dl_argv_match(dl, "show") ||
2520 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2521 dl_arg_inc(dl);
2522 return cmd_sb_show(dl);
2523 } else if (dl_argv_match(dl, "pool")) {
2524 dl_arg_inc(dl);
2525 return cmd_sb_pool(dl);
2526 } else if (dl_argv_match(dl, "port")) {
2527 dl_arg_inc(dl);
2528 return cmd_sb_port(dl);
2529 } else if (dl_argv_match(dl, "tc")) {
2530 dl_arg_inc(dl);
2531 return cmd_sb_tc(dl);
2532 } else if (dl_argv_match(dl, "occupancy")) {
2533 dl_arg_inc(dl);
2534 return cmd_sb_occ(dl);
2535 }
2536 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2537 return -ENOENT;
2538 }
2539
2540 static const char *cmd_name(uint8_t cmd)
2541 {
2542 switch (cmd) {
2543 case DEVLINK_CMD_UNSPEC: return "unspec";
2544 case DEVLINK_CMD_GET: return "get";
2545 case DEVLINK_CMD_SET: return "set";
2546 case DEVLINK_CMD_NEW: return "new";
2547 case DEVLINK_CMD_DEL: return "del";
2548 case DEVLINK_CMD_PORT_GET: return "get";
2549 case DEVLINK_CMD_PORT_SET: return "set";
2550 case DEVLINK_CMD_PORT_NEW: return "net";
2551 case DEVLINK_CMD_PORT_DEL: return "del";
2552 default: return "<unknown cmd>";
2553 }
2554 }
2555
2556 static const char *cmd_obj(uint8_t cmd)
2557 {
2558 switch (cmd) {
2559 case DEVLINK_CMD_UNSPEC: return "unspec";
2560 case DEVLINK_CMD_GET:
2561 case DEVLINK_CMD_SET:
2562 case DEVLINK_CMD_NEW:
2563 case DEVLINK_CMD_DEL:
2564 return "dev";
2565 case DEVLINK_CMD_PORT_GET:
2566 case DEVLINK_CMD_PORT_SET:
2567 case DEVLINK_CMD_PORT_NEW:
2568 case DEVLINK_CMD_PORT_DEL:
2569 return "port";
2570 default: return "<unknown obj>";
2571 }
2572 }
2573
2574 static void pr_out_mon_header(uint8_t cmd)
2575 {
2576 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
2577 }
2578
2579 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
2580 {
2581 const char *obj = cmd_obj(cmd);
2582 unsigned int index = 0;
2583 const char *cur_obj;
2584
2585 if (dl_no_arg(dl))
2586 return true;
2587 while ((cur_obj = dl_argv_index(dl, index++))) {
2588 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
2589 return true;
2590 }
2591 return false;
2592 }
2593
2594 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
2595 {
2596 struct dl *dl = data;
2597 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2598 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2599 uint8_t cmd = genl->cmd;
2600
2601 if (!cmd_filter_check(dl, cmd))
2602 return MNL_CB_OK;
2603
2604 switch (cmd) {
2605 case DEVLINK_CMD_GET: /* fall through */
2606 case DEVLINK_CMD_SET: /* fall through */
2607 case DEVLINK_CMD_NEW: /* fall through */
2608 case DEVLINK_CMD_DEL:
2609 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2610 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2611 return MNL_CB_ERROR;
2612 pr_out_mon_header(genl->cmd);
2613 pr_out_dev(dl, tb);
2614 break;
2615 case DEVLINK_CMD_PORT_GET: /* fall through */
2616 case DEVLINK_CMD_PORT_SET: /* fall through */
2617 case DEVLINK_CMD_PORT_NEW: /* fall through */
2618 case DEVLINK_CMD_PORT_DEL:
2619 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2620 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2621 !tb[DEVLINK_ATTR_PORT_INDEX])
2622 return MNL_CB_ERROR;
2623 pr_out_mon_header(genl->cmd);
2624 pr_out_port(dl, tb);
2625 break;
2626 }
2627 return MNL_CB_OK;
2628 }
2629
2630 static int cmd_mon_show(struct dl *dl)
2631 {
2632 int err;
2633 unsigned int index = 0;
2634 const char *cur_obj;
2635
2636 while ((cur_obj = dl_argv_index(dl, index++))) {
2637 if (strcmp(cur_obj, "all") != 0 &&
2638 strcmp(cur_obj, "dev") != 0 &&
2639 strcmp(cur_obj, "port") != 0) {
2640 pr_err("Unknown object \"%s\"\n", cur_obj);
2641 return -EINVAL;
2642 }
2643 }
2644 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
2645 if (err)
2646 return err;
2647 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
2648 if (err)
2649 return err;
2650 return 0;
2651 }
2652
2653 static void cmd_mon_help(void)
2654 {
2655 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
2656 "where OBJECT-LIST := { dev | port }\n");
2657 }
2658
2659 static int cmd_mon(struct dl *dl)
2660 {
2661 if (dl_argv_match(dl, "help")) {
2662 cmd_mon_help();
2663 return 0;
2664 } else if (dl_no_arg(dl)) {
2665 dl_arg_inc(dl);
2666 return cmd_mon_show(dl);
2667 }
2668 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2669 return -ENOENT;
2670 }
2671
2672 struct dpipe_field {
2673 char *name;
2674 unsigned int id;
2675 unsigned int bitwidth;
2676 enum devlink_dpipe_field_mapping_type mapping_type;
2677 };
2678
2679 struct dpipe_header {
2680 struct list_head list;
2681 char *name;
2682 unsigned int id;
2683 struct dpipe_field *fields;
2684 unsigned int fields_count;
2685 };
2686
2687 struct dpipe_ctx {
2688 struct dl *dl;
2689 int err;
2690 struct list_head global_headers;
2691 struct list_head local_headers;
2692 bool print_headers;
2693 };
2694
2695 static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
2696 {
2697 struct dpipe_header *header;
2698
2699 header = calloc(1, sizeof(struct dpipe_header));
2700 if (!header)
2701 return NULL;
2702 header->fields = calloc(fields_count, sizeof(struct dpipe_field));
2703 if (!header->fields)
2704 goto err_fields_alloc;
2705 header->fields_count = fields_count;
2706 return header;
2707
2708 err_fields_alloc:
2709 free(header);
2710 return NULL;
2711 }
2712
2713 static void dpipe_header_free(struct dpipe_header *header)
2714 {
2715 free(header->fields);
2716 free(header);
2717 }
2718
2719 static void dpipe_header_clear(struct dpipe_header *header)
2720 {
2721 struct dpipe_field *field;
2722 int i;
2723
2724 for (i = 0; i < header->fields_count; i++) {
2725 field = &header->fields[i];
2726 free(field->name);
2727 }
2728 free(header->name);
2729 }
2730
2731 static void dpipe_header_add(struct dpipe_ctx *ctx,
2732 struct dpipe_header *header, bool global)
2733 {
2734 if (global)
2735 list_add(&header->list, &ctx->global_headers);
2736 else
2737 list_add(&header->list, &ctx->local_headers);
2738 }
2739
2740 static void dpipe_header_del(struct dpipe_header *header)
2741 {
2742 list_del(&header->list);
2743 }
2744
2745 static struct dpipe_ctx *dpipe_ctx_alloc(struct dl *dl)
2746 {
2747 struct dpipe_ctx *ctx;
2748
2749 ctx = calloc(1, sizeof(struct dpipe_ctx));
2750 if (!ctx)
2751 return NULL;
2752 ctx->dl = dl;
2753 INIT_LIST_HEAD(&ctx->global_headers);
2754 INIT_LIST_HEAD(&ctx->local_headers);
2755 return ctx;
2756 }
2757
2758 static void dpipe_ctx_free(struct dpipe_ctx *ctx)
2759 {
2760 free(ctx);
2761 }
2762
2763 static void dpipe_ctx_clear(struct dpipe_ctx *ctx)
2764 {
2765 struct dpipe_header *header, *tmp;
2766
2767 list_for_each_entry_safe(header, tmp, &ctx->global_headers,
2768 list) {
2769 dpipe_header_del(header);
2770 dpipe_header_clear(header);
2771 dpipe_header_free(header);
2772 }
2773 list_for_each_entry_safe(header, tmp, &ctx->local_headers,
2774 list) {
2775 dpipe_header_del(header);
2776 dpipe_header_clear(header);
2777 dpipe_header_free(header);
2778 }
2779 }
2780
2781 static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
2782 uint32_t header_id, bool global)
2783 {
2784 struct list_head *header_list;
2785 struct dpipe_header *header;
2786
2787 if (global)
2788 header_list = &ctx->global_headers;
2789 else
2790 header_list = &ctx->local_headers;
2791 list_for_each_entry(header, header_list, list) {
2792 if (header->id != header_id)
2793 continue;
2794 return header->name;
2795 }
2796 return NULL;
2797 }
2798
2799 static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
2800 uint32_t header_id,
2801 uint32_t field_id, bool global)
2802 {
2803 struct list_head *header_list;
2804 struct dpipe_header *header;
2805
2806 if (global)
2807 header_list = &ctx->global_headers;
2808 else
2809 header_list = &ctx->local_headers;
2810 list_for_each_entry(header, header_list, list) {
2811 if (header->id != header_id)
2812 continue;
2813 return header->fields[field_id].name;
2814 }
2815 return NULL;
2816 }
2817
2818 static const char *
2819 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
2820 {
2821 switch (mapping_type) {
2822 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
2823 return NULL;
2824 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
2825 return "ifindex";
2826 default:
2827 return "<unknown>";
2828 }
2829 }
2830
2831 static const char *
2832 dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
2833 uint32_t field_id, bool global)
2834 {
2835 enum devlink_dpipe_field_mapping_type mapping_type;
2836 struct list_head *header_list;
2837 struct dpipe_header *header;
2838
2839 if (global)
2840 header_list = &ctx->global_headers;
2841 else
2842 header_list = &ctx->local_headers;
2843 list_for_each_entry(header, header_list, list) {
2844 if (header->id != header_id)
2845 continue;
2846 mapping_type = header->fields[field_id].mapping_type;
2847 return dpipe_field_mapping_e2s(mapping_type);
2848 }
2849 return NULL;
2850 }
2851
2852 static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
2853 struct dpipe_field *fields,
2854 unsigned int field_count)
2855 {
2856 struct dpipe_field *field;
2857 int i;
2858
2859 for (i = 0; i < field_count; i++) {
2860 field = &fields[i];
2861 pr_out_entry_start(ctx->dl);
2862 pr_out_str(ctx->dl, "name", field->name);
2863 if (ctx->dl->verbose)
2864 pr_out_uint(ctx->dl, "id", field->id);
2865 pr_out_uint(ctx->dl, "bitwidth", field->bitwidth);
2866 if (field->mapping_type)
2867 pr_out_str(ctx->dl, "mapping_type",
2868 dpipe_field_mapping_e2s(field->mapping_type));
2869 pr_out_entry_end(ctx->dl);
2870 }
2871 }
2872
2873 static void
2874 pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
2875 struct dpipe_header *header, bool global)
2876 {
2877 pr_out_handle_start_arr(ctx->dl, tb);
2878 pr_out_str(ctx->dl, "name", header->name);
2879 if (ctx->dl->verbose) {
2880 pr_out_uint(ctx->dl, "id", header->id);
2881 pr_out_str(ctx->dl, "global",
2882 global ? "true" : "false");
2883 }
2884 pr_out_array_start(ctx->dl, "field");
2885 pr_out_dpipe_fields(ctx, header->fields,
2886 header->fields_count);
2887 pr_out_array_end(ctx->dl);
2888 pr_out_handle_end(ctx->dl);
2889 }
2890
2891 static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
2892 struct nlattr **tb)
2893 {
2894 struct dpipe_header *header;
2895
2896 list_for_each_entry(header, &ctx->local_headers, list)
2897 pr_out_dpipe_header(ctx, tb, header, false);
2898
2899 list_for_each_entry(header, &ctx->global_headers, list)
2900 pr_out_dpipe_header(ctx, tb, header, true);
2901 }
2902
2903 static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
2904 {
2905 struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
2906 const char *name;
2907 int err;
2908
2909 err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
2910 if (err != MNL_CB_OK)
2911 return -EINVAL;
2912 if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
2913 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
2914 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
2915 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
2916 return -EINVAL;
2917
2918 name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
2919 field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
2920 field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
2921 field->name = strdup(name);
2922 if (!field->name)
2923 return -ENOMEM;
2924 field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
2925 return 0;
2926 }
2927
2928 static int dpipe_header_fields_get(struct nlattr *nla_fields,
2929 struct dpipe_field *fields)
2930 {
2931 struct nlattr *nla_field;
2932 int count = 0;
2933 int err;
2934
2935 mnl_attr_for_each_nested(nla_field, nla_fields) {
2936 err = dpipe_header_field_get(nla_field, &fields[count]);
2937 if (err)
2938 return err;
2939 count++;
2940 }
2941 return 0;
2942 }
2943
2944 static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
2945 {
2946 struct nlattr *nla_field;
2947 unsigned int count = 0;
2948
2949 mnl_attr_for_each_nested(nla_field, nla_fields)
2950 count++;
2951 return count;
2952 }
2953
2954 static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
2955 {
2956 struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
2957 struct dpipe_header *header;
2958 unsigned int fields_count;
2959 const char *header_name;
2960 bool global;
2961 int err;
2962
2963 err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
2964 if (err != MNL_CB_OK)
2965 return -EINVAL;
2966
2967 if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
2968 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
2969 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
2970 return -EINVAL;
2971
2972 fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
2973 header = dpipe_header_alloc(fields_count);
2974 if (!header)
2975 return -ENOMEM;
2976
2977 header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
2978 header->name = strdup(header_name);
2979 header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
2980 header->fields_count = fields_count;
2981 global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
2982
2983 err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
2984 header->fields);
2985 if (err)
2986 goto err_field_get;
2987 dpipe_header_add(ctx, header, global);
2988 return 0;
2989
2990 err_field_get:
2991 dpipe_header_free(header);
2992 return err;
2993 }
2994
2995 static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
2996 {
2997 struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
2998 struct nlattr *nla_header;
2999 int err;
3000
3001 mnl_attr_for_each_nested(nla_header, nla_headers) {
3002 err = dpipe_header_get(ctx, nla_header);
3003 if (err)
3004 return err;
3005 }
3006 return 0;
3007 }
3008
3009 static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
3010 {
3011 struct dpipe_ctx *ctx = data;
3012 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3013 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3014 int err;
3015
3016 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3017 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3018 !tb[DEVLINK_ATTR_DPIPE_HEADERS])
3019 return MNL_CB_ERROR;
3020 err = dpipe_headers_get(ctx, tb);
3021 if (err) {
3022 ctx->err = err;
3023 return MNL_CB_ERROR;
3024 }
3025
3026 if (ctx->print_headers)
3027 pr_out_dpipe_headers(ctx, tb);
3028 return MNL_CB_OK;
3029 }
3030
3031 static int cmd_dpipe_headers_show(struct dl *dl)
3032 {
3033 struct nlmsghdr *nlh;
3034 struct dpipe_ctx *ctx;
3035 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3036 int err;
3037
3038 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3039
3040 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3041 if (err)
3042 return err;
3043
3044 ctx = dpipe_ctx_alloc(dl);
3045 if (!ctx)
3046 return -ENOMEM;
3047
3048 ctx->print_headers = true;
3049
3050 pr_out_section_start(dl, "header");
3051 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
3052 if (err)
3053 pr_err("error get headers %s\n", strerror(ctx->err));
3054 pr_out_section_end(dl);
3055
3056 dpipe_ctx_clear(ctx);
3057 dpipe_ctx_free(ctx);
3058 return err;
3059 }
3060
3061 static void cmd_dpipe_header_help(void)
3062 {
3063 pr_err("Usage: devlink dpipe headers show DEV\n");
3064 }
3065
3066 static int cmd_dpipe_header(struct dl *dl)
3067 {
3068 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3069 cmd_dpipe_header_help();
3070 return 0;
3071 } else if (dl_argv_match(dl, "show")) {
3072 dl_arg_inc(dl);
3073 return cmd_dpipe_headers_show(dl);
3074 }
3075 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3076 return -ENOENT;
3077 }
3078
3079 static const char
3080 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
3081 {
3082 switch (action_type) {
3083 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
3084 return "field_modify";
3085 default:
3086 return "<unknown>";
3087 }
3088 }
3089
3090 struct dpipe_op_info {
3091 uint32_t header_id;
3092 uint32_t field_id;
3093 bool header_global;
3094 };
3095
3096 struct dpipe_action {
3097 struct dpipe_op_info info;
3098 uint32_t type;
3099 };
3100
3101 static void pr_out_dpipe_action(struct dpipe_action *action,
3102 struct dpipe_ctx *ctx)
3103 {
3104 struct dpipe_op_info *op_info = &action->info;
3105 const char *mapping;
3106
3107 pr_out_str(ctx->dl, "type",
3108 dpipe_action_type_e2s(action->type));
3109 pr_out_str(ctx->dl, "header",
3110 dpipe_header_id2s(ctx, op_info->header_id,
3111 op_info->header_global));
3112 pr_out_str(ctx->dl, "field",
3113 dpipe_field_id2s(ctx, op_info->header_id,
3114 op_info->field_id,
3115 op_info->header_global));
3116 mapping = dpipe_mapping_get(ctx, op_info->header_id,
3117 op_info->field_id,
3118 op_info->header_global);
3119 if (mapping)
3120 pr_out_str(ctx->dl, "mapping", mapping);
3121 }
3122
3123 static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
3124 {
3125 struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
3126 int err;
3127
3128 err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
3129 if (err != MNL_CB_OK)
3130 return -EINVAL;
3131
3132 if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
3133 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
3134 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
3135 !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
3136 return -EINVAL;
3137 }
3138
3139 action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
3140 action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
3141 action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
3142 action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
3143
3144 return 0;
3145 }
3146
3147 static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
3148 struct nlattr *nla_actions)
3149 {
3150 struct nlattr *nla_action;
3151 struct dpipe_action action;
3152
3153 mnl_attr_for_each_nested(nla_action, nla_actions) {
3154 pr_out_entry_start(ctx->dl);
3155 if (dpipe_action_parse(&action, nla_action))
3156 goto err_action_parse;
3157 pr_out_dpipe_action(&action, ctx);
3158 pr_out_entry_end(ctx->dl);
3159 }
3160 return 0;
3161
3162 err_action_parse:
3163 pr_out_entry_end(ctx->dl);
3164 return -EINVAL;
3165 }
3166
3167 static const char *
3168 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
3169 {
3170 switch (match_type) {
3171 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
3172 return "field_exact";
3173 default:
3174 return "<unknown>";
3175 }
3176 }
3177
3178 struct dpipe_match {
3179 struct dpipe_op_info info;
3180 uint32_t type;
3181 };
3182
3183 static void pr_out_dpipe_match(struct dpipe_match *match,
3184 struct dpipe_ctx *ctx)
3185 {
3186 struct dpipe_op_info *op_info = &match->info;
3187 const char *mapping;
3188
3189 pr_out_str(ctx->dl, "type",
3190 dpipe_match_type_e2s(match->type));
3191 pr_out_str(ctx->dl, "header",
3192 dpipe_header_id2s(ctx, op_info->header_id,
3193 op_info->header_global));
3194 pr_out_str(ctx->dl, "field",
3195 dpipe_field_id2s(ctx, op_info->header_id,
3196 op_info->field_id,
3197 op_info->header_global));
3198 mapping = dpipe_mapping_get(ctx, op_info->header_id,
3199 op_info->field_id,
3200 op_info->header_global);
3201 if (mapping)
3202 pr_out_str(ctx->dl, "mapping", mapping);
3203 }
3204
3205 static int dpipe_match_parse(struct dpipe_match *match,
3206 struct nlattr *nl)
3207
3208 {
3209 struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
3210 int err;
3211
3212 err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
3213 if (err != MNL_CB_OK)
3214 return -EINVAL;
3215
3216 if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
3217 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
3218 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
3219 !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
3220 return -EINVAL;
3221 }
3222
3223 match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
3224 match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
3225 match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
3226 match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
3227
3228 return 0;
3229 }
3230
3231 static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
3232 struct nlattr *nla_matches)
3233 {
3234 struct nlattr *nla_match;
3235 struct dpipe_match match;
3236
3237 mnl_attr_for_each_nested(nla_match, nla_matches) {
3238 pr_out_entry_start(ctx->dl);
3239 if (dpipe_match_parse(&match, nla_match))
3240 goto err_match_parse;
3241 pr_out_dpipe_match(&match, ctx);
3242 pr_out_entry_end(ctx->dl);
3243 }
3244 return 0;
3245
3246 err_match_parse:
3247 pr_out_entry_end(ctx->dl);
3248 return -EINVAL;
3249 }
3250
3251 static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
3252 {
3253 struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
3254 bool counters_enabled;
3255 const char *name;
3256 uint32_t size;
3257 int err;
3258
3259 err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
3260 if (err != MNL_CB_OK)
3261 return -EINVAL;
3262
3263 if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
3264 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
3265 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
3266 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
3267 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
3268 return -EINVAL;
3269 }
3270
3271 name = mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
3272 size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
3273 counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
3274
3275 pr_out_str(ctx->dl, "name", name);
3276 pr_out_uint(ctx->dl, "size", size);
3277 pr_out_str(ctx->dl, "counters_enabled",
3278 counters_enabled ? "true" : "false");
3279
3280 pr_out_array_start(ctx->dl, "match");
3281 if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
3282 goto err_matches_show;
3283 pr_out_array_end(ctx->dl);
3284
3285 pr_out_array_start(ctx->dl, "action");
3286 if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
3287 goto err_actions_show;
3288 pr_out_array_end(ctx->dl);
3289
3290 return 0;
3291
3292 err_actions_show:
3293 err_matches_show:
3294 pr_out_array_end(ctx->dl);
3295 return -EINVAL;
3296 }
3297
3298 static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
3299 {
3300 struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
3301 struct nlattr *nla_table;
3302
3303 mnl_attr_for_each_nested(nla_table, nla_tables) {
3304 pr_out_handle_start_arr(ctx->dl, tb);
3305 if (dpipe_table_show(ctx, nla_table))
3306 goto err_table_show;
3307 pr_out_handle_end(ctx->dl);
3308 }
3309 return 0;
3310
3311 err_table_show:
3312 pr_out_handle_end(ctx->dl);
3313 return -EINVAL;
3314 }
3315
3316 static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
3317 {
3318 struct dpipe_ctx *ctx = data;
3319 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3320 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3321
3322 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3323 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3324 !tb[DEVLINK_ATTR_DPIPE_TABLES])
3325 return MNL_CB_ERROR;
3326
3327 if (dpipe_tables_show(ctx, tb))
3328 return MNL_CB_ERROR;
3329 return MNL_CB_OK;
3330 }
3331
3332 static int cmd_dpipe_table_show(struct dl *dl)
3333 {
3334 struct nlmsghdr *nlh;
3335 struct dpipe_ctx *ctx;
3336 uint16_t flags = NLM_F_REQUEST;
3337 int err;
3338
3339 ctx = dpipe_ctx_alloc(dl);
3340 if (!ctx)
3341 return -ENOMEM;
3342
3343 err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
3344 if (err)
3345 goto out;
3346
3347 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3348 dl_opts_put(nlh, dl);
3349 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
3350 if (err) {
3351 pr_err("error get headers %s\n", strerror(ctx->err));
3352 goto out;
3353 }
3354
3355 flags = NLM_F_REQUEST | NLM_F_ACK;
3356 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
3357 dl_opts_put(nlh, dl);
3358
3359 pr_out_section_start(dl, "table");
3360 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, ctx);
3361 pr_out_section_end(dl);
3362 out:
3363 dpipe_ctx_clear(ctx);
3364 dpipe_ctx_free(ctx);
3365 return err;
3366 }
3367
3368 static int cmd_dpipe_table_set(struct dl *dl)
3369 {
3370 struct nlmsghdr *nlh;
3371 int err;
3372
3373 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
3374 NLM_F_REQUEST | NLM_F_ACK);
3375
3376 err = dl_argv_parse_put(nlh, dl,
3377 DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
3378 DL_OPT_DPIPE_TABLE_COUNTERS, 0);
3379 if (err)
3380 return err;
3381
3382 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3383 }
3384
3385 enum dpipe_value_type {
3386 DPIPE_VALUE_TYPE_VALUE,
3387 DPIPE_VALUE_TYPE_MASK,
3388 };
3389
3390 static const char *
3391 dpipe_value_type_e2s(enum dpipe_value_type type)
3392 {
3393 switch (type) {
3394 case DPIPE_VALUE_TYPE_VALUE:
3395 return "value";
3396 case DPIPE_VALUE_TYPE_MASK:
3397 return "value_mask";
3398 default:
3399 return "<unknown>";
3400 }
3401 }
3402
3403 struct dpipe_field_printer {
3404 unsigned int field_id;
3405 void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
3406 };
3407
3408 struct dpipe_header_printer {
3409 struct dpipe_field_printer *printers;
3410 unsigned int printers_count;
3411 unsigned int header_id;
3412 };
3413
3414 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
3415 enum dpipe_value_type type,
3416 void *value)
3417 {
3418 struct in_addr ip_addr;
3419
3420 ip_addr.s_addr = htonl(*(uint32_t *)value);
3421 pr_out_str(ctx->dl, dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
3422 }
3423
3424 static void
3425 dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
3426 enum dpipe_value_type type,
3427 void *value)
3428 {
3429 pr_out_str(ctx->dl, dpipe_value_type_e2s(type),
3430 ether_ntoa((struct ether_addr *)value));
3431 }
3432
3433 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
3434 enum dpipe_value_type type,
3435 void *value)
3436 {
3437 char str[INET6_ADDRSTRLEN];
3438
3439 inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
3440 pr_out_str(ctx->dl, dpipe_value_type_e2s(type), str);
3441 }
3442
3443 static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
3444 {
3445 .printer = dpipe_field_printer_ipv4_addr,
3446 .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
3447 }
3448 };
3449
3450 static struct dpipe_header_printer dpipe_header_printer_ipv4 = {
3451 .printers = dpipe_field_printers_ipv4,
3452 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
3453 .header_id = DEVLINK_DPIPE_HEADER_IPV4,
3454 };
3455
3456 static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
3457 {
3458 .printer = dpipe_field_printer_ethernet_addr,
3459 .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
3460 },
3461 };
3462
3463 static struct dpipe_header_printer dpipe_header_printer_ethernet = {
3464 .printers = dpipe_field_printers_ethernet,
3465 .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
3466 .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
3467 };
3468
3469 static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
3470 {
3471 .printer = dpipe_field_printer_ipv6_addr,
3472 .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
3473 }
3474 };
3475
3476 static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
3477 .printers = dpipe_field_printers_ipv6,
3478 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
3479 .header_id = DEVLINK_DPIPE_HEADER_IPV6,
3480 };
3481
3482 static struct dpipe_header_printer *dpipe_header_printers[] = {
3483 &dpipe_header_printer_ipv4,
3484 &dpipe_header_printer_ethernet,
3485 &dpipe_header_printer_ipv6,
3486 };
3487
3488 static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
3489 struct dpipe_op_info *info,
3490 enum dpipe_value_type type,
3491 void *value)
3492 {
3493 unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
3494 struct dpipe_header_printer *header_printer;
3495 struct dpipe_field_printer *field_printer;
3496 unsigned int field_printers_count;
3497 int j;
3498 int i;
3499
3500 for (i = 0; i < header_printers_count; i++) {
3501 header_printer = dpipe_header_printers[i];
3502 if (header_printer->header_id != info->header_id)
3503 continue;
3504 field_printers_count = header_printer->printers_count;
3505 for (j = 0; j < field_printers_count; j++) {
3506 field_printer = &header_printer->printers[j];
3507 if (field_printer->field_id != info->field_id)
3508 continue;
3509 field_printer->printer(ctx, type, value);
3510 return 0;
3511 }
3512 }
3513
3514 return -EINVAL;
3515 }
3516
3517 static void __pr_out_entry_value(struct dpipe_ctx *ctx,
3518 void *value,
3519 unsigned int value_len,
3520 struct dpipe_op_info *info,
3521 enum dpipe_value_type type)
3522 {
3523 if (info->header_global &&
3524 !dpipe_print_prot_header(ctx, info, type, value))
3525 return;
3526
3527 if (value_len == sizeof(uint32_t)) {
3528 uint32_t *value_32 = value;
3529
3530 pr_out_uint(ctx->dl, dpipe_value_type_e2s(type), *value_32);
3531 }
3532 }
3533
3534 static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
3535 struct nlattr **nla_match_value,
3536 struct dpipe_op_info *info)
3537 {
3538 void *value, *value_mask;
3539 uint32_t value_mapping;
3540 uint16_t value_len;
3541 bool mask, mapping;
3542
3543 mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
3544 mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
3545
3546 value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3547 value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3548
3549 if (mapping) {
3550 value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
3551 pr_out_uint(ctx->dl, "mapping_value", value_mapping);
3552 }
3553
3554 if (mask) {
3555 value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3556 __pr_out_entry_value(ctx, value_mask, value_len, info,
3557 DPIPE_VALUE_TYPE_MASK);
3558 }
3559
3560 __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
3561 }
3562
3563 static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
3564 struct nlattr *nl)
3565 {
3566 struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
3567 struct dpipe_match match;
3568 int err;
3569
3570 err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
3571 if (err != MNL_CB_OK)
3572 return -EINVAL;
3573
3574 if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
3575 !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
3576 return -EINVAL;
3577 }
3578
3579 pr_out_entry_start(ctx->dl);
3580 if (dpipe_match_parse(&match,
3581 nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
3582 goto err_match_parse;
3583 pr_out_dpipe_match(&match, ctx);
3584 pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
3585 pr_out_entry_end(ctx->dl);
3586
3587 return 0;
3588
3589 err_match_parse:
3590 pr_out_entry_end(ctx->dl);
3591 return -EINVAL;
3592 }
3593
3594 static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
3595 struct nlattr *nl)
3596 {
3597 struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
3598 struct dpipe_action action;
3599 int err;
3600
3601 err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
3602 if (err != MNL_CB_OK)
3603 return -EINVAL;
3604
3605 if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
3606 !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
3607 return -EINVAL;
3608 }
3609
3610 pr_out_entry_start(ctx->dl);
3611 if (dpipe_action_parse(&action,
3612 nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
3613 goto err_action_parse;
3614 pr_out_dpipe_action(&action, ctx);
3615 pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
3616 pr_out_entry_end(ctx->dl);
3617
3618 return 0;
3619
3620 err_action_parse:
3621 pr_out_entry_end(ctx->dl);
3622 return -EINVAL;
3623 }
3624
3625 static int
3626 dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
3627 struct nlattr *nla_action_values)
3628 {
3629 struct nlattr *nla_action_value;
3630
3631 mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
3632 if (dpipe_entry_action_value_show(ctx, nla_action_value))
3633 return -EINVAL;
3634 }
3635 return 0;
3636 }
3637
3638 static int
3639 dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
3640 struct nlattr *nla_match_values)
3641 {
3642 struct nlattr *nla_match_value;
3643
3644 mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
3645 if (dpipe_entry_match_value_show(ctx, nla_match_value))
3646 return -EINVAL;
3647 }
3648 return 0;
3649 }
3650
3651 static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
3652 {
3653 struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
3654 uint32_t entry_index;
3655 uint64_t counter;
3656 int err;
3657
3658 err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
3659 if (err != MNL_CB_OK)
3660 return -EINVAL;
3661
3662 if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
3663 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
3664 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
3665 return -EINVAL;
3666 }
3667
3668 entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
3669 pr_out_uint(ctx->dl, "index", entry_index);
3670
3671 if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
3672 counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
3673 pr_out_uint(ctx->dl, "counter", counter);
3674 }
3675
3676 pr_out_array_start(ctx->dl, "match_value");
3677 if (dpipe_tables_match_values_show(ctx,
3678 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
3679 goto err_match_values_show;
3680 pr_out_array_end(ctx->dl);
3681
3682 pr_out_array_start(ctx->dl, "action_value");
3683 if (dpipe_tables_action_values_show(ctx,
3684 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
3685 goto err_action_values_show;
3686 pr_out_array_end(ctx->dl);
3687 return 0;
3688
3689 err_action_values_show:
3690 err_match_values_show:
3691 pr_out_array_end(ctx->dl);
3692 return -EINVAL;
3693 }
3694
3695 static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
3696 {
3697 struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
3698 struct nlattr *nla_entry;
3699
3700 mnl_attr_for_each_nested(nla_entry, nla_entries) {
3701 pr_out_handle_start_arr(ctx->dl, tb);
3702 if (dpipe_entry_show(ctx, nla_entry))
3703 goto err_entry_show;
3704 pr_out_handle_end(ctx->dl);
3705 }
3706 return 0;
3707
3708 err_entry_show:
3709 pr_out_handle_end(ctx->dl);
3710 return -EINVAL;
3711 }
3712
3713 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
3714 {
3715 struct dpipe_ctx *ctx = data;
3716 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3717 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3718
3719 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3720 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3721 !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
3722 return MNL_CB_ERROR;
3723
3724 if (dpipe_table_entries_show(ctx, tb))
3725 return MNL_CB_ERROR;
3726 return MNL_CB_OK;
3727 }
3728
3729 static int cmd_dpipe_table_dump(struct dl *dl)
3730 {
3731 struct nlmsghdr *nlh;
3732 struct dpipe_ctx *ctx;
3733 uint16_t flags = NLM_F_REQUEST;
3734 int err;
3735
3736 ctx = dpipe_ctx_alloc(dl);
3737 if (!ctx)
3738 return -ENOMEM;
3739
3740 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
3741 if (err)
3742 goto out;
3743
3744 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3745 dl_opts_put(nlh, dl);
3746 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
3747 if (err) {
3748 pr_err("error get headers %s\n", strerror(ctx->err));
3749 goto out;
3750 }
3751
3752 flags = NLM_F_REQUEST | NLM_F_ACK;
3753 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
3754 dl_opts_put(nlh, dl);
3755
3756 pr_out_section_start(dl, "table_entry");
3757 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, ctx);
3758 pr_out_section_end(dl);
3759 out:
3760 dpipe_ctx_clear(ctx);
3761 dpipe_ctx_free(ctx);
3762 return err;
3763 }
3764
3765 static void cmd_dpipe_table_help(void)
3766 {
3767 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
3768 "where OBJECT-LIST := { show | set | dump }\n");
3769 }
3770
3771 static int cmd_dpipe_table(struct dl *dl)
3772 {
3773 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3774 cmd_dpipe_table_help();
3775 return 0;
3776 } else if (dl_argv_match(dl, "show")) {
3777 dl_arg_inc(dl);
3778 return cmd_dpipe_table_show(dl);
3779 } else if (dl_argv_match(dl, "set")) {
3780 dl_arg_inc(dl);
3781 return cmd_dpipe_table_set(dl);
3782 } else if (dl_argv_match(dl, "dump")) {
3783 dl_arg_inc(dl);
3784 return cmd_dpipe_table_dump(dl);
3785 }
3786 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3787 return -ENOENT;
3788 }
3789
3790 static void cmd_dpipe_help(void)
3791 {
3792 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
3793 "where OBJECT-LIST := { header | table }\n");
3794 }
3795
3796 static int cmd_dpipe(struct dl *dl)
3797 {
3798 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3799 cmd_dpipe_help();
3800 return 0;
3801 } else if (dl_argv_match(dl, "header")) {
3802 dl_arg_inc(dl);
3803 return cmd_dpipe_header(dl);
3804 } else if (dl_argv_match(dl, "table")) {
3805 dl_arg_inc(dl);
3806 return cmd_dpipe_table(dl);
3807 }
3808 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3809 return -ENOENT;
3810 }
3811
3812 static void help(void)
3813 {
3814 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
3815 " devlink [ -f[orce] ] -b[atch] filename\n"
3816 "where OBJECT := { dev | port | sb | monitor | dpipe }\n"
3817 " OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] | -v[verbose] }\n");
3818 }
3819
3820 static int dl_cmd(struct dl *dl, int argc, char **argv)
3821 {
3822 dl->argc = argc;
3823 dl->argv = argv;
3824
3825 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3826 help();
3827 return 0;
3828 } else if (dl_argv_match(dl, "dev")) {
3829 dl_arg_inc(dl);
3830 return cmd_dev(dl);
3831 } else if (dl_argv_match(dl, "port")) {
3832 dl_arg_inc(dl);
3833 return cmd_port(dl);
3834 } else if (dl_argv_match(dl, "sb")) {
3835 dl_arg_inc(dl);
3836 return cmd_sb(dl);
3837 } else if (dl_argv_match(dl, "monitor")) {
3838 dl_arg_inc(dl);
3839 return cmd_mon(dl);
3840 } else if (dl_argv_match(dl, "dpipe")) {
3841 dl_arg_inc(dl);
3842 return cmd_dpipe(dl);
3843 }
3844 pr_err("Object \"%s\" not found\n", dl_argv(dl));
3845 return -ENOENT;
3846 }
3847
3848 static int dl_init(struct dl *dl)
3849 {
3850 int err;
3851
3852 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
3853 if (!dl->nlg) {
3854 pr_err("Failed to connect to devlink Netlink\n");
3855 return -errno;
3856 }
3857
3858 err = ifname_map_init(dl);
3859 if (err) {
3860 pr_err("Failed to create index map\n");
3861 goto err_ifname_map_create;
3862 }
3863 if (dl->json_output) {
3864 dl->jw = jsonw_new(stdout);
3865 if (!dl->jw) {
3866 pr_err("Failed to create JSON writer\n");
3867 goto err_json_new;
3868 }
3869 jsonw_pretty(dl->jw, dl->pretty_output);
3870 }
3871 return 0;
3872
3873 err_json_new:
3874 ifname_map_fini(dl);
3875 err_ifname_map_create:
3876 mnlg_socket_close(dl->nlg);
3877 return err;
3878 }
3879
3880 static void dl_fini(struct dl *dl)
3881 {
3882 if (dl->json_output)
3883 jsonw_destroy(&dl->jw);
3884 ifname_map_fini(dl);
3885 mnlg_socket_close(dl->nlg);
3886 }
3887
3888 static struct dl *dl_alloc(void)
3889 {
3890 struct dl *dl;
3891
3892 dl = calloc(1, sizeof(*dl));
3893 if (!dl)
3894 return NULL;
3895 return dl;
3896 }
3897
3898 static void dl_free(struct dl *dl)
3899 {
3900 free(dl);
3901 }
3902
3903 static int dl_batch(struct dl *dl, const char *name, bool force)
3904 {
3905 char *line = NULL;
3906 size_t len = 0;
3907 int ret = EXIT_SUCCESS;
3908
3909 if (name && strcmp(name, "-") != 0) {
3910 if (freopen(name, "r", stdin) == NULL) {
3911 fprintf(stderr,
3912 "Cannot open file \"%s\" for reading: %s\n",
3913 name, strerror(errno));
3914 return EXIT_FAILURE;
3915 }
3916 }
3917
3918 cmdlineno = 0;
3919 while (getcmdline(&line, &len, stdin) != -1) {
3920 char *largv[100];
3921 int largc;
3922
3923 largc = makeargs(line, largv, 100);
3924 if (!largc)
3925 continue; /* blank line */
3926
3927 if (dl_cmd(dl, largc, largv)) {
3928 fprintf(stderr, "Command failed %s:%d\n",
3929 name, cmdlineno);
3930 ret = EXIT_FAILURE;
3931 if (!force)
3932 break;
3933 }
3934 }
3935
3936 if (line)
3937 free(line);
3938
3939 return ret;
3940 }
3941
3942 int main(int argc, char **argv)
3943 {
3944 static const struct option long_options[] = {
3945 { "Version", no_argument, NULL, 'V' },
3946 { "force", no_argument, NULL, 'f' },
3947 { "batch", required_argument, NULL, 'b' },
3948 { "no-nice-names", no_argument, NULL, 'n' },
3949 { "json", no_argument, NULL, 'j' },
3950 { "pretty", no_argument, NULL, 'p' },
3951 { "verbose", no_argument, NULL, 'v' },
3952 { NULL, 0, NULL, 0 }
3953 };
3954 const char *batch_file = NULL;
3955 bool force = false;
3956 struct dl *dl;
3957 int opt;
3958 int err;
3959 int ret;
3960
3961 dl = dl_alloc();
3962 if (!dl) {
3963 pr_err("Failed to allocate memory for devlink\n");
3964 return EXIT_FAILURE;
3965 }
3966
3967 while ((opt = getopt_long(argc, argv, "Vfb:njpv",
3968 long_options, NULL)) >= 0) {
3969
3970 switch (opt) {
3971 case 'V':
3972 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
3973 ret = EXIT_SUCCESS;
3974 goto dl_free;
3975 case 'f':
3976 force = true;
3977 break;
3978 case 'b':
3979 batch_file = optarg;
3980 break;
3981 case 'n':
3982 dl->no_nice_names = true;
3983 break;
3984 case 'j':
3985 dl->json_output = true;
3986 break;
3987 case 'p':
3988 dl->pretty_output = true;
3989 break;
3990 case 'v':
3991 dl->verbose = true;
3992 break;
3993 default:
3994 pr_err("Unknown option.\n");
3995 help();
3996 ret = EXIT_FAILURE;
3997 goto dl_free;
3998 }
3999 }
4000
4001 argc -= optind;
4002 argv += optind;
4003
4004 err = dl_init(dl);
4005 if (err) {
4006 ret = EXIT_FAILURE;
4007 goto dl_free;
4008 }
4009
4010 if (batch_file)
4011 err = dl_batch(dl, batch_file, force);
4012 else
4013 err = dl_cmd(dl, argc, argv);
4014
4015 if (err) {
4016 ret = EXIT_FAILURE;
4017 goto dl_fini;
4018 }
4019
4020 ret = EXIT_SUCCESS;
4021
4022 dl_fini:
4023 dl_fini(dl);
4024 dl_free:
4025 dl_free(dl);
4026
4027 return ret;
4028 }