]> 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 const char *port_flavour_name(uint16_t flavour)
1697 {
1698 switch (flavour) {
1699 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
1700 return "physical";
1701 case DEVLINK_PORT_FLAVOUR_CPU:
1702 return "cpu";
1703 case DEVLINK_PORT_FLAVOUR_DSA:
1704 return "dsa";
1705 default:
1706 return "<unknown flavour>";
1707 }
1708 }
1709
1710 static void pr_out_port(struct dl *dl, struct nlattr **tb)
1711 {
1712 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
1713 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
1714
1715 pr_out_port_handle_start(dl, tb, false);
1716 if (pt_attr) {
1717 uint16_t port_type = mnl_attr_get_u16(pt_attr);
1718
1719 pr_out_str(dl, "type", port_type_name(port_type));
1720 if (dpt_attr) {
1721 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
1722
1723 if (port_type != des_port_type)
1724 pr_out_str(dl, "des_type",
1725 port_type_name(des_port_type));
1726 }
1727 }
1728 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
1729 pr_out_str(dl, "netdev",
1730 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
1731 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
1732 pr_out_str(dl, "ibdev",
1733 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
1734 if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
1735 uint16_t port_flavour =
1736 mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
1737
1738 pr_out_str(dl, "flavour", port_flavour_name(port_flavour));
1739 }
1740 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
1741 pr_out_uint(dl, "split_group",
1742 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
1743 pr_out_port_handle_end(dl);
1744 }
1745
1746 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
1747 {
1748 struct dl *dl = data;
1749 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1750 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1751
1752 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1753 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1754 !tb[DEVLINK_ATTR_PORT_INDEX])
1755 return MNL_CB_ERROR;
1756 pr_out_port(dl, tb);
1757 return MNL_CB_OK;
1758 }
1759
1760 static int cmd_port_show(struct dl *dl)
1761 {
1762 struct nlmsghdr *nlh;
1763 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1764 int err;
1765
1766 if (dl_argc(dl) == 0)
1767 flags |= NLM_F_DUMP;
1768
1769 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
1770
1771 if (dl_argc(dl) > 0) {
1772 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1773 if (err)
1774 return err;
1775 }
1776
1777 pr_out_section_start(dl, "port");
1778 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
1779 pr_out_section_end(dl);
1780 return err;
1781 }
1782
1783 static int cmd_port_set(struct dl *dl)
1784 {
1785 struct nlmsghdr *nlh;
1786 int err;
1787
1788 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
1789 NLM_F_REQUEST | NLM_F_ACK);
1790
1791 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
1792 if (err)
1793 return err;
1794
1795 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1796 }
1797
1798 static int cmd_port_split(struct dl *dl)
1799 {
1800 struct nlmsghdr *nlh;
1801 int err;
1802
1803 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
1804 NLM_F_REQUEST | NLM_F_ACK);
1805
1806 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
1807 if (err)
1808 return err;
1809
1810 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1811 }
1812
1813 static int cmd_port_unsplit(struct dl *dl)
1814 {
1815 struct nlmsghdr *nlh;
1816 int err;
1817
1818 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
1819 NLM_F_REQUEST | NLM_F_ACK);
1820
1821 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1822 if (err)
1823 return err;
1824
1825 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1826 }
1827
1828 static int cmd_port(struct dl *dl)
1829 {
1830 if (dl_argv_match(dl, "help")) {
1831 cmd_port_help();
1832 return 0;
1833 } else if (dl_argv_match(dl, "show") ||
1834 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1835 dl_arg_inc(dl);
1836 return cmd_port_show(dl);
1837 } else if (dl_argv_match(dl, "set")) {
1838 dl_arg_inc(dl);
1839 return cmd_port_set(dl);
1840 } else if (dl_argv_match(dl, "split")) {
1841 dl_arg_inc(dl);
1842 return cmd_port_split(dl);
1843 } else if (dl_argv_match(dl, "unsplit")) {
1844 dl_arg_inc(dl);
1845 return cmd_port_unsplit(dl);
1846 }
1847 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1848 return -ENOENT;
1849 }
1850
1851 static void cmd_sb_help(void)
1852 {
1853 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
1854 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
1855 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
1856 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
1857 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1858 pr_err(" pool POOL_INDEX ]\n");
1859 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1860 pr_err(" pool POOL_INDEX th THRESHOLD\n");
1861 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1862 pr_err(" type { ingress | egress } ]\n");
1863 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1864 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
1865 pr_err(" th THRESHOLD\n");
1866 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
1867 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
1868 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
1869 }
1870
1871 static void pr_out_sb(struct dl *dl, struct nlattr **tb)
1872 {
1873 pr_out_handle_start_arr(dl, tb);
1874 pr_out_uint(dl, "sb",
1875 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1876 pr_out_uint(dl, "size",
1877 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
1878 pr_out_uint(dl, "ing_pools",
1879 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
1880 pr_out_uint(dl, "eg_pools",
1881 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
1882 pr_out_uint(dl, "ing_tcs",
1883 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
1884 pr_out_uint(dl, "eg_tcs",
1885 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
1886 pr_out_handle_end(dl);
1887 }
1888
1889 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
1890 {
1891 struct dl *dl = data;
1892 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1893 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1894
1895 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1896 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1897 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
1898 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
1899 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
1900 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
1901 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
1902 return MNL_CB_ERROR;
1903 pr_out_sb(dl, tb);
1904 return MNL_CB_OK;
1905 }
1906
1907 static int cmd_sb_show(struct dl *dl)
1908 {
1909 struct nlmsghdr *nlh;
1910 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1911 int err;
1912
1913 if (dl_argc(dl) == 0)
1914 flags |= NLM_F_DUMP;
1915
1916 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
1917
1918 if (dl_argc(dl) > 0) {
1919 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
1920 if (err)
1921 return err;
1922 }
1923
1924 pr_out_section_start(dl, "sb");
1925 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl);
1926 pr_out_section_end(dl);
1927 return err;
1928 }
1929
1930 static const char *pool_type_name(uint8_t type)
1931 {
1932 switch (type) {
1933 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
1934 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
1935 default: return "<unknown type>";
1936 }
1937 }
1938
1939 static const char *threshold_type_name(uint8_t type)
1940 {
1941 switch (type) {
1942 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
1943 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
1944 default: return "<unknown type>";
1945 }
1946 }
1947
1948 static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
1949 {
1950 pr_out_handle_start_arr(dl, tb);
1951 pr_out_uint(dl, "sb",
1952 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1953 pr_out_uint(dl, "pool",
1954 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
1955 pr_out_str(dl, "type",
1956 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
1957 pr_out_uint(dl, "size",
1958 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
1959 pr_out_str(dl, "thtype",
1960 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
1961 pr_out_handle_end(dl);
1962 }
1963
1964 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1965 {
1966 struct dl *dl = data;
1967 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1968 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1969
1970 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1971 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1972 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
1973 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
1974 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
1975 return MNL_CB_ERROR;
1976 pr_out_sb_pool(dl, tb);
1977 return MNL_CB_OK;
1978 }
1979
1980 static int cmd_sb_pool_show(struct dl *dl)
1981 {
1982 struct nlmsghdr *nlh;
1983 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1984 int err;
1985
1986 if (dl_argc(dl) == 0)
1987 flags |= NLM_F_DUMP;
1988
1989 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
1990
1991 if (dl_argc(dl) > 0) {
1992 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
1993 DL_OPT_SB);
1994 if (err)
1995 return err;
1996 }
1997
1998 pr_out_section_start(dl, "pool");
1999 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
2000 pr_out_section_end(dl);
2001 return err;
2002 }
2003
2004 static int cmd_sb_pool_set(struct dl *dl)
2005 {
2006 struct nlmsghdr *nlh;
2007 int err;
2008
2009 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
2010 NLM_F_REQUEST | NLM_F_ACK);
2011
2012 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
2013 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
2014 if (err)
2015 return err;
2016
2017 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2018 }
2019
2020 static int cmd_sb_pool(struct dl *dl)
2021 {
2022 if (dl_argv_match(dl, "help")) {
2023 cmd_sb_help();
2024 return 0;
2025 } else if (dl_argv_match(dl, "show") ||
2026 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2027 dl_arg_inc(dl);
2028 return cmd_sb_pool_show(dl);
2029 } else if (dl_argv_match(dl, "set")) {
2030 dl_arg_inc(dl);
2031 return cmd_sb_pool_set(dl);
2032 }
2033 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2034 return -ENOENT;
2035 }
2036
2037 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
2038 {
2039 pr_out_port_handle_start_arr(dl, tb, true);
2040 pr_out_uint(dl, "sb",
2041 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
2042 pr_out_uint(dl, "pool",
2043 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
2044 pr_out_uint(dl, "threshold",
2045 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
2046 pr_out_port_handle_end(dl);
2047 }
2048
2049 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
2050 {
2051 struct dl *dl = data;
2052 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2053 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2054
2055 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2056 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2057 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2058 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
2059 return MNL_CB_ERROR;
2060 pr_out_sb_port_pool(dl, tb);
2061 return MNL_CB_OK;
2062 }
2063
2064 static int cmd_sb_port_pool_show(struct dl *dl)
2065 {
2066 struct nlmsghdr *nlh;
2067 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2068 int err;
2069
2070 if (dl_argc(dl) == 0)
2071 flags |= NLM_F_DUMP;
2072
2073 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
2074
2075 if (dl_argc(dl) > 0) {
2076 err = dl_argv_parse_put(nlh, dl,
2077 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
2078 DL_OPT_SB);
2079 if (err)
2080 return err;
2081 }
2082
2083 pr_out_section_start(dl, "port_pool");
2084 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
2085 pr_out_section_end(dl);
2086 return 0;
2087 }
2088
2089 static int cmd_sb_port_pool_set(struct dl *dl)
2090 {
2091 struct nlmsghdr *nlh;
2092 int err;
2093
2094 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
2095 NLM_F_REQUEST | NLM_F_ACK);
2096
2097 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
2098 DL_OPT_SB_TH, DL_OPT_SB);
2099 if (err)
2100 return err;
2101
2102 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2103 }
2104
2105 static int cmd_sb_port_pool(struct dl *dl)
2106 {
2107 if (dl_argv_match(dl, "help")) {
2108 cmd_sb_help();
2109 return 0;
2110 } else if (dl_argv_match(dl, "show") ||
2111 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2112 dl_arg_inc(dl);
2113 return cmd_sb_port_pool_show(dl);
2114 } else if (dl_argv_match(dl, "set")) {
2115 dl_arg_inc(dl);
2116 return cmd_sb_port_pool_set(dl);
2117 }
2118 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2119 return -ENOENT;
2120 }
2121
2122 static int cmd_sb_port(struct dl *dl)
2123 {
2124 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2125 cmd_sb_help();
2126 return 0;
2127 } else if (dl_argv_match(dl, "pool")) {
2128 dl_arg_inc(dl);
2129 return cmd_sb_port_pool(dl);
2130 }
2131 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2132 return -ENOENT;
2133 }
2134
2135 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
2136 {
2137 pr_out_port_handle_start_arr(dl, tb, true);
2138 pr_out_uint(dl, "sb",
2139 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
2140 pr_out_uint(dl, "tc",
2141 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
2142 pr_out_str(dl, "type",
2143 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
2144 pr_out_uint(dl, "pool",
2145 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
2146 pr_out_uint(dl, "threshold",
2147 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
2148 pr_out_port_handle_end(dl);
2149 }
2150
2151 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
2152 {
2153 struct dl *dl = data;
2154 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2155 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2156
2157 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2158 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2159 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2160 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
2161 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
2162 return MNL_CB_ERROR;
2163 pr_out_sb_tc_bind(dl, tb);
2164 return MNL_CB_OK;
2165 }
2166
2167 static int cmd_sb_tc_bind_show(struct dl *dl)
2168 {
2169 struct nlmsghdr *nlh;
2170 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2171 int err;
2172
2173 if (dl_argc(dl) == 0)
2174 flags |= NLM_F_DUMP;
2175
2176 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
2177
2178 if (dl_argc(dl) > 0) {
2179 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
2180 DL_OPT_SB_TYPE, DL_OPT_SB);
2181 if (err)
2182 return err;
2183 }
2184
2185 pr_out_section_start(dl, "tc_bind");
2186 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
2187 pr_out_section_end(dl);
2188 return err;
2189 }
2190
2191 static int cmd_sb_tc_bind_set(struct dl *dl)
2192 {
2193 struct nlmsghdr *nlh;
2194 int err;
2195
2196 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
2197 NLM_F_REQUEST | NLM_F_ACK);
2198
2199 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
2200 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
2201 DL_OPT_SB);
2202 if (err)
2203 return err;
2204
2205 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2206 }
2207
2208 static int cmd_sb_tc_bind(struct dl *dl)
2209 {
2210 if (dl_argv_match(dl, "help")) {
2211 cmd_sb_help();
2212 return 0;
2213 } else if (dl_argv_match(dl, "show") ||
2214 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2215 dl_arg_inc(dl);
2216 return cmd_sb_tc_bind_show(dl);
2217 } else if (dl_argv_match(dl, "set")) {
2218 dl_arg_inc(dl);
2219 return cmd_sb_tc_bind_set(dl);
2220 }
2221 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2222 return -ENOENT;
2223 }
2224
2225 static int cmd_sb_tc(struct dl *dl)
2226 {
2227 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2228 cmd_sb_help();
2229 return 0;
2230 } else if (dl_argv_match(dl, "bind")) {
2231 dl_arg_inc(dl);
2232 return cmd_sb_tc_bind(dl);
2233 }
2234 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2235 return -ENOENT;
2236 }
2237
2238 struct occ_item {
2239 struct list_head list;
2240 uint32_t index;
2241 uint32_t cur;
2242 uint32_t max;
2243 uint32_t bound_pool_index;
2244 };
2245
2246 struct occ_port {
2247 struct list_head list;
2248 char *bus_name;
2249 char *dev_name;
2250 uint32_t port_index;
2251 uint32_t sb_index;
2252 struct list_head pool_list;
2253 struct list_head ing_tc_list;
2254 struct list_head eg_tc_list;
2255 };
2256
2257 struct occ_show {
2258 struct dl *dl;
2259 int err;
2260 struct list_head port_list;
2261 };
2262
2263 static struct occ_item *occ_item_alloc(void)
2264 {
2265 return calloc(1, sizeof(struct occ_item));
2266 }
2267
2268 static void occ_item_free(struct occ_item *occ_item)
2269 {
2270 free(occ_item);
2271 }
2272
2273 static struct occ_port *occ_port_alloc(uint32_t port_index)
2274 {
2275 struct occ_port *occ_port;
2276
2277 occ_port = calloc(1, sizeof(*occ_port));
2278 if (!occ_port)
2279 return NULL;
2280 occ_port->port_index = port_index;
2281 INIT_LIST_HEAD(&occ_port->pool_list);
2282 INIT_LIST_HEAD(&occ_port->ing_tc_list);
2283 INIT_LIST_HEAD(&occ_port->eg_tc_list);
2284 return occ_port;
2285 }
2286
2287 static void occ_port_free(struct occ_port *occ_port)
2288 {
2289 struct occ_item *occ_item, *tmp;
2290
2291 list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
2292 occ_item_free(occ_item);
2293 list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
2294 occ_item_free(occ_item);
2295 list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
2296 occ_item_free(occ_item);
2297 }
2298
2299 static struct occ_show *occ_show_alloc(struct dl *dl)
2300 {
2301 struct occ_show *occ_show;
2302
2303 occ_show = calloc(1, sizeof(*occ_show));
2304 if (!occ_show)
2305 return NULL;
2306 occ_show->dl = dl;
2307 INIT_LIST_HEAD(&occ_show->port_list);
2308 return occ_show;
2309 }
2310
2311 static void occ_show_free(struct occ_show *occ_show)
2312 {
2313 struct occ_port *occ_port, *tmp;
2314
2315 list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
2316 occ_port_free(occ_port);
2317 }
2318
2319 static struct occ_port *occ_port_get(struct occ_show *occ_show,
2320 struct nlattr **tb)
2321 {
2322 struct occ_port *occ_port;
2323 uint32_t port_index;
2324
2325 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2326
2327 list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
2328 if (occ_port->port_index == port_index)
2329 return occ_port;
2330 }
2331 occ_port = occ_port_alloc(port_index);
2332 if (!occ_port)
2333 return NULL;
2334 list_add_tail(&occ_port->list, &occ_show->port_list);
2335 return occ_port;
2336 }
2337
2338 static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
2339 bool bound_pool)
2340 {
2341 struct occ_item *occ_item;
2342 int i = 1;
2343
2344 pr_out_sp(7, " %s:", label);
2345 list_for_each_entry(occ_item, list, list) {
2346 if ((i - 1) % 4 == 0 && i != 1)
2347 pr_out_sp(7, " ");
2348 if (bound_pool)
2349 pr_out_sp(7, "%2u(%u):", occ_item->index,
2350 occ_item->bound_pool_index);
2351 else
2352 pr_out_sp(7, "%2u:", occ_item->index);
2353 pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max);
2354 if (i++ % 4 == 0)
2355 pr_out("\n");
2356 }
2357 if ((i - 1) % 4 != 0)
2358 pr_out("\n");
2359 }
2360
2361 static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
2362 struct list_head *list,
2363 bool bound_pool)
2364 {
2365 struct occ_item *occ_item;
2366 char buf[32];
2367
2368 jsonw_name(dl->jw, label);
2369 jsonw_start_object(dl->jw);
2370 list_for_each_entry(occ_item, list, list) {
2371 sprintf(buf, "%u", occ_item->index);
2372 jsonw_name(dl->jw, buf);
2373 jsonw_start_object(dl->jw);
2374 if (bound_pool)
2375 jsonw_uint_field(dl->jw, "bound_pool",
2376 occ_item->bound_pool_index);
2377 jsonw_uint_field(dl->jw, "current", occ_item->cur);
2378 jsonw_uint_field(dl->jw, "max", occ_item->max);
2379 jsonw_end_object(dl->jw);
2380 }
2381 jsonw_end_object(dl->jw);
2382 }
2383
2384 static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
2385 {
2386 if (dl->json_output) {
2387 pr_out_json_occ_show_item_list(dl, "pool",
2388 &occ_port->pool_list, false);
2389 pr_out_json_occ_show_item_list(dl, "itc",
2390 &occ_port->ing_tc_list, true);
2391 pr_out_json_occ_show_item_list(dl, "etc",
2392 &occ_port->eg_tc_list, true);
2393 } else {
2394 pr_out("\n");
2395 pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
2396 pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
2397 pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
2398 }
2399 }
2400
2401 static void pr_out_occ_show(struct occ_show *occ_show)
2402 {
2403 struct dl *dl = occ_show->dl;
2404 struct dl_opts *opts = &dl->opts;
2405 struct occ_port *occ_port;
2406
2407 list_for_each_entry(occ_port, &occ_show->port_list, list) {
2408 __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
2409 occ_port->port_index, true, false);
2410 pr_out_occ_show_port(dl, occ_port);
2411 pr_out_port_handle_end(dl);
2412 }
2413 }
2414
2415 static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
2416 struct nlattr **tb)
2417 {
2418 struct occ_port *occ_port;
2419 struct occ_item *occ_item;
2420
2421 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
2422 return;
2423
2424 occ_port = occ_port_get(occ_show, tb);
2425 if (!occ_port) {
2426 occ_show->err = -ENOMEM;
2427 return;
2428 }
2429
2430 occ_item = occ_item_alloc();
2431 if (!occ_item) {
2432 occ_show->err = -ENOMEM;
2433 return;
2434 }
2435 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
2436 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
2437 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
2438 list_add_tail(&occ_item->list, &occ_port->pool_list);
2439 }
2440
2441 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
2442 {
2443 struct occ_show *occ_show = data;
2444 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2445 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2446
2447 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2448 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2449 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2450 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
2451 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
2452 return MNL_CB_ERROR;
2453 cmd_sb_occ_port_pool_process(occ_show, tb);
2454 return MNL_CB_OK;
2455 }
2456
2457 static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
2458 struct nlattr **tb)
2459 {
2460 struct occ_port *occ_port;
2461 struct occ_item *occ_item;
2462 uint8_t pool_type;
2463
2464 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
2465 return;
2466
2467 occ_port = occ_port_get(occ_show, tb);
2468 if (!occ_port) {
2469 occ_show->err = -ENOMEM;
2470 return;
2471 }
2472
2473 occ_item = occ_item_alloc();
2474 if (!occ_item) {
2475 occ_show->err = -ENOMEM;
2476 return;
2477 }
2478 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
2479 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
2480 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
2481 occ_item->bound_pool_index =
2482 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
2483 pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
2484 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
2485 list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
2486 else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
2487 list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
2488 else
2489 occ_item_free(occ_item);
2490 }
2491
2492 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
2493 {
2494 struct occ_show *occ_show = data;
2495 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2496 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2497
2498 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2499 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2500 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2501 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
2502 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
2503 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
2504 return MNL_CB_ERROR;
2505 cmd_sb_occ_tc_pool_process(occ_show, tb);
2506 return MNL_CB_OK;
2507 }
2508
2509 static int cmd_sb_occ_show(struct dl *dl)
2510 {
2511 struct nlmsghdr *nlh;
2512 struct occ_show *occ_show;
2513 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
2514 int err;
2515
2516 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
2517 if (err)
2518 return err;
2519
2520 occ_show = occ_show_alloc(dl);
2521 if (!occ_show)
2522 return -ENOMEM;
2523
2524 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
2525
2526 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
2527 cmd_sb_occ_port_pool_process_cb, occ_show);
2528 if (err)
2529 goto out;
2530
2531 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
2532
2533 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
2534 cmd_sb_occ_tc_pool_process_cb, occ_show);
2535 if (err)
2536 goto out;
2537
2538 pr_out_section_start(dl, "occupancy");
2539 pr_out_occ_show(occ_show);
2540 pr_out_section_end(dl);
2541
2542 out:
2543 occ_show_free(occ_show);
2544 return err;
2545 }
2546
2547 static int cmd_sb_occ_snapshot(struct dl *dl)
2548 {
2549 struct nlmsghdr *nlh;
2550 int err;
2551
2552 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
2553 NLM_F_REQUEST | NLM_F_ACK);
2554
2555 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
2556 if (err)
2557 return err;
2558
2559 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2560 }
2561
2562 static int cmd_sb_occ_clearmax(struct dl *dl)
2563 {
2564 struct nlmsghdr *nlh;
2565 int err;
2566
2567 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
2568 NLM_F_REQUEST | NLM_F_ACK);
2569
2570 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
2571 if (err)
2572 return err;
2573
2574 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2575 }
2576
2577 static int cmd_sb_occ(struct dl *dl)
2578 {
2579 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2580 cmd_sb_help();
2581 return 0;
2582 } else if (dl_argv_match(dl, "show") ||
2583 dl_argv_match(dl, "list")) {
2584 dl_arg_inc(dl);
2585 return cmd_sb_occ_show(dl);
2586 } else if (dl_argv_match(dl, "snapshot")) {
2587 dl_arg_inc(dl);
2588 return cmd_sb_occ_snapshot(dl);
2589 } else if (dl_argv_match(dl, "clearmax")) {
2590 dl_arg_inc(dl);
2591 return cmd_sb_occ_clearmax(dl);
2592 }
2593 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2594 return -ENOENT;
2595 }
2596
2597 static int cmd_sb(struct dl *dl)
2598 {
2599 if (dl_argv_match(dl, "help")) {
2600 cmd_sb_help();
2601 return 0;
2602 } else if (dl_argv_match(dl, "show") ||
2603 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2604 dl_arg_inc(dl);
2605 return cmd_sb_show(dl);
2606 } else if (dl_argv_match(dl, "pool")) {
2607 dl_arg_inc(dl);
2608 return cmd_sb_pool(dl);
2609 } else if (dl_argv_match(dl, "port")) {
2610 dl_arg_inc(dl);
2611 return cmd_sb_port(dl);
2612 } else if (dl_argv_match(dl, "tc")) {
2613 dl_arg_inc(dl);
2614 return cmd_sb_tc(dl);
2615 } else if (dl_argv_match(dl, "occupancy")) {
2616 dl_arg_inc(dl);
2617 return cmd_sb_occ(dl);
2618 }
2619 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2620 return -ENOENT;
2621 }
2622
2623 static const char *cmd_name(uint8_t cmd)
2624 {
2625 switch (cmd) {
2626 case DEVLINK_CMD_UNSPEC: return "unspec";
2627 case DEVLINK_CMD_GET: return "get";
2628 case DEVLINK_CMD_SET: return "set";
2629 case DEVLINK_CMD_NEW: return "new";
2630 case DEVLINK_CMD_DEL: return "del";
2631 case DEVLINK_CMD_PORT_GET: return "get";
2632 case DEVLINK_CMD_PORT_SET: return "set";
2633 case DEVLINK_CMD_PORT_NEW: return "new";
2634 case DEVLINK_CMD_PORT_DEL: return "del";
2635 default: return "<unknown cmd>";
2636 }
2637 }
2638
2639 static const char *cmd_obj(uint8_t cmd)
2640 {
2641 switch (cmd) {
2642 case DEVLINK_CMD_UNSPEC: return "unspec";
2643 case DEVLINK_CMD_GET:
2644 case DEVLINK_CMD_SET:
2645 case DEVLINK_CMD_NEW:
2646 case DEVLINK_CMD_DEL:
2647 return "dev";
2648 case DEVLINK_CMD_PORT_GET:
2649 case DEVLINK_CMD_PORT_SET:
2650 case DEVLINK_CMD_PORT_NEW:
2651 case DEVLINK_CMD_PORT_DEL:
2652 return "port";
2653 default: return "<unknown obj>";
2654 }
2655 }
2656
2657 static void pr_out_mon_header(uint8_t cmd)
2658 {
2659 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
2660 }
2661
2662 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
2663 {
2664 const char *obj = cmd_obj(cmd);
2665 unsigned int index = 0;
2666 const char *cur_obj;
2667
2668 if (dl_no_arg(dl))
2669 return true;
2670 while ((cur_obj = dl_argv_index(dl, index++))) {
2671 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
2672 return true;
2673 }
2674 return false;
2675 }
2676
2677 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
2678 {
2679 struct dl *dl = data;
2680 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2681 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2682 uint8_t cmd = genl->cmd;
2683
2684 if (!cmd_filter_check(dl, cmd))
2685 return MNL_CB_OK;
2686
2687 switch (cmd) {
2688 case DEVLINK_CMD_GET: /* fall through */
2689 case DEVLINK_CMD_SET: /* fall through */
2690 case DEVLINK_CMD_NEW: /* fall through */
2691 case DEVLINK_CMD_DEL:
2692 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2693 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2694 return MNL_CB_ERROR;
2695 pr_out_mon_header(genl->cmd);
2696 pr_out_dev(dl, tb);
2697 break;
2698 case DEVLINK_CMD_PORT_GET: /* fall through */
2699 case DEVLINK_CMD_PORT_SET: /* fall through */
2700 case DEVLINK_CMD_PORT_NEW: /* fall through */
2701 case DEVLINK_CMD_PORT_DEL:
2702 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2703 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2704 !tb[DEVLINK_ATTR_PORT_INDEX])
2705 return MNL_CB_ERROR;
2706 pr_out_mon_header(genl->cmd);
2707 pr_out_port(dl, tb);
2708 break;
2709 }
2710 return MNL_CB_OK;
2711 }
2712
2713 static int cmd_mon_show(struct dl *dl)
2714 {
2715 int err;
2716 unsigned int index = 0;
2717 const char *cur_obj;
2718
2719 while ((cur_obj = dl_argv_index(dl, index++))) {
2720 if (strcmp(cur_obj, "all") != 0 &&
2721 strcmp(cur_obj, "dev") != 0 &&
2722 strcmp(cur_obj, "port") != 0) {
2723 pr_err("Unknown object \"%s\"\n", cur_obj);
2724 return -EINVAL;
2725 }
2726 }
2727 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
2728 if (err)
2729 return err;
2730 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
2731 if (err)
2732 return err;
2733 return 0;
2734 }
2735
2736 static void cmd_mon_help(void)
2737 {
2738 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
2739 "where OBJECT-LIST := { dev | port }\n");
2740 }
2741
2742 static int cmd_mon(struct dl *dl)
2743 {
2744 if (dl_argv_match(dl, "help")) {
2745 cmd_mon_help();
2746 return 0;
2747 } else if (dl_no_arg(dl)) {
2748 dl_arg_inc(dl);
2749 return cmd_mon_show(dl);
2750 }
2751 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2752 return -ENOENT;
2753 }
2754
2755 struct dpipe_field {
2756 char *name;
2757 unsigned int id;
2758 unsigned int bitwidth;
2759 enum devlink_dpipe_field_mapping_type mapping_type;
2760 };
2761
2762 struct dpipe_header {
2763 struct list_head list;
2764 char *name;
2765 unsigned int id;
2766 struct dpipe_field *fields;
2767 unsigned int fields_count;
2768 };
2769
2770 struct dpipe_table {
2771 struct list_head list;
2772 char *name;
2773 unsigned int resource_id;
2774 bool resource_valid;
2775 };
2776
2777 struct dpipe_tables {
2778 struct list_head table_list;
2779 };
2780
2781 struct resource {
2782 char *name;
2783 uint64_t size;
2784 uint64_t size_new;
2785 uint64_t size_min;
2786 uint64_t size_max;
2787 uint64_t size_gran;
2788 enum devlink_resource_unit unit;
2789 bool size_valid;
2790 uint64_t size_occ;
2791 bool occ_valid;
2792 uint64_t id;
2793 struct list_head list;
2794 struct list_head resource_list;
2795 struct resource *parent;
2796 };
2797
2798 struct resources {
2799 struct list_head resource_list;
2800 };
2801
2802 struct resource_ctx {
2803 struct dl *dl;
2804 int err;
2805 struct resources *resources;
2806 struct dpipe_tables *tables;
2807 bool print_resources;
2808 bool pending_change;
2809 };
2810
2811 static struct resource *resource_alloc(void)
2812 {
2813 struct resource *resource;
2814
2815 resource = calloc(1, sizeof(struct resource));
2816 if (!resource)
2817 return NULL;
2818 INIT_LIST_HEAD(&resource->resource_list);
2819 return resource;
2820 }
2821
2822 static void resource_free(struct resource *resource)
2823 {
2824 struct resource *child_resource, *tmp;
2825
2826 list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
2827 list) {
2828 free(child_resource->name);
2829 resource_free(child_resource);
2830 }
2831 free(resource);
2832 }
2833
2834 static struct resources *resources_alloc(void)
2835 {
2836 struct resources *resources;
2837
2838 resources = calloc(1, sizeof(struct resources));
2839 if (!resources)
2840 return NULL;
2841 INIT_LIST_HEAD(&resources->resource_list);
2842 return resources;
2843 }
2844
2845 static void resources_free(struct resources *resources)
2846 {
2847 struct resource *resource, *tmp;
2848
2849 list_for_each_entry_safe(resource, tmp, &resources->resource_list, list)
2850 resource_free(resource);
2851 }
2852
2853 static int resource_ctx_init(struct resource_ctx *ctx, struct dl *dl)
2854 {
2855 ctx->resources = resources_alloc();
2856 if (!ctx->resources)
2857 return -ENOMEM;
2858 ctx->dl = dl;
2859 return 0;
2860 }
2861
2862 static void resource_ctx_fini(struct resource_ctx *ctx)
2863 {
2864 resources_free(ctx->resources);
2865 }
2866
2867 struct dpipe_ctx {
2868 struct dl *dl;
2869 int err;
2870 struct list_head global_headers;
2871 struct list_head local_headers;
2872 struct dpipe_tables *tables;
2873 struct resources *resources;
2874 bool print_headers;
2875 bool print_tables;
2876 };
2877
2878 static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
2879 {
2880 struct dpipe_header *header;
2881
2882 header = calloc(1, sizeof(struct dpipe_header));
2883 if (!header)
2884 return NULL;
2885 header->fields = calloc(fields_count, sizeof(struct dpipe_field));
2886 if (!header->fields)
2887 goto err_fields_alloc;
2888 header->fields_count = fields_count;
2889 return header;
2890
2891 err_fields_alloc:
2892 free(header);
2893 return NULL;
2894 }
2895
2896 static void dpipe_header_free(struct dpipe_header *header)
2897 {
2898 free(header->fields);
2899 free(header);
2900 }
2901
2902 static void dpipe_header_clear(struct dpipe_header *header)
2903 {
2904 struct dpipe_field *field;
2905 int i;
2906
2907 for (i = 0; i < header->fields_count; i++) {
2908 field = &header->fields[i];
2909 free(field->name);
2910 }
2911 free(header->name);
2912 }
2913
2914 static void dpipe_header_add(struct dpipe_ctx *ctx,
2915 struct dpipe_header *header, bool global)
2916 {
2917 if (global)
2918 list_add(&header->list, &ctx->global_headers);
2919 else
2920 list_add(&header->list, &ctx->local_headers);
2921 }
2922
2923 static void dpipe_header_del(struct dpipe_header *header)
2924 {
2925 list_del(&header->list);
2926 }
2927
2928 static struct dpipe_table *dpipe_table_alloc(void)
2929 {
2930 return calloc(1, sizeof(struct dpipe_table));
2931 }
2932
2933 static void dpipe_table_free(struct dpipe_table *table)
2934 {
2935 free(table);
2936 }
2937
2938 static struct dpipe_tables *dpipe_tables_alloc(void)
2939 {
2940 struct dpipe_tables *tables;
2941
2942 tables = calloc(1, sizeof(struct dpipe_tables));
2943 if (!tables)
2944 return NULL;
2945 INIT_LIST_HEAD(&tables->table_list);
2946 return tables;
2947 }
2948
2949 static void dpipe_tables_free(struct dpipe_tables *tables)
2950 {
2951 struct dpipe_table *table, *tmp;
2952
2953 list_for_each_entry_safe(table, tmp, &tables->table_list, list)
2954 dpipe_table_free(table);
2955 free(tables);
2956 }
2957
2958 static int dpipe_ctx_init(struct dpipe_ctx *ctx, struct dl *dl)
2959 {
2960 ctx->tables = dpipe_tables_alloc();
2961 if (!ctx->tables)
2962 return -ENOMEM;
2963
2964 ctx->dl = dl;
2965 INIT_LIST_HEAD(&ctx->global_headers);
2966 INIT_LIST_HEAD(&ctx->local_headers);
2967 return 0;
2968 }
2969
2970 static void dpipe_ctx_fini(struct dpipe_ctx *ctx)
2971 {
2972 struct dpipe_header *header, *tmp;
2973
2974 list_for_each_entry_safe(header, tmp, &ctx->global_headers,
2975 list) {
2976 dpipe_header_del(header);
2977 dpipe_header_clear(header);
2978 dpipe_header_free(header);
2979 }
2980 list_for_each_entry_safe(header, tmp, &ctx->local_headers,
2981 list) {
2982 dpipe_header_del(header);
2983 dpipe_header_clear(header);
2984 dpipe_header_free(header);
2985 }
2986 dpipe_tables_free(ctx->tables);
2987 }
2988
2989 static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
2990 uint32_t header_id, bool global)
2991 {
2992 struct list_head *header_list;
2993 struct dpipe_header *header;
2994
2995 if (global)
2996 header_list = &ctx->global_headers;
2997 else
2998 header_list = &ctx->local_headers;
2999 list_for_each_entry(header, header_list, list) {
3000 if (header->id != header_id)
3001 continue;
3002 return header->name;
3003 }
3004 return NULL;
3005 }
3006
3007 static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
3008 uint32_t header_id,
3009 uint32_t field_id, bool global)
3010 {
3011 struct list_head *header_list;
3012 struct dpipe_header *header;
3013
3014 if (global)
3015 header_list = &ctx->global_headers;
3016 else
3017 header_list = &ctx->local_headers;
3018 list_for_each_entry(header, header_list, list) {
3019 if (header->id != header_id)
3020 continue;
3021 return header->fields[field_id].name;
3022 }
3023 return NULL;
3024 }
3025
3026 static const char *
3027 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
3028 {
3029 switch (mapping_type) {
3030 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
3031 return NULL;
3032 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
3033 return "ifindex";
3034 default:
3035 return "<unknown>";
3036 }
3037 }
3038
3039 static const char *
3040 dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
3041 uint32_t field_id, bool global)
3042 {
3043 enum devlink_dpipe_field_mapping_type mapping_type;
3044 struct list_head *header_list;
3045 struct dpipe_header *header;
3046
3047 if (global)
3048 header_list = &ctx->global_headers;
3049 else
3050 header_list = &ctx->local_headers;
3051 list_for_each_entry(header, header_list, list) {
3052 if (header->id != header_id)
3053 continue;
3054 mapping_type = header->fields[field_id].mapping_type;
3055 return dpipe_field_mapping_e2s(mapping_type);
3056 }
3057 return NULL;
3058 }
3059
3060 static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
3061 struct dpipe_field *fields,
3062 unsigned int field_count)
3063 {
3064 struct dpipe_field *field;
3065 int i;
3066
3067 for (i = 0; i < field_count; i++) {
3068 field = &fields[i];
3069 pr_out_entry_start(ctx->dl);
3070 pr_out_str(ctx->dl, "name", field->name);
3071 if (ctx->dl->verbose)
3072 pr_out_uint(ctx->dl, "id", field->id);
3073 pr_out_uint(ctx->dl, "bitwidth", field->bitwidth);
3074 if (field->mapping_type)
3075 pr_out_str(ctx->dl, "mapping_type",
3076 dpipe_field_mapping_e2s(field->mapping_type));
3077 pr_out_entry_end(ctx->dl);
3078 }
3079 }
3080
3081 static void
3082 pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
3083 struct dpipe_header *header, bool global)
3084 {
3085 pr_out_handle_start_arr(ctx->dl, tb);
3086 pr_out_str(ctx->dl, "name", header->name);
3087 if (ctx->dl->verbose) {
3088 pr_out_uint(ctx->dl, "id", header->id);
3089 pr_out_str(ctx->dl, "global",
3090 global ? "true" : "false");
3091 }
3092 pr_out_array_start(ctx->dl, "field");
3093 pr_out_dpipe_fields(ctx, header->fields,
3094 header->fields_count);
3095 pr_out_array_end(ctx->dl);
3096 pr_out_handle_end(ctx->dl);
3097 }
3098
3099 static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
3100 struct nlattr **tb)
3101 {
3102 struct dpipe_header *header;
3103
3104 list_for_each_entry(header, &ctx->local_headers, list)
3105 pr_out_dpipe_header(ctx, tb, header, false);
3106
3107 list_for_each_entry(header, &ctx->global_headers, list)
3108 pr_out_dpipe_header(ctx, tb, header, true);
3109 }
3110
3111 static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
3112 {
3113 struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
3114 const char *name;
3115 int err;
3116
3117 err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
3118 if (err != MNL_CB_OK)
3119 return -EINVAL;
3120 if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
3121 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
3122 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
3123 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
3124 return -EINVAL;
3125
3126 name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
3127 field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
3128 field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
3129 field->name = strdup(name);
3130 if (!field->name)
3131 return -ENOMEM;
3132 field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
3133 return 0;
3134 }
3135
3136 static int dpipe_header_fields_get(struct nlattr *nla_fields,
3137 struct dpipe_field *fields)
3138 {
3139 struct nlattr *nla_field;
3140 int count = 0;
3141 int err;
3142
3143 mnl_attr_for_each_nested(nla_field, nla_fields) {
3144 err = dpipe_header_field_get(nla_field, &fields[count]);
3145 if (err)
3146 return err;
3147 count++;
3148 }
3149 return 0;
3150 }
3151
3152 static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
3153 {
3154 struct nlattr *nla_field;
3155 unsigned int count = 0;
3156
3157 mnl_attr_for_each_nested(nla_field, nla_fields)
3158 count++;
3159 return count;
3160 }
3161
3162 static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
3163 {
3164 struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
3165 struct dpipe_header *header;
3166 unsigned int fields_count;
3167 const char *header_name;
3168 bool global;
3169 int err;
3170
3171 err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
3172 if (err != MNL_CB_OK)
3173 return -EINVAL;
3174
3175 if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
3176 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
3177 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
3178 return -EINVAL;
3179
3180 fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
3181 header = dpipe_header_alloc(fields_count);
3182 if (!header)
3183 return -ENOMEM;
3184
3185 header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
3186 header->name = strdup(header_name);
3187 header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
3188 header->fields_count = fields_count;
3189 global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
3190
3191 err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
3192 header->fields);
3193 if (err)
3194 goto err_field_get;
3195 dpipe_header_add(ctx, header, global);
3196 return 0;
3197
3198 err_field_get:
3199 dpipe_header_free(header);
3200 return err;
3201 }
3202
3203 static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
3204 {
3205 struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
3206 struct nlattr *nla_header;
3207 int err;
3208
3209 mnl_attr_for_each_nested(nla_header, nla_headers) {
3210 err = dpipe_header_get(ctx, nla_header);
3211 if (err)
3212 return err;
3213 }
3214 return 0;
3215 }
3216
3217 static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
3218 {
3219 struct dpipe_ctx *ctx = data;
3220 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3221 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3222 int err;
3223
3224 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3225 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3226 !tb[DEVLINK_ATTR_DPIPE_HEADERS])
3227 return MNL_CB_ERROR;
3228 err = dpipe_headers_get(ctx, tb);
3229 if (err) {
3230 ctx->err = err;
3231 return MNL_CB_ERROR;
3232 }
3233
3234 if (ctx->print_headers)
3235 pr_out_dpipe_headers(ctx, tb);
3236 return MNL_CB_OK;
3237 }
3238
3239 static int cmd_dpipe_headers_show(struct dl *dl)
3240 {
3241 struct nlmsghdr *nlh;
3242 struct dpipe_ctx ctx = {};
3243 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3244 int err;
3245
3246 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3247
3248 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3249 if (err)
3250 return err;
3251
3252 err = dpipe_ctx_init(&ctx, dl);
3253 if (err)
3254 return err;
3255
3256 ctx.print_headers = true;
3257
3258 pr_out_section_start(dl, "header");
3259 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
3260 if (err)
3261 pr_err("error get headers %s\n", strerror(ctx.err));
3262 pr_out_section_end(dl);
3263
3264 dpipe_ctx_fini(&ctx);
3265 return err;
3266 }
3267
3268 static void cmd_dpipe_header_help(void)
3269 {
3270 pr_err("Usage: devlink dpipe headers show DEV\n");
3271 }
3272
3273 static int cmd_dpipe_header(struct dl *dl)
3274 {
3275 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3276 cmd_dpipe_header_help();
3277 return 0;
3278 } else if (dl_argv_match(dl, "show")) {
3279 dl_arg_inc(dl);
3280 return cmd_dpipe_headers_show(dl);
3281 }
3282 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3283 return -ENOENT;
3284 }
3285
3286 static const char
3287 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
3288 {
3289 switch (action_type) {
3290 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
3291 return "field_modify";
3292 default:
3293 return "<unknown>";
3294 }
3295 }
3296
3297 struct dpipe_op_info {
3298 uint32_t header_id;
3299 uint32_t field_id;
3300 bool header_global;
3301 };
3302
3303 struct dpipe_action {
3304 struct dpipe_op_info info;
3305 uint32_t type;
3306 };
3307
3308 static void pr_out_dpipe_action(struct dpipe_action *action,
3309 struct dpipe_ctx *ctx)
3310 {
3311 struct dpipe_op_info *op_info = &action->info;
3312 const char *mapping;
3313
3314 pr_out_str(ctx->dl, "type",
3315 dpipe_action_type_e2s(action->type));
3316 pr_out_str(ctx->dl, "header",
3317 dpipe_header_id2s(ctx, op_info->header_id,
3318 op_info->header_global));
3319 pr_out_str(ctx->dl, "field",
3320 dpipe_field_id2s(ctx, op_info->header_id,
3321 op_info->field_id,
3322 op_info->header_global));
3323 mapping = dpipe_mapping_get(ctx, op_info->header_id,
3324 op_info->field_id,
3325 op_info->header_global);
3326 if (mapping)
3327 pr_out_str(ctx->dl, "mapping", mapping);
3328 }
3329
3330 static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
3331 {
3332 struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
3333 int err;
3334
3335 err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
3336 if (err != MNL_CB_OK)
3337 return -EINVAL;
3338
3339 if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
3340 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
3341 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
3342 !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
3343 return -EINVAL;
3344 }
3345
3346 action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
3347 action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
3348 action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
3349 action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
3350
3351 return 0;
3352 }
3353
3354 static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
3355 struct nlattr *nla_actions)
3356 {
3357 struct nlattr *nla_action;
3358 struct dpipe_action action;
3359
3360 mnl_attr_for_each_nested(nla_action, nla_actions) {
3361 pr_out_entry_start(ctx->dl);
3362 if (dpipe_action_parse(&action, nla_action))
3363 goto err_action_parse;
3364 pr_out_dpipe_action(&action, ctx);
3365 pr_out_entry_end(ctx->dl);
3366 }
3367 return 0;
3368
3369 err_action_parse:
3370 pr_out_entry_end(ctx->dl);
3371 return -EINVAL;
3372 }
3373
3374 static const char *
3375 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
3376 {
3377 switch (match_type) {
3378 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
3379 return "field_exact";
3380 default:
3381 return "<unknown>";
3382 }
3383 }
3384
3385 struct dpipe_match {
3386 struct dpipe_op_info info;
3387 uint32_t type;
3388 };
3389
3390 static void pr_out_dpipe_match(struct dpipe_match *match,
3391 struct dpipe_ctx *ctx)
3392 {
3393 struct dpipe_op_info *op_info = &match->info;
3394 const char *mapping;
3395
3396 pr_out_str(ctx->dl, "type",
3397 dpipe_match_type_e2s(match->type));
3398 pr_out_str(ctx->dl, "header",
3399 dpipe_header_id2s(ctx, op_info->header_id,
3400 op_info->header_global));
3401 pr_out_str(ctx->dl, "field",
3402 dpipe_field_id2s(ctx, op_info->header_id,
3403 op_info->field_id,
3404 op_info->header_global));
3405 mapping = dpipe_mapping_get(ctx, op_info->header_id,
3406 op_info->field_id,
3407 op_info->header_global);
3408 if (mapping)
3409 pr_out_str(ctx->dl, "mapping", mapping);
3410 }
3411
3412 static int dpipe_match_parse(struct dpipe_match *match,
3413 struct nlattr *nl)
3414
3415 {
3416 struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
3417 int err;
3418
3419 err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
3420 if (err != MNL_CB_OK)
3421 return -EINVAL;
3422
3423 if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
3424 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
3425 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
3426 !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
3427 return -EINVAL;
3428 }
3429
3430 match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
3431 match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
3432 match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
3433 match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
3434
3435 return 0;
3436 }
3437
3438 static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
3439 struct nlattr *nla_matches)
3440 {
3441 struct nlattr *nla_match;
3442 struct dpipe_match match;
3443
3444 mnl_attr_for_each_nested(nla_match, nla_matches) {
3445 pr_out_entry_start(ctx->dl);
3446 if (dpipe_match_parse(&match, nla_match))
3447 goto err_match_parse;
3448 pr_out_dpipe_match(&match, ctx);
3449 pr_out_entry_end(ctx->dl);
3450 }
3451 return 0;
3452
3453 err_match_parse:
3454 pr_out_entry_end(ctx->dl);
3455 return -EINVAL;
3456 }
3457
3458 static struct resource *
3459 resource_find(struct resources *resources, struct resource *resource,
3460 uint64_t resource_id)
3461 {
3462 struct list_head *list_head;
3463
3464 if (!resource)
3465 list_head = &resources->resource_list;
3466 else
3467 list_head = &resource->resource_list;
3468
3469 list_for_each_entry(resource, list_head, list) {
3470 struct resource *child_resource;
3471
3472 if (resource->id == resource_id)
3473 return resource;
3474
3475 child_resource = resource_find(resources, resource,
3476 resource_id);
3477 if (child_resource)
3478 return child_resource;
3479 }
3480 return NULL;
3481 }
3482
3483 static void
3484 resource_path_print(struct dl *dl, struct resources *resources,
3485 uint64_t resource_id)
3486 {
3487 struct resource *resource, *parent_resource;
3488 const char del[] = "/";
3489 int path_len = 0;
3490 char *path;
3491
3492 resource = resource_find(resources, NULL, resource_id);
3493 if (!resource)
3494 return;
3495
3496 for (parent_resource = resource; parent_resource;
3497 parent_resource = parent_resource->parent)
3498 path_len += strlen(parent_resource->name) + 1;
3499
3500 path_len++;
3501 path = calloc(1, path_len);
3502 if (!path)
3503 return;
3504
3505 path += path_len - 1;
3506 for (parent_resource = resource; parent_resource;
3507 parent_resource = parent_resource->parent) {
3508 path -= strlen(parent_resource->name);
3509 memcpy(path, parent_resource->name,
3510 strlen(parent_resource->name));
3511 path -= strlen(del);
3512 memcpy(path, del, strlen(del));
3513 }
3514 pr_out_str(dl, "resource_path", path);
3515 free(path);
3516 }
3517
3518 static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
3519 {
3520 struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
3521 struct dpipe_table *table;
3522 uint32_t resource_units;
3523 bool counters_enabled;
3524 bool resource_valid;
3525 uint32_t size;
3526 int err;
3527
3528 err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
3529 if (err != MNL_CB_OK)
3530 return -EINVAL;
3531
3532 if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
3533 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
3534 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
3535 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
3536 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
3537 return -EINVAL;
3538 }
3539
3540 table = dpipe_table_alloc();
3541 if (!table)
3542 return -ENOMEM;
3543
3544 table->name = strdup(mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]));
3545 size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
3546 counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
3547
3548 resource_valid = !!nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID];
3549 if (resource_valid) {
3550 table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
3551 table->resource_valid = true;
3552 }
3553
3554 list_add_tail(&table->list, &ctx->tables->table_list);
3555 if (!ctx->print_tables)
3556 return 0;
3557
3558 pr_out_str(ctx->dl, "name", table->name);
3559 pr_out_uint(ctx->dl, "size", size);
3560 pr_out_str(ctx->dl, "counters_enabled",
3561 counters_enabled ? "true" : "false");
3562
3563 if (resource_valid) {
3564 resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
3565 resource_path_print(ctx->dl, ctx->resources,
3566 table->resource_id);
3567 pr_out_uint(ctx->dl, "resource_units", resource_units);
3568 }
3569
3570 pr_out_array_start(ctx->dl, "match");
3571 if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
3572 goto err_matches_show;
3573 pr_out_array_end(ctx->dl);
3574
3575 pr_out_array_start(ctx->dl, "action");
3576 if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
3577 goto err_actions_show;
3578 pr_out_array_end(ctx->dl);
3579
3580 return 0;
3581
3582 err_actions_show:
3583 err_matches_show:
3584 pr_out_array_end(ctx->dl);
3585 return -EINVAL;
3586 }
3587
3588 static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
3589 {
3590 struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
3591 struct nlattr *nla_table;
3592
3593 mnl_attr_for_each_nested(nla_table, nla_tables) {
3594 if (ctx->print_tables)
3595 pr_out_handle_start_arr(ctx->dl, tb);
3596 if (dpipe_table_show(ctx, nla_table))
3597 goto err_table_show;
3598 if (ctx->print_tables)
3599 pr_out_handle_end(ctx->dl);
3600 }
3601 return 0;
3602
3603 err_table_show:
3604 if (ctx->print_tables)
3605 pr_out_handle_end(ctx->dl);
3606 return -EINVAL;
3607 }
3608
3609 static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
3610 {
3611 struct dpipe_ctx *ctx = data;
3612 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3613 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3614
3615 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3616 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3617 !tb[DEVLINK_ATTR_DPIPE_TABLES])
3618 return MNL_CB_ERROR;
3619
3620 if (dpipe_tables_show(ctx, tb))
3621 return MNL_CB_ERROR;
3622 return MNL_CB_OK;
3623 }
3624
3625 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data);
3626
3627 static int cmd_dpipe_table_show(struct dl *dl)
3628 {
3629 struct nlmsghdr *nlh;
3630 struct dpipe_ctx dpipe_ctx = {};
3631 struct resource_ctx resource_ctx = {};
3632 uint16_t flags = NLM_F_REQUEST;
3633 int err;
3634
3635 err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
3636 if (err)
3637 return err;
3638
3639 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3640
3641 err = dpipe_ctx_init(&dpipe_ctx, dl);
3642 if (err)
3643 return err;
3644
3645 dpipe_ctx.print_tables = true;
3646
3647 dl_opts_put(nlh, dl);
3648 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb,
3649 &dpipe_ctx);
3650 if (err) {
3651 pr_err("error get headers %s\n", strerror(dpipe_ctx.err));
3652 goto err_headers_get;
3653 }
3654
3655 err = resource_ctx_init(&resource_ctx, dl);
3656 if (err)
3657 goto err_resource_ctx_init;
3658
3659 resource_ctx.print_resources = false;
3660 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags);
3661 dl_opts_put(nlh, dl);
3662 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
3663 &resource_ctx);
3664 if (err) {
3665 pr_err("error get resources %s\n", strerror(resource_ctx.err));
3666 goto err_resource_dump;
3667 }
3668
3669 dpipe_ctx.resources = resource_ctx.resources;
3670 flags = NLM_F_REQUEST | NLM_F_ACK;
3671 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
3672 dl_opts_put(nlh, dl);
3673
3674 pr_out_section_start(dl, "table");
3675 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx);
3676 pr_out_section_end(dl);
3677
3678 resource_ctx_fini(&resource_ctx);
3679 dpipe_ctx_fini(&dpipe_ctx);
3680 return 0;
3681
3682 err_resource_dump:
3683 resource_ctx_fini(&resource_ctx);
3684 err_resource_ctx_init:
3685 err_headers_get:
3686 dpipe_ctx_fini(&dpipe_ctx);
3687 return err;
3688 }
3689
3690 static int cmd_dpipe_table_set(struct dl *dl)
3691 {
3692 struct nlmsghdr *nlh;
3693 int err;
3694
3695 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
3696 NLM_F_REQUEST | NLM_F_ACK);
3697
3698 err = dl_argv_parse_put(nlh, dl,
3699 DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
3700 DL_OPT_DPIPE_TABLE_COUNTERS, 0);
3701 if (err)
3702 return err;
3703
3704 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3705 }
3706
3707 enum dpipe_value_type {
3708 DPIPE_VALUE_TYPE_VALUE,
3709 DPIPE_VALUE_TYPE_MASK,
3710 };
3711
3712 static const char *
3713 dpipe_value_type_e2s(enum dpipe_value_type type)
3714 {
3715 switch (type) {
3716 case DPIPE_VALUE_TYPE_VALUE:
3717 return "value";
3718 case DPIPE_VALUE_TYPE_MASK:
3719 return "value_mask";
3720 default:
3721 return "<unknown>";
3722 }
3723 }
3724
3725 struct dpipe_field_printer {
3726 unsigned int field_id;
3727 void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
3728 };
3729
3730 struct dpipe_header_printer {
3731 struct dpipe_field_printer *printers;
3732 unsigned int printers_count;
3733 unsigned int header_id;
3734 };
3735
3736 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
3737 enum dpipe_value_type type,
3738 void *value)
3739 {
3740 struct in_addr ip_addr;
3741
3742 ip_addr.s_addr = htonl(*(uint32_t *)value);
3743 pr_out_str(ctx->dl, dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
3744 }
3745
3746 static void
3747 dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
3748 enum dpipe_value_type type,
3749 void *value)
3750 {
3751 pr_out_str(ctx->dl, dpipe_value_type_e2s(type),
3752 ether_ntoa((struct ether_addr *)value));
3753 }
3754
3755 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
3756 enum dpipe_value_type type,
3757 void *value)
3758 {
3759 char str[INET6_ADDRSTRLEN];
3760
3761 inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
3762 pr_out_str(ctx->dl, dpipe_value_type_e2s(type), str);
3763 }
3764
3765 static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
3766 {
3767 .printer = dpipe_field_printer_ipv4_addr,
3768 .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
3769 }
3770 };
3771
3772 static struct dpipe_header_printer dpipe_header_printer_ipv4 = {
3773 .printers = dpipe_field_printers_ipv4,
3774 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
3775 .header_id = DEVLINK_DPIPE_HEADER_IPV4,
3776 };
3777
3778 static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
3779 {
3780 .printer = dpipe_field_printer_ethernet_addr,
3781 .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
3782 },
3783 };
3784
3785 static struct dpipe_header_printer dpipe_header_printer_ethernet = {
3786 .printers = dpipe_field_printers_ethernet,
3787 .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
3788 .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
3789 };
3790
3791 static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
3792 {
3793 .printer = dpipe_field_printer_ipv6_addr,
3794 .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
3795 }
3796 };
3797
3798 static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
3799 .printers = dpipe_field_printers_ipv6,
3800 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
3801 .header_id = DEVLINK_DPIPE_HEADER_IPV6,
3802 };
3803
3804 static struct dpipe_header_printer *dpipe_header_printers[] = {
3805 &dpipe_header_printer_ipv4,
3806 &dpipe_header_printer_ethernet,
3807 &dpipe_header_printer_ipv6,
3808 };
3809
3810 static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
3811 struct dpipe_op_info *info,
3812 enum dpipe_value_type type,
3813 void *value)
3814 {
3815 unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
3816 struct dpipe_header_printer *header_printer;
3817 struct dpipe_field_printer *field_printer;
3818 unsigned int field_printers_count;
3819 int j;
3820 int i;
3821
3822 for (i = 0; i < header_printers_count; i++) {
3823 header_printer = dpipe_header_printers[i];
3824 if (header_printer->header_id != info->header_id)
3825 continue;
3826 field_printers_count = header_printer->printers_count;
3827 for (j = 0; j < field_printers_count; j++) {
3828 field_printer = &header_printer->printers[j];
3829 if (field_printer->field_id != info->field_id)
3830 continue;
3831 field_printer->printer(ctx, type, value);
3832 return 0;
3833 }
3834 }
3835
3836 return -EINVAL;
3837 }
3838
3839 static void __pr_out_entry_value(struct dpipe_ctx *ctx,
3840 void *value,
3841 unsigned int value_len,
3842 struct dpipe_op_info *info,
3843 enum dpipe_value_type type)
3844 {
3845 if (info->header_global &&
3846 !dpipe_print_prot_header(ctx, info, type, value))
3847 return;
3848
3849 if (value_len == sizeof(uint32_t)) {
3850 uint32_t *value_32 = value;
3851
3852 pr_out_uint(ctx->dl, dpipe_value_type_e2s(type), *value_32);
3853 }
3854 }
3855
3856 static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
3857 struct nlattr **nla_match_value,
3858 struct dpipe_op_info *info)
3859 {
3860 void *value, *value_mask;
3861 uint32_t value_mapping;
3862 uint16_t value_len;
3863 bool mask, mapping;
3864
3865 mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
3866 mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
3867
3868 value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3869 value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3870
3871 if (mapping) {
3872 value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
3873 pr_out_uint(ctx->dl, "mapping_value", value_mapping);
3874 }
3875
3876 if (mask) {
3877 value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3878 __pr_out_entry_value(ctx, value_mask, value_len, info,
3879 DPIPE_VALUE_TYPE_MASK);
3880 }
3881
3882 __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
3883 }
3884
3885 static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
3886 struct nlattr *nl)
3887 {
3888 struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
3889 struct dpipe_match match;
3890 int err;
3891
3892 err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
3893 if (err != MNL_CB_OK)
3894 return -EINVAL;
3895
3896 if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
3897 !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
3898 return -EINVAL;
3899 }
3900
3901 pr_out_entry_start(ctx->dl);
3902 if (dpipe_match_parse(&match,
3903 nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
3904 goto err_match_parse;
3905 pr_out_dpipe_match(&match, ctx);
3906 pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
3907 pr_out_entry_end(ctx->dl);
3908
3909 return 0;
3910
3911 err_match_parse:
3912 pr_out_entry_end(ctx->dl);
3913 return -EINVAL;
3914 }
3915
3916 static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
3917 struct nlattr *nl)
3918 {
3919 struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
3920 struct dpipe_action action;
3921 int err;
3922
3923 err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
3924 if (err != MNL_CB_OK)
3925 return -EINVAL;
3926
3927 if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
3928 !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
3929 return -EINVAL;
3930 }
3931
3932 pr_out_entry_start(ctx->dl);
3933 if (dpipe_action_parse(&action,
3934 nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
3935 goto err_action_parse;
3936 pr_out_dpipe_action(&action, ctx);
3937 pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
3938 pr_out_entry_end(ctx->dl);
3939
3940 return 0;
3941
3942 err_action_parse:
3943 pr_out_entry_end(ctx->dl);
3944 return -EINVAL;
3945 }
3946
3947 static int
3948 dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
3949 struct nlattr *nla_action_values)
3950 {
3951 struct nlattr *nla_action_value;
3952
3953 mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
3954 if (dpipe_entry_action_value_show(ctx, nla_action_value))
3955 return -EINVAL;
3956 }
3957 return 0;
3958 }
3959
3960 static int
3961 dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
3962 struct nlattr *nla_match_values)
3963 {
3964 struct nlattr *nla_match_value;
3965
3966 mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
3967 if (dpipe_entry_match_value_show(ctx, nla_match_value))
3968 return -EINVAL;
3969 }
3970 return 0;
3971 }
3972
3973 static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
3974 {
3975 struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
3976 uint32_t entry_index;
3977 uint64_t counter;
3978 int err;
3979
3980 err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
3981 if (err != MNL_CB_OK)
3982 return -EINVAL;
3983
3984 if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
3985 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
3986 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
3987 return -EINVAL;
3988 }
3989
3990 entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
3991 pr_out_uint(ctx->dl, "index", entry_index);
3992
3993 if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
3994 counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
3995 pr_out_uint(ctx->dl, "counter", counter);
3996 }
3997
3998 pr_out_array_start(ctx->dl, "match_value");
3999 if (dpipe_tables_match_values_show(ctx,
4000 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
4001 goto err_match_values_show;
4002 pr_out_array_end(ctx->dl);
4003
4004 pr_out_array_start(ctx->dl, "action_value");
4005 if (dpipe_tables_action_values_show(ctx,
4006 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
4007 goto err_action_values_show;
4008 pr_out_array_end(ctx->dl);
4009 return 0;
4010
4011 err_action_values_show:
4012 err_match_values_show:
4013 pr_out_array_end(ctx->dl);
4014 return -EINVAL;
4015 }
4016
4017 static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
4018 {
4019 struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
4020 struct nlattr *nla_entry;
4021
4022 mnl_attr_for_each_nested(nla_entry, nla_entries) {
4023 pr_out_handle_start_arr(ctx->dl, tb);
4024 if (dpipe_entry_show(ctx, nla_entry))
4025 goto err_entry_show;
4026 pr_out_handle_end(ctx->dl);
4027 }
4028 return 0;
4029
4030 err_entry_show:
4031 pr_out_handle_end(ctx->dl);
4032 return -EINVAL;
4033 }
4034
4035 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
4036 {
4037 struct dpipe_ctx *ctx = data;
4038 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4039 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4040
4041 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4042 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4043 !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
4044 return MNL_CB_ERROR;
4045
4046 if (dpipe_table_entries_show(ctx, tb))
4047 return MNL_CB_ERROR;
4048 return MNL_CB_OK;
4049 }
4050
4051 static int cmd_dpipe_table_dump(struct dl *dl)
4052 {
4053 struct nlmsghdr *nlh;
4054 struct dpipe_ctx ctx = {};
4055 uint16_t flags = NLM_F_REQUEST;
4056 int err;
4057
4058 err = dpipe_ctx_init(&ctx, dl);
4059 if (err)
4060 return err;
4061
4062 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
4063 if (err)
4064 goto out;
4065
4066 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
4067 dl_opts_put(nlh, dl);
4068 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
4069 if (err) {
4070 pr_err("error get headers %s\n", strerror(ctx.err));
4071 goto out;
4072 }
4073
4074 flags = NLM_F_REQUEST | NLM_F_ACK;
4075 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
4076 dl_opts_put(nlh, dl);
4077
4078 pr_out_section_start(dl, "table_entry");
4079 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx);
4080 pr_out_section_end(dl);
4081 out:
4082 dpipe_ctx_fini(&ctx);
4083 return err;
4084 }
4085
4086 static void cmd_dpipe_table_help(void)
4087 {
4088 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
4089 "where OBJECT-LIST := { show | set | dump }\n");
4090 }
4091
4092 static int cmd_dpipe_table(struct dl *dl)
4093 {
4094 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4095 cmd_dpipe_table_help();
4096 return 0;
4097 } else if (dl_argv_match(dl, "show")) {
4098 dl_arg_inc(dl);
4099 return cmd_dpipe_table_show(dl);
4100 } else if (dl_argv_match(dl, "set")) {
4101 dl_arg_inc(dl);
4102 return cmd_dpipe_table_set(dl);
4103 } else if (dl_argv_match(dl, "dump")) {
4104 dl_arg_inc(dl);
4105 return cmd_dpipe_table_dump(dl);
4106 }
4107 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4108 return -ENOENT;
4109 }
4110
4111 static void cmd_dpipe_help(void)
4112 {
4113 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
4114 "where OBJECT-LIST := { header | table }\n");
4115 }
4116
4117 static int cmd_dpipe(struct dl *dl)
4118 {
4119 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4120 cmd_dpipe_help();
4121 return 0;
4122 } else if (dl_argv_match(dl, "header")) {
4123 dl_arg_inc(dl);
4124 return cmd_dpipe_header(dl);
4125 } else if (dl_argv_match(dl, "table")) {
4126 dl_arg_inc(dl);
4127 return cmd_dpipe_table(dl);
4128 }
4129 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4130 return -ENOENT;
4131 }
4132
4133 static int
4134 resource_parse(struct resource_ctx *ctx, struct resource *resource,
4135 struct nlattr **nla_resource)
4136 {
4137 if (!nla_resource[DEVLINK_ATTR_RESOURCE_NAME] ||
4138 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE] ||
4139 !nla_resource[DEVLINK_ATTR_RESOURCE_ID] ||
4140 !nla_resource[DEVLINK_ATTR_RESOURCE_UNIT] ||
4141 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN] ||
4142 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX] ||
4143 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]) {
4144 return -EINVAL;
4145 }
4146
4147 resource->name = strdup(mnl_attr_get_str(nla_resource[DEVLINK_ATTR_RESOURCE_NAME]));
4148 resource->size = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE]);
4149 resource->id = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_ID]);
4150 resource->unit = mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_UNIT]);
4151 resource->size_min = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN]);
4152 resource->size_max = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX]);
4153 resource->size_gran = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]);
4154
4155 if (nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW])
4156 resource->size_new = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW]);
4157 else
4158 resource->size_new = resource->size;
4159
4160 if (nla_resource[DEVLINK_ATTR_RESOURCE_OCC]) {
4161 resource->size_occ = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_OCC]);
4162 resource->occ_valid = true;
4163 }
4164
4165 if (resource->size_new != resource->size)
4166 ctx->pending_change = true;
4167
4168 return 0;
4169 }
4170
4171 static int
4172 resource_get(struct resource_ctx *ctx, struct resource *resource,
4173 struct resource *parent_resource, struct nlattr *nl)
4174 {
4175 struct nlattr *nla_resource[DEVLINK_ATTR_MAX + 1] = {};
4176 struct nlattr *nla_child_resource;
4177 struct nlattr *nla_resources;
4178 bool top = false;
4179 int err;
4180
4181 if (!resource) {
4182 nla_resources = nl;
4183 top = true;
4184 goto out;
4185 }
4186
4187 err = mnl_attr_parse_nested(nl, attr_cb, nla_resource);
4188 if (err != MNL_CB_OK)
4189 return -EINVAL;
4190
4191 err = resource_parse(ctx, resource, nla_resource);
4192 if (err)
4193 return err;
4194
4195 resource->parent = parent_resource;
4196 if (!nla_resource[DEVLINK_ATTR_RESOURCE_LIST])
4197 return 0;
4198
4199 resource->size_valid = !!mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_VALID]);
4200 nla_resources = nla_resource[DEVLINK_ATTR_RESOURCE_LIST];
4201 out:
4202 mnl_attr_for_each_nested(nla_child_resource, nla_resources) {
4203 struct resource *child_resource;
4204 struct list_head *list;
4205
4206 child_resource = resource_alloc();
4207 if (!child_resource)
4208 return -ENOMEM;
4209
4210 if (top)
4211 list = &ctx->resources->resource_list;
4212 else
4213 list = &resource->resource_list;
4214
4215 list_add_tail(&child_resource->list, list);
4216 err = resource_get(ctx, child_resource, resource,
4217 nla_child_resource);
4218 if (err)
4219 return err;
4220 }
4221
4222 return 0;
4223 }
4224
4225 static const char *resource_unit_str_get(enum devlink_resource_unit unit)
4226 {
4227 switch (unit) {
4228 case DEVLINK_RESOURCE_UNIT_ENTRY: return "entry";
4229 default: return "<unknown unit>";
4230 }
4231 }
4232
4233 static void resource_show(struct resource *resource,
4234 struct resource_ctx *ctx)
4235 {
4236 struct resource *child_resource;
4237 struct dpipe_table *table;
4238 struct dl *dl = ctx->dl;
4239 bool array = false;
4240
4241 pr_out_str(dl, "name", resource->name);
4242 if (dl->verbose)
4243 resource_path_print(dl, ctx->resources, resource->id);
4244 pr_out_u64(dl, "size", resource->size);
4245 if (resource->size != resource->size_new)
4246 pr_out_u64(dl, "size_new", resource->size_new);
4247 if (resource->occ_valid)
4248 pr_out_uint(dl, "occ", resource->size_occ);
4249 pr_out_str(dl, "unit", resource_unit_str_get(resource->unit));
4250
4251 if (resource->size_min != resource->size_max) {
4252 pr_out_uint(dl, "size_min", resource->size_min);
4253 pr_out_u64(dl, "size_max", resource->size_max);
4254 pr_out_uint(dl, "size_gran", resource->size_gran);
4255 }
4256
4257 list_for_each_entry(table, &ctx->tables->table_list, list)
4258 if (table->resource_id == resource->id &&
4259 table->resource_valid)
4260 array = true;
4261
4262 if (array)
4263 pr_out_array_start(dl, "dpipe_tables");
4264 else
4265 pr_out_str(dl, "dpipe_tables", "none");
4266
4267 list_for_each_entry(table, &ctx->tables->table_list, list) {
4268 if (table->resource_id != resource->id ||
4269 !table->resource_valid)
4270 continue;
4271 pr_out_entry_start(dl);
4272 pr_out_str(dl, "table_name", table->name);
4273 pr_out_entry_end(dl);
4274 }
4275 if (array)
4276 pr_out_array_end(dl);
4277
4278 if (list_empty(&resource->resource_list))
4279 return;
4280
4281 if (ctx->pending_change)
4282 pr_out_str(dl, "size_valid", resource->size_valid ?
4283 "true" : "false");
4284 pr_out_array_start(dl, "resources");
4285 list_for_each_entry(child_resource, &resource->resource_list, list) {
4286 pr_out_entry_start(dl);
4287 resource_show(child_resource, ctx);
4288 pr_out_entry_end(dl);
4289 }
4290 pr_out_array_end(dl);
4291 }
4292
4293 static void
4294 resources_show(struct resource_ctx *ctx, struct nlattr **tb)
4295 {
4296 struct resources *resources = ctx->resources;
4297 struct resource *resource;
4298
4299 list_for_each_entry(resource, &resources->resource_list, list) {
4300 pr_out_handle_start_arr(ctx->dl, tb);
4301 resource_show(resource, ctx);
4302 pr_out_handle_end(ctx->dl);
4303 }
4304 }
4305
4306 static int resources_get(struct resource_ctx *ctx, struct nlattr **tb)
4307 {
4308 return resource_get(ctx, NULL, NULL, tb[DEVLINK_ATTR_RESOURCE_LIST]);
4309 }
4310
4311 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data)
4312 {
4313 struct resource_ctx *ctx = data;
4314 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4315 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4316 int err;
4317
4318 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4319 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4320 !tb[DEVLINK_ATTR_RESOURCE_LIST])
4321 return MNL_CB_ERROR;
4322
4323 err = resources_get(ctx, tb);
4324 if (err) {
4325 ctx->err = err;
4326 return MNL_CB_ERROR;
4327 }
4328
4329 if (ctx->print_resources)
4330 resources_show(ctx, tb);
4331
4332 return MNL_CB_OK;
4333 }
4334
4335 static int cmd_resource_show(struct dl *dl)
4336 {
4337 struct nlmsghdr *nlh;
4338 struct dpipe_ctx dpipe_ctx = {};
4339 struct resource_ctx resource_ctx = {};
4340 int err;
4341
4342 err = dl_argv_parse(dl, DL_OPT_HANDLE, 0);
4343 if (err)
4344 return err;
4345
4346 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET,
4347 NLM_F_REQUEST);
4348 dl_opts_put(nlh, dl);
4349
4350 err = dpipe_ctx_init(&dpipe_ctx, dl);
4351 if (err)
4352 return err;
4353
4354 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb,
4355 &dpipe_ctx);
4356 if (err) {
4357 pr_err("error get tables %s\n", strerror(dpipe_ctx.err));
4358 goto out;
4359 }
4360
4361 err = resource_ctx_init(&resource_ctx, dl);
4362 if (err)
4363 goto out;
4364
4365 resource_ctx.print_resources = true;
4366 resource_ctx.tables = dpipe_ctx.tables;
4367 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
4368 NLM_F_REQUEST | NLM_F_ACK);
4369 dl_opts_put(nlh, dl);
4370 pr_out_section_start(dl, "resources");
4371 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
4372 &resource_ctx);
4373 pr_out_section_end(dl);
4374 resource_ctx_fini(&resource_ctx);
4375 out:
4376 dpipe_ctx_fini(&dpipe_ctx);
4377 return err;
4378 }
4379
4380 static void cmd_resource_help(void)
4381 {
4382 pr_err("Usage: devlink resource show DEV\n"
4383 " devlink resource set DEV path PATH size SIZE\n");
4384 }
4385
4386 static struct resource *
4387 resource_find_by_name(struct list_head *list, char *name)
4388 {
4389 struct resource *resource;
4390
4391 list_for_each_entry(resource, list, list) {
4392 if (!strcmp(resource->name, name))
4393 return resource;
4394 }
4395 return NULL;
4396 }
4397
4398 static int
4399 resource_path_parse(struct resource_ctx *ctx, const char *resource_path,
4400 uint32_t *p_resource_id, bool *p_resource_valid)
4401 {
4402 struct resource *resource;
4403 uint32_t resource_id = 0;
4404 char *resource_path_dup;
4405 struct list_head *list;
4406 const char del[] = "/";
4407 char *resource_name;
4408
4409 resource_path_dup = strdup(resource_path);
4410 list = &ctx->resources->resource_list;
4411 resource_name = strtok(resource_path_dup, del);
4412 while (resource_name != NULL) {
4413 resource = resource_find_by_name(list, resource_name);
4414 if (!resource)
4415 goto err_resource_lookup;
4416
4417 list = &resource->resource_list;
4418 resource_name = strtok(NULL, del);
4419 resource_id = resource->id;
4420 }
4421 free(resource_path_dup);
4422 *p_resource_valid = true;
4423 *p_resource_id = resource_id;
4424 return 0;
4425
4426 err_resource_lookup:
4427 free(resource_path_dup);
4428 return -EINVAL;
4429 }
4430
4431 static int cmd_resource_set(struct dl *dl)
4432 {
4433 struct nlmsghdr *nlh;
4434 struct resource_ctx ctx = {};
4435 int err;
4436
4437 err = resource_ctx_init(&ctx, dl);
4438 if (err)
4439 return err;
4440
4441 ctx.print_resources = false;
4442 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_RESOURCE_PATH |
4443 DL_OPT_RESOURCE_SIZE, 0);
4444 if (err)
4445 goto out;
4446
4447 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
4448 NLM_F_REQUEST);
4449 dl_opts_put(nlh, dl);
4450 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, &ctx);
4451 if (err) {
4452 pr_err("error getting resources %s\n", strerror(ctx.err));
4453 goto out;
4454 }
4455
4456 err = resource_path_parse(&ctx, dl->opts.resource_path,
4457 &dl->opts.resource_id,
4458 &dl->opts.resource_id_valid);
4459 if (err) {
4460 pr_err("error parsing resource path %s\n", strerror(err));
4461 goto out;
4462 }
4463
4464 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_SET,
4465 NLM_F_REQUEST | NLM_F_ACK);
4466
4467 dl_opts_put(nlh, dl);
4468 err = _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4469 out:
4470 resource_ctx_fini(&ctx);
4471 return err;
4472 }
4473
4474 static int cmd_resource(struct dl *dl)
4475 {
4476 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4477 cmd_resource_help();
4478 return 0;
4479 } else if (dl_argv_match(dl, "show")) {
4480 dl_arg_inc(dl);
4481 return cmd_resource_show(dl);
4482 } else if (dl_argv_match(dl, "set")) {
4483 dl_arg_inc(dl);
4484 return cmd_resource_set(dl);
4485 }
4486 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4487 return -ENOENT;
4488 }
4489
4490 static void help(void)
4491 {
4492 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
4493 " devlink [ -f[orce] ] -b[atch] filename\n"
4494 "where OBJECT := { dev | port | sb | monitor | dpipe | resource }\n"
4495 " OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] | -v[verbose] }\n");
4496 }
4497
4498 static int dl_cmd(struct dl *dl, int argc, char **argv)
4499 {
4500 dl->argc = argc;
4501 dl->argv = argv;
4502
4503 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4504 help();
4505 return 0;
4506 } else if (dl_argv_match(dl, "dev")) {
4507 dl_arg_inc(dl);
4508 return cmd_dev(dl);
4509 } else if (dl_argv_match(dl, "port")) {
4510 dl_arg_inc(dl);
4511 return cmd_port(dl);
4512 } else if (dl_argv_match(dl, "sb")) {
4513 dl_arg_inc(dl);
4514 return cmd_sb(dl);
4515 } else if (dl_argv_match(dl, "monitor")) {
4516 dl_arg_inc(dl);
4517 return cmd_mon(dl);
4518 } else if (dl_argv_match(dl, "dpipe")) {
4519 dl_arg_inc(dl);
4520 return cmd_dpipe(dl);
4521 } else if (dl_argv_match(dl, "resource")) {
4522 dl_arg_inc(dl);
4523 return cmd_resource(dl);
4524 }
4525 pr_err("Object \"%s\" not found\n", dl_argv(dl));
4526 return -ENOENT;
4527 }
4528
4529 static int dl_init(struct dl *dl)
4530 {
4531 int err;
4532
4533 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
4534 if (!dl->nlg) {
4535 pr_err("Failed to connect to devlink Netlink\n");
4536 return -errno;
4537 }
4538
4539 err = ifname_map_init(dl);
4540 if (err) {
4541 pr_err("Failed to create index map\n");
4542 goto err_ifname_map_create;
4543 }
4544 if (dl->json_output) {
4545 dl->jw = jsonw_new(stdout);
4546 if (!dl->jw) {
4547 pr_err("Failed to create JSON writer\n");
4548 goto err_json_new;
4549 }
4550 jsonw_pretty(dl->jw, dl->pretty_output);
4551 }
4552 return 0;
4553
4554 err_json_new:
4555 ifname_map_fini(dl);
4556 err_ifname_map_create:
4557 mnlg_socket_close(dl->nlg);
4558 return err;
4559 }
4560
4561 static void dl_fini(struct dl *dl)
4562 {
4563 if (dl->json_output)
4564 jsonw_destroy(&dl->jw);
4565 ifname_map_fini(dl);
4566 mnlg_socket_close(dl->nlg);
4567 }
4568
4569 static struct dl *dl_alloc(void)
4570 {
4571 struct dl *dl;
4572
4573 dl = calloc(1, sizeof(*dl));
4574 if (!dl)
4575 return NULL;
4576 return dl;
4577 }
4578
4579 static void dl_free(struct dl *dl)
4580 {
4581 free(dl);
4582 }
4583
4584 static int dl_batch(struct dl *dl, const char *name, bool force)
4585 {
4586 char *line = NULL;
4587 size_t len = 0;
4588 int ret = EXIT_SUCCESS;
4589
4590 if (name && strcmp(name, "-") != 0) {
4591 if (freopen(name, "r", stdin) == NULL) {
4592 fprintf(stderr,
4593 "Cannot open file \"%s\" for reading: %s\n",
4594 name, strerror(errno));
4595 return EXIT_FAILURE;
4596 }
4597 }
4598
4599 cmdlineno = 0;
4600 while (getcmdline(&line, &len, stdin) != -1) {
4601 char *largv[100];
4602 int largc;
4603
4604 largc = makeargs(line, largv, 100);
4605 if (!largc)
4606 continue; /* blank line */
4607
4608 if (dl_cmd(dl, largc, largv)) {
4609 fprintf(stderr, "Command failed %s:%d\n",
4610 name, cmdlineno);
4611 ret = EXIT_FAILURE;
4612 if (!force)
4613 break;
4614 }
4615 }
4616
4617 if (line)
4618 free(line);
4619
4620 return ret;
4621 }
4622
4623 int main(int argc, char **argv)
4624 {
4625 static const struct option long_options[] = {
4626 { "Version", no_argument, NULL, 'V' },
4627 { "force", no_argument, NULL, 'f' },
4628 { "batch", required_argument, NULL, 'b' },
4629 { "no-nice-names", no_argument, NULL, 'n' },
4630 { "json", no_argument, NULL, 'j' },
4631 { "pretty", no_argument, NULL, 'p' },
4632 { "verbose", no_argument, NULL, 'v' },
4633 { NULL, 0, NULL, 0 }
4634 };
4635 const char *batch_file = NULL;
4636 bool force = false;
4637 struct dl *dl;
4638 int opt;
4639 int err;
4640 int ret;
4641
4642 dl = dl_alloc();
4643 if (!dl) {
4644 pr_err("Failed to allocate memory for devlink\n");
4645 return EXIT_FAILURE;
4646 }
4647
4648 while ((opt = getopt_long(argc, argv, "Vfb:njpv",
4649 long_options, NULL)) >= 0) {
4650
4651 switch (opt) {
4652 case 'V':
4653 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
4654 ret = EXIT_SUCCESS;
4655 goto dl_free;
4656 case 'f':
4657 force = true;
4658 break;
4659 case 'b':
4660 batch_file = optarg;
4661 break;
4662 case 'n':
4663 dl->no_nice_names = true;
4664 break;
4665 case 'j':
4666 dl->json_output = true;
4667 break;
4668 case 'p':
4669 dl->pretty_output = true;
4670 break;
4671 case 'v':
4672 dl->verbose = true;
4673 break;
4674 default:
4675 pr_err("Unknown option.\n");
4676 help();
4677 ret = EXIT_FAILURE;
4678 goto dl_free;
4679 }
4680 }
4681
4682 argc -= optind;
4683 argv += optind;
4684
4685 err = dl_init(dl);
4686 if (err) {
4687 ret = EXIT_FAILURE;
4688 goto dl_free;
4689 }
4690
4691 if (batch_file)
4692 err = dl_batch(dl, batch_file, force);
4693 else
4694 err = dl_cmd(dl, argc, argv);
4695
4696 if (err) {
4697 ret = EXIT_FAILURE;
4698 goto dl_fini;
4699 }
4700
4701 ret = EXIT_SUCCESS;
4702
4703 dl_fini:
4704 dl_fini(dl);
4705 dl_free:
4706 dl_free(dl);
4707
4708 return ret;
4709 }