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