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