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