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