]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
devlink: implement shared buffer occupancy control
[mirror_iproute2.git] / devlink / devlink.c
1 /*
2 * devlink.c Devlink tool
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Jiri Pirko <jiri@mellanox.com>
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdbool.h>
16 #include <unistd.h>
17 #include <getopt.h>
18 #include <limits.h>
19 #include <errno.h>
20 #include <linux/genetlink.h>
21 #include <linux/devlink.h>
22 #include <libmnl/libmnl.h>
23
24 #include "SNAPSHOT.h"
25 #include "list.h"
26 #include "mnlg.h"
27
28 #define pr_err(args...) fprintf(stderr, ##args)
29 #define pr_out(args...) fprintf(stdout, ##args)
30 #define pr_out_sp(num, args...) \
31 do { \
32 int ret = fprintf(stdout, ##args); \
33 if (ret < num) \
34 fprintf(stdout, "%*s", num - ret, ""); \
35 } while (0)
36
37 static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
38 mnl_cb_t data_cb, void *data)
39 {
40 int err;
41
42 err = mnlg_socket_recv_run(nlg, data_cb, data);
43 if (err < 0) {
44 pr_err("devlink answers: %s\n", strerror(errno));
45 return -errno;
46 }
47 return 0;
48 }
49
50 static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
51 const struct nlmsghdr *nlh,
52 mnl_cb_t data_cb, void *data)
53 {
54 int err;
55
56 err = mnlg_socket_send(nlg, nlh);
57 if (err < 0) {
58 pr_err("Failed to call mnlg_socket_send\n");
59 return -errno;
60 }
61 return _mnlg_socket_recv_run(nlg, data_cb, data);
62 }
63
64 static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
65 const char *group_name)
66 {
67 int err;
68
69 err = mnlg_socket_group_add(nlg, group_name);
70 if (err < 0) {
71 pr_err("Failed to call mnlg_socket_group_add\n");
72 return -errno;
73 }
74 return 0;
75 }
76
77 struct ifname_map {
78 struct list_head list;
79 char *bus_name;
80 char *dev_name;
81 uint32_t port_index;
82 char *ifname;
83 };
84
85 static struct ifname_map *ifname_map_alloc(const char *bus_name,
86 const char *dev_name,
87 uint32_t port_index,
88 const char *ifname)
89 {
90 struct ifname_map *ifname_map;
91
92 ifname_map = calloc(1, sizeof(*ifname_map));
93 if (!ifname_map)
94 return NULL;
95 ifname_map->bus_name = strdup(bus_name);
96 ifname_map->dev_name = strdup(dev_name);
97 ifname_map->port_index = port_index;
98 ifname_map->ifname = strdup(ifname);
99 if (!ifname_map->bus_name || !ifname_map->dev_name ||
100 !ifname_map->ifname) {
101 free(ifname_map->ifname);
102 free(ifname_map->dev_name);
103 free(ifname_map->bus_name);
104 free(ifname_map);
105 return NULL;
106 }
107 return ifname_map;
108 }
109
110 static void ifname_map_free(struct ifname_map *ifname_map)
111 {
112 free(ifname_map->ifname);
113 free(ifname_map->dev_name);
114 free(ifname_map->bus_name);
115 free(ifname_map);
116 }
117
118 #define BIT(nr) (1UL << (nr))
119 #define DL_OPT_HANDLE BIT(0)
120 #define DL_OPT_HANDLEP BIT(1)
121 #define DL_OPT_PORT_TYPE BIT(2)
122 #define DL_OPT_PORT_COUNT BIT(3)
123 #define DL_OPT_SB BIT(4)
124 #define DL_OPT_SB_POOL BIT(5)
125 #define DL_OPT_SB_SIZE BIT(6)
126 #define DL_OPT_SB_TYPE BIT(7)
127 #define DL_OPT_SB_THTYPE BIT(8)
128 #define DL_OPT_SB_TH BIT(9)
129 #define DL_OPT_SB_TC BIT(10)
130
131 struct dl_opts {
132 uint32_t present; /* flags of present items */
133 char *bus_name;
134 char *dev_name;
135 uint32_t port_index;
136 enum devlink_port_type port_type;
137 uint32_t port_count;
138 uint32_t sb_index;
139 uint16_t sb_pool_index;
140 uint32_t sb_pool_size;
141 enum devlink_sb_pool_type sb_pool_type;
142 enum devlink_sb_threshold_type sb_pool_thtype;
143 uint32_t sb_threshold;
144 uint16_t sb_tc_index;
145 };
146
147 struct dl {
148 struct mnlg_socket *nlg;
149 struct list_head ifname_map_list;
150 int argc;
151 char **argv;
152 bool no_nice_names;
153 struct dl_opts opts;
154 };
155
156 static int dl_argc(struct dl *dl)
157 {
158 return dl->argc;
159 }
160
161 static char *dl_argv(struct dl *dl)
162 {
163 if (dl_argc(dl) == 0)
164 return NULL;
165 return *dl->argv;
166 }
167
168 static void dl_arg_inc(struct dl *dl)
169 {
170 if (dl_argc(dl) == 0)
171 return;
172 dl->argc--;
173 dl->argv++;
174 }
175
176 static char *dl_argv_next(struct dl *dl)
177 {
178 char *ret;
179
180 if (dl_argc(dl) == 0)
181 return NULL;
182
183 ret = *dl->argv;
184 dl_arg_inc(dl);
185 return ret;
186 }
187
188 static char *dl_argv_index(struct dl *dl, unsigned int index)
189 {
190 if (index >= dl_argc(dl))
191 return NULL;
192 return dl->argv[index];
193 }
194
195 static int strcmpx(const char *str1, const char *str2)
196 {
197 if (strlen(str1) > strlen(str2))
198 return -1;
199 return strncmp(str1, str2, strlen(str1));
200 }
201
202 static bool dl_argv_match(struct dl *dl, const char *pattern)
203 {
204 if (dl_argc(dl) == 0)
205 return false;
206 return strcmpx(dl_argv(dl), pattern) == 0;
207 }
208
209 static bool dl_no_arg(struct dl *dl)
210 {
211 return dl_argc(dl) == 0;
212 }
213
214 static int attr_cb(const struct nlattr *attr, void *data)
215 {
216 const struct nlattr **tb = data;
217 int type;
218
219 type = mnl_attr_get_type(attr);
220
221 if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
222 return MNL_CB_ERROR;
223
224 if (type == DEVLINK_ATTR_BUS_NAME &&
225 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
226 return MNL_CB_ERROR;
227 if (type == DEVLINK_ATTR_DEV_NAME &&
228 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
229 return MNL_CB_ERROR;
230 if (type == DEVLINK_ATTR_PORT_INDEX &&
231 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
232 return MNL_CB_ERROR;
233 if (type == DEVLINK_ATTR_PORT_TYPE &&
234 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
235 return MNL_CB_ERROR;
236 if (type == DEVLINK_ATTR_PORT_DESIRED_TYPE &&
237 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
238 return MNL_CB_ERROR;
239 if (type == DEVLINK_ATTR_PORT_NETDEV_IFINDEX &&
240 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
241 return MNL_CB_ERROR;
242 if (type == DEVLINK_ATTR_PORT_NETDEV_NAME &&
243 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
244 return MNL_CB_ERROR;
245 if (type == DEVLINK_ATTR_PORT_IBDEV_NAME &&
246 mnl_attr_validate(attr, MNL_TYPE_NUL_STRING) < 0)
247 return MNL_CB_ERROR;
248 if (type == DEVLINK_ATTR_SB_INDEX &&
249 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
250 return MNL_CB_ERROR;
251 if (type == DEVLINK_ATTR_SB_SIZE &&
252 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
253 return MNL_CB_ERROR;
254 if (type == DEVLINK_ATTR_SB_INGRESS_POOL_COUNT &&
255 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
256 return MNL_CB_ERROR;
257 if (type == DEVLINK_ATTR_SB_EGRESS_POOL_COUNT &&
258 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
259 return MNL_CB_ERROR;
260 if (type == DEVLINK_ATTR_SB_INGRESS_TC_COUNT &&
261 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
262 return MNL_CB_ERROR;
263 if (type == DEVLINK_ATTR_SB_EGRESS_TC_COUNT &&
264 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
265 return MNL_CB_ERROR;
266 if (type == DEVLINK_ATTR_SB_POOL_INDEX &&
267 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
268 return MNL_CB_ERROR;
269 if (type == DEVLINK_ATTR_SB_POOL_TYPE &&
270 mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
271 return MNL_CB_ERROR;
272 if (type == DEVLINK_ATTR_SB_POOL_SIZE &&
273 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
274 return MNL_CB_ERROR;
275 if (type == DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE &&
276 mnl_attr_validate(attr, MNL_TYPE_U8) < 0)
277 return MNL_CB_ERROR;
278 if (type == DEVLINK_ATTR_SB_THRESHOLD &&
279 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
280 return MNL_CB_ERROR;
281 if (type == DEVLINK_ATTR_SB_TC_INDEX &&
282 mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
283 return MNL_CB_ERROR;
284 if (type == DEVLINK_ATTR_SB_OCC_CUR &&
285 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
286 return MNL_CB_ERROR;
287 if (type == DEVLINK_ATTR_SB_OCC_MAX &&
288 mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
289 return MNL_CB_ERROR;
290 tb[type] = attr;
291 return MNL_CB_OK;
292 }
293
294 static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
295 {
296 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
297 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
298 struct dl *dl = data;
299 struct ifname_map *ifname_map;
300 const char *bus_name;
301 const char *dev_name;
302 uint32_t port_ifindex;
303 const char *port_ifname;
304
305 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
306 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
307 !tb[DEVLINK_ATTR_PORT_INDEX])
308 return MNL_CB_ERROR;
309
310 if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
311 return MNL_CB_OK;
312
313 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
314 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
315 port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
316 port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
317 ifname_map = ifname_map_alloc(bus_name, dev_name,
318 port_ifindex, port_ifname);
319 if (!ifname_map)
320 return MNL_CB_ERROR;
321 list_add(&ifname_map->list, &dl->ifname_map_list);
322
323 return MNL_CB_OK;
324 }
325
326 static void ifname_map_fini(struct dl *dl)
327 {
328 struct ifname_map *ifname_map, *tmp;
329
330 list_for_each_entry_safe(ifname_map, tmp,
331 &dl->ifname_map_list, list) {
332 list_del(&ifname_map->list);
333 ifname_map_free(ifname_map);
334 }
335 }
336
337 static int ifname_map_init(struct dl *dl)
338 {
339 struct nlmsghdr *nlh;
340 int err;
341
342 INIT_LIST_HEAD(&dl->ifname_map_list);
343
344 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
345 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
346
347 err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl);
348 if (err) {
349 ifname_map_fini(dl);
350 return err;
351 }
352 return 0;
353 }
354
355 static int ifname_map_lookup(struct dl *dl, const char *ifname,
356 char **p_bus_name, char **p_dev_name,
357 uint32_t *p_port_index)
358 {
359 struct ifname_map *ifname_map;
360
361 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
362 if (strcmp(ifname, ifname_map->ifname) == 0) {
363 *p_bus_name = ifname_map->bus_name;
364 *p_dev_name = ifname_map->dev_name;
365 *p_port_index = ifname_map->port_index;
366 return 0;
367 }
368 }
369 return -ENOENT;
370 }
371
372 static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name,
373 const char *dev_name, uint32_t port_index,
374 char **p_ifname)
375 {
376 struct ifname_map *ifname_map;
377
378 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
379 if (strcmp(bus_name, ifname_map->bus_name) == 0 &&
380 strcmp(dev_name, ifname_map->dev_name) == 0 &&
381 port_index == ifname_map->port_index) {
382 *p_ifname = ifname_map->ifname;
383 return 0;
384 }
385 }
386 return -ENOENT;
387 }
388
389 static unsigned int strslashcount(char *str)
390 {
391 unsigned int count = 0;
392 char *pos = str;
393
394 while ((pos = strchr(pos, '/'))) {
395 count++;
396 pos++;
397 }
398 return count;
399 }
400
401 static int strslashrsplit(char *str, char **before, char **after)
402 {
403 char *slash;
404
405 slash = strrchr(str, '/');
406 if (!slash)
407 return -EINVAL;
408 *slash = '\0';
409 *before = str;
410 *after = slash + 1;
411 return 0;
412 }
413
414 static int strtouint32_t(const char *str, uint32_t *p_val)
415 {
416 char *endptr;
417 unsigned long int val;
418
419 val = strtoul(str, &endptr, 10);
420 if (endptr == str || *endptr != '\0')
421 return -EINVAL;
422 if (val > UINT_MAX)
423 return -ERANGE;
424 *p_val = val;
425 return 0;
426 }
427
428 static int strtouint16_t(const char *str, uint16_t *p_val)
429 {
430 char *endptr;
431 unsigned long int val;
432
433 val = strtoul(str, &endptr, 10);
434 if (endptr == str || *endptr != '\0')
435 return -EINVAL;
436 if (val > USHRT_MAX)
437 return -ERANGE;
438 *p_val = val;
439 return 0;
440 }
441
442 static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
443 {
444 strslashrsplit(str, p_bus_name, p_dev_name);
445 return 0;
446 }
447
448 static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
449 {
450 char *str = dl_argv_next(dl);
451
452 if (!str) {
453 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
454 return -EINVAL;
455 }
456 if (strslashcount(str) != 1) {
457 pr_err("Wrong devlink identification string format.\n");
458 pr_err("Expected \"bus_name/dev_name\".\n");
459 return -EINVAL;
460 }
461 return __dl_argv_handle(str, p_bus_name, p_dev_name);
462 }
463
464 static int __dl_argv_handle_port(char *str,
465 char **p_bus_name, char **p_dev_name,
466 uint32_t *p_port_index)
467 {
468 char *handlestr = handlestr;
469 char *portstr = portstr;
470 int err;
471
472 strslashrsplit(str, &handlestr, &portstr);
473 err = strtouint32_t(portstr, p_port_index);
474 if (err) {
475 pr_err("Port index \"%s\" is not a number or not within range\n",
476 portstr);
477 return err;
478 }
479 strslashrsplit(handlestr, p_bus_name, p_dev_name);
480 return 0;
481 }
482
483 static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
484 char **p_bus_name, char **p_dev_name,
485 uint32_t *p_port_index)
486 {
487 int err;
488
489 err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
490 p_port_index);
491 if (err) {
492 pr_err("Netdevice \"%s\" not found\n", str);
493 return err;
494 }
495 return 0;
496 }
497
498 static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
499 char **p_dev_name, uint32_t *p_port_index)
500 {
501 char *str = dl_argv_next(dl);
502 unsigned int slash_count;
503
504 if (!str) {
505 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
506 return -EINVAL;
507 }
508 slash_count = strslashcount(str);
509 if (slash_count != 2 && slash_count != 0) {
510 pr_err("Wrong port identification string format.\n");
511 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
512 return -EINVAL;
513 }
514 if (slash_count == 2) {
515 return __dl_argv_handle_port(str, p_bus_name,
516 p_dev_name, p_port_index);
517 } else if (slash_count == 0) {
518 return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
519 p_dev_name, p_port_index);
520 }
521 return 0;
522 }
523
524 static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
525 char **p_dev_name, uint32_t *p_port_index,
526 uint32_t *p_handle_bit)
527 {
528 char *str = dl_argv_next(dl);
529 unsigned int slash_count;
530 int err;
531
532 if (!str) {
533 pr_err("One of following identifications expected:\n"
534 "Devlink identification (\"bus_name/dev_name\")\n"
535 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
536 return -EINVAL;
537 }
538 slash_count = strslashcount(str);
539 if (slash_count == 1) {
540 err = __dl_argv_handle(str, p_bus_name, p_dev_name);
541 if (err)
542 return err;
543 *p_handle_bit = DL_OPT_HANDLE;
544 } else if (slash_count == 2) {
545 err = __dl_argv_handle_port(str, p_bus_name,
546 p_dev_name, p_port_index);
547 if (err)
548 return err;
549 *p_handle_bit = DL_OPT_HANDLEP;
550 } else if (slash_count == 0) {
551 err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
552 p_dev_name, p_port_index);
553 if (err)
554 return err;
555 *p_handle_bit = DL_OPT_HANDLEP;
556 } else {
557 pr_err("Wrong port identification string format.\n");
558 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
559 return -EINVAL;
560 }
561 return 0;
562 }
563
564 static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
565 {
566 char *str = dl_argv_next(dl);
567 int err;
568
569 if (!str) {
570 pr_err("Unsigned number argument expected\n");
571 return -EINVAL;
572 }
573
574 err = strtouint32_t(str, p_val);
575 if (err) {
576 pr_err("\"%s\" is not a number or not within range\n", str);
577 return err;
578 }
579 return 0;
580 }
581
582 static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val)
583 {
584 char *str = dl_argv_next(dl);
585 int err;
586
587 if (!str) {
588 pr_err("Unsigned number argument expected\n");
589 return -EINVAL;
590 }
591
592 err = strtouint16_t(str, p_val);
593 if (err) {
594 pr_err("\"%s\" is not a number or not within range\n", str);
595 return err;
596 }
597 return 0;
598 }
599
600 static int dl_argv_str(struct dl *dl, const char **p_str)
601 {
602 const char *str = dl_argv_next(dl);
603
604 if (!str) {
605 pr_err("String parameter expected\n");
606 return -EINVAL;
607 }
608 *p_str = str;
609 return 0;
610 }
611
612 static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
613 {
614 if (strcmp(typestr, "auto") == 0) {
615 *p_type = DEVLINK_PORT_TYPE_AUTO;
616 } else if (strcmp(typestr, "eth") == 0) {
617 *p_type = DEVLINK_PORT_TYPE_ETH;
618 } else if (strcmp(typestr, "ib") == 0) {
619 *p_type = DEVLINK_PORT_TYPE_IB;
620 } else {
621 pr_err("Unknown port type \"%s\"\n", typestr);
622 return -EINVAL;
623 }
624 return 0;
625 }
626
627 static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type)
628 {
629 if (strcmp(typestr, "ingress") == 0) {
630 *p_type = DEVLINK_SB_POOL_TYPE_INGRESS;
631 } else if (strcmp(typestr, "egress") == 0) {
632 *p_type = DEVLINK_SB_POOL_TYPE_EGRESS;
633 } else {
634 pr_err("Unknown pool type \"%s\"\n", typestr);
635 return -EINVAL;
636 }
637 return 0;
638 }
639
640 static int threshold_type_get(const char *typestr,
641 enum devlink_sb_threshold_type *p_type)
642 {
643 if (strcmp(typestr, "static") == 0) {
644 *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC;
645 } else if (strcmp(typestr, "dynamic") == 0) {
646 *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC;
647 } else {
648 pr_err("Unknown threshold type \"%s\"\n", typestr);
649 return -EINVAL;
650 }
651 return 0;
652 }
653
654 static int dl_argv_parse(struct dl *dl, uint32_t o_required,
655 uint32_t o_optional)
656 {
657 struct dl_opts *opts = &dl->opts;
658 uint32_t o_all = o_required | o_optional;
659 uint32_t o_found = 0;
660 int err;
661
662 if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
663 uint32_t handle_bit = handle_bit;
664
665 err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
666 &opts->port_index, &handle_bit);
667 if (err)
668 return err;
669 o_found |= handle_bit;
670 } else if (o_required & DL_OPT_HANDLE) {
671 err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
672 if (err)
673 return err;
674 o_found |= DL_OPT_HANDLE;
675 } else if (o_required & DL_OPT_HANDLEP) {
676 err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
677 &opts->port_index);
678 if (err)
679 return err;
680 o_found |= DL_OPT_HANDLEP;
681 }
682
683 while (dl_argc(dl)) {
684 if (dl_argv_match(dl, "type") &&
685 (o_all & DL_OPT_PORT_TYPE)) {
686 const char *typestr;
687
688 dl_arg_inc(dl);
689 err = dl_argv_str(dl, &typestr);
690 if (err)
691 return err;
692 err = port_type_get(typestr, &opts->port_type);
693 if (err)
694 return err;
695 o_found |= DL_OPT_PORT_TYPE;
696 } else if (dl_argv_match(dl, "count") &&
697 (o_all & DL_OPT_PORT_COUNT)) {
698 dl_arg_inc(dl);
699 err = dl_argv_uint32_t(dl, &opts->port_count);
700 if (err)
701 return err;
702 o_found |= DL_OPT_PORT_COUNT;
703 } else if (dl_argv_match(dl, "sb") &&
704 (o_all & DL_OPT_SB)) {
705 dl_arg_inc(dl);
706 err = dl_argv_uint32_t(dl, &opts->sb_index);
707 if (err)
708 return err;
709 o_found |= DL_OPT_SB;
710 } else if (dl_argv_match(dl, "pool") &&
711 (o_all & DL_OPT_SB_POOL)) {
712 dl_arg_inc(dl);
713 err = dl_argv_uint16_t(dl, &opts->sb_pool_index);
714 if (err)
715 return err;
716 o_found |= DL_OPT_SB_POOL;
717 } else if (dl_argv_match(dl, "size") &&
718 (o_all & DL_OPT_SB_SIZE)) {
719 dl_arg_inc(dl);
720 err = dl_argv_uint32_t(dl, &opts->sb_pool_size);
721 if (err)
722 return err;
723 o_found |= DL_OPT_SB_SIZE;
724 } else if (dl_argv_match(dl, "type") &&
725 (o_all & DL_OPT_SB_TYPE)) {
726 const char *typestr;
727
728 dl_arg_inc(dl);
729 err = dl_argv_str(dl, &typestr);
730 if (err)
731 return err;
732 err = pool_type_get(typestr, &opts->sb_pool_type);
733 if (err)
734 return err;
735 o_found |= DL_OPT_SB_TYPE;
736 } else if (dl_argv_match(dl, "thtype") &&
737 (o_all & DL_OPT_SB_THTYPE)) {
738 const char *typestr;
739
740 dl_arg_inc(dl);
741 err = dl_argv_str(dl, &typestr);
742 if (err)
743 return err;
744 err = threshold_type_get(typestr,
745 &opts->sb_pool_thtype);
746 if (err)
747 return err;
748 o_found |= DL_OPT_SB_THTYPE;
749 } else if (dl_argv_match(dl, "th") &&
750 (o_all & DL_OPT_SB_TH)) {
751 dl_arg_inc(dl);
752 err = dl_argv_uint32_t(dl, &opts->sb_threshold);
753 if (err)
754 return err;
755 o_found |= DL_OPT_SB_TH;
756 } else if (dl_argv_match(dl, "tc") &&
757 (o_all & DL_OPT_SB_TC)) {
758 dl_arg_inc(dl);
759 err = dl_argv_uint16_t(dl, &opts->sb_tc_index);
760 if (err)
761 return err;
762 o_found |= DL_OPT_SB_TC;
763 } else {
764 pr_err("Unknown option \"%s\"\n", dl_argv(dl));
765 return -EINVAL;
766 }
767 }
768
769 opts->present = o_found;
770
771 if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) {
772 opts->sb_index = 0;
773 opts->present |= DL_OPT_SB;
774 }
775
776 if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) {
777 pr_err("Port type option expected.\n");
778 return -EINVAL;
779 }
780
781 if ((o_required & DL_OPT_PORT_COUNT) &&
782 !(o_found & DL_OPT_PORT_COUNT)) {
783 pr_err("Port split count option expected.\n");
784 return -EINVAL;
785 }
786
787 if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) {
788 pr_err("Pool index option expected.\n");
789 return -EINVAL;
790 }
791
792 if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) {
793 pr_err("Pool size option expected.\n");
794 return -EINVAL;
795 }
796
797 if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) {
798 pr_err("Pool type option expected.\n");
799 return -EINVAL;
800 }
801
802 if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) {
803 pr_err("Pool threshold type option expected.\n");
804 return -EINVAL;
805 }
806
807 if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) {
808 pr_err("Threshold option expected.\n");
809 return -EINVAL;
810 }
811
812 if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) {
813 pr_err("TC index option expected.\n");
814 return -EINVAL;
815 }
816 return 0;
817 }
818
819 static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
820 {
821 struct dl_opts *opts = &dl->opts;
822
823 if (opts->present & DL_OPT_HANDLE) {
824 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
825 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
826 } else if (opts->present & DL_OPT_HANDLEP) {
827 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
828 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
829 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
830 opts->port_index);
831 }
832 if (opts->present & DL_OPT_PORT_TYPE)
833 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
834 opts->port_type);
835 if (opts->present & DL_OPT_PORT_COUNT)
836 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
837 opts->port_count);
838 if (opts->present & DL_OPT_SB)
839 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX,
840 opts->sb_index);
841 if (opts->present & DL_OPT_SB_POOL)
842 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX,
843 opts->sb_pool_index);
844 if (opts->present & DL_OPT_SB_SIZE)
845 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE,
846 opts->sb_pool_size);
847 if (opts->present & DL_OPT_SB_TYPE)
848 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE,
849 opts->sb_pool_type);
850 if (opts->present & DL_OPT_SB_THTYPE)
851 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
852 opts->sb_pool_thtype);
853 if (opts->present & DL_OPT_SB_TH)
854 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD,
855 opts->sb_threshold);
856 if (opts->present & DL_OPT_SB_TC)
857 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX,
858 opts->sb_tc_index);
859 }
860
861 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
862 uint32_t o_required, uint32_t o_optional)
863 {
864 int err;
865
866 err = dl_argv_parse(dl, o_required, o_optional);
867 if (err)
868 return err;
869 dl_opts_put(nlh, dl);
870 return 0;
871 }
872
873 static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
874 {
875 struct dl_opts *opts = &dl->opts;
876 struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME];
877 struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME];
878 struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX];
879 struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX];
880
881 if (opts->present & DL_OPT_HANDLE &&
882 attr_bus_name && attr_dev_name) {
883 const char *bus_name = mnl_attr_get_str(attr_bus_name);
884 const char *dev_name = mnl_attr_get_str(attr_dev_name);
885
886 if (strcmp(bus_name, opts->bus_name) != 0 ||
887 strcmp(dev_name, opts->dev_name) != 0)
888 return false;
889 }
890 if (opts->present & DL_OPT_HANDLEP &&
891 attr_bus_name && attr_dev_name && attr_port_index) {
892 const char *bus_name = mnl_attr_get_str(attr_bus_name);
893 const char *dev_name = mnl_attr_get_str(attr_dev_name);
894 uint32_t port_index = mnl_attr_get_u32(attr_port_index);
895
896 if (strcmp(bus_name, opts->bus_name) != 0 ||
897 strcmp(dev_name, opts->dev_name) != 0 ||
898 port_index != opts->port_index)
899 return false;
900 }
901 if (opts->present & DL_OPT_SB && attr_sb_index) {
902 uint32_t sb_index = mnl_attr_get_u32(attr_sb_index);
903
904 if (sb_index != opts->sb_index)
905 return false;
906 }
907 return true;
908 }
909
910 static void cmd_dev_help(void)
911 {
912 pr_out("Usage: devlink dev show [ DEV ]\n");
913 }
914
915 static void __pr_out_handle(const char *bus_name, const char *dev_name)
916 {
917 pr_out("%s/%s", bus_name, dev_name);
918 }
919
920 static void pr_out_handle(struct nlattr **tb)
921 {
922 __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
923 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]));
924 }
925
926 static void __pr_out_port_handle(const char *bus_name, const char *dev_name,
927 uint32_t port_index)
928 {
929 __pr_out_handle(bus_name, dev_name);
930 pr_out("/%d", port_index);
931 }
932
933 static void pr_out_port_handle(struct nlattr **tb)
934 {
935 __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
936 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]),
937 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]));
938 }
939
940 static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name,
941 const char *dev_name, uint32_t port_index)
942 {
943 char *ifname;
944 int err;
945
946 if (dl->no_nice_names)
947 goto no_nice_names;
948
949 err = ifname_map_rev_lookup(dl, bus_name, dev_name,
950 port_index, &ifname);
951 if (err)
952 goto no_nice_names;
953 pr_out("%s", ifname);
954 return;
955
956 no_nice_names:
957 __pr_out_port_handle(bus_name, dev_name, port_index);
958 }
959
960 static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb)
961 {
962 const char *bus_name;
963 const char *dev_name;
964 uint32_t port_index;
965
966 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
967 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
968 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
969
970 __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index);
971 }
972
973 static void pr_out_dev(struct nlattr **tb)
974 {
975 pr_out_handle(tb);
976 pr_out("\n");
977 }
978
979 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
980 {
981 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
982 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
983
984 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
985 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
986 return MNL_CB_ERROR;
987 pr_out_dev(tb);
988 return MNL_CB_OK;
989 }
990
991 static int cmd_dev_show(struct dl *dl)
992 {
993 struct nlmsghdr *nlh;
994 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
995 int err;
996
997 if (dl_argc(dl) == 0)
998 flags |= NLM_F_DUMP;
999
1000 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
1001
1002 if (dl_argc(dl) > 0) {
1003 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
1004 if (err)
1005 return err;
1006 }
1007
1008 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL);
1009 }
1010
1011 static int cmd_dev(struct dl *dl)
1012 {
1013 if (dl_argv_match(dl, "help")) {
1014 cmd_dev_help();
1015 return 0;
1016 } else if (dl_argv_match(dl, "show") ||
1017 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1018 dl_arg_inc(dl);
1019 return cmd_dev_show(dl);
1020 }
1021 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1022 return -ENOENT;
1023 }
1024
1025 static void cmd_port_help(void)
1026 {
1027 pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
1028 pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
1029 pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n");
1030 pr_out(" devlink port unsplit DEV/PORT_INDEX\n");
1031 }
1032
1033 static const char *port_type_name(uint32_t type)
1034 {
1035 switch (type) {
1036 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
1037 case DEVLINK_PORT_TYPE_AUTO: return "auto";
1038 case DEVLINK_PORT_TYPE_ETH: return "eth";
1039 case DEVLINK_PORT_TYPE_IB: return "ib";
1040 default: return "<unknown type>";
1041 }
1042 }
1043
1044 static void pr_out_port(struct nlattr **tb)
1045 {
1046 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
1047 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
1048
1049 pr_out_port_handle(tb);
1050 pr_out(":");
1051 if (pt_attr) {
1052 uint16_t port_type = mnl_attr_get_u16(pt_attr);
1053
1054 pr_out(" type %s", port_type_name(port_type));
1055 if (dpt_attr) {
1056 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
1057
1058 if (port_type != des_port_type)
1059 pr_out("(%s)", port_type_name(des_port_type));
1060 }
1061 }
1062 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
1063 pr_out(" netdev %s",
1064 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
1065 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
1066 pr_out(" ibdev %s",
1067 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
1068 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
1069 pr_out(" split_group %u",
1070 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
1071 pr_out("\n");
1072 }
1073
1074 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
1075 {
1076 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1077 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1078
1079 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1080 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1081 !tb[DEVLINK_ATTR_PORT_INDEX])
1082 return MNL_CB_ERROR;
1083 pr_out_port(tb);
1084 return MNL_CB_OK;
1085 }
1086
1087 static int cmd_port_show(struct dl *dl)
1088 {
1089 struct nlmsghdr *nlh;
1090 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1091 int err;
1092
1093 if (dl_argc(dl) == 0)
1094 flags |= NLM_F_DUMP;
1095
1096 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
1097
1098 if (dl_argc(dl) > 0) {
1099 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1100 if (err)
1101 return err;
1102 }
1103
1104 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL);
1105 }
1106
1107 static int cmd_port_set(struct dl *dl)
1108 {
1109 struct nlmsghdr *nlh;
1110 int err;
1111
1112 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
1113 NLM_F_REQUEST | NLM_F_ACK);
1114
1115 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
1116 if (err)
1117 return err;
1118
1119 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1120 }
1121
1122 static int cmd_port_split(struct dl *dl)
1123 {
1124 struct nlmsghdr *nlh;
1125 int err;
1126
1127 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
1128 NLM_F_REQUEST | NLM_F_ACK);
1129
1130 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
1131 if (err)
1132 return err;
1133
1134 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1135 }
1136
1137 static int cmd_port_unsplit(struct dl *dl)
1138 {
1139 struct nlmsghdr *nlh;
1140 int err;
1141
1142 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
1143 NLM_F_REQUEST | NLM_F_ACK);
1144
1145 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1146 if (err)
1147 return err;
1148
1149 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1150 }
1151
1152 static int cmd_port(struct dl *dl)
1153 {
1154 if (dl_argv_match(dl, "help")) {
1155 cmd_port_help();
1156 return 0;
1157 } else if (dl_argv_match(dl, "show") ||
1158 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1159 dl_arg_inc(dl);
1160 return cmd_port_show(dl);
1161 } else if (dl_argv_match(dl, "set")) {
1162 dl_arg_inc(dl);
1163 return cmd_port_set(dl);
1164 } else if (dl_argv_match(dl, "split")) {
1165 dl_arg_inc(dl);
1166 return cmd_port_split(dl);
1167 } else if (dl_argv_match(dl, "unsplit")) {
1168 dl_arg_inc(dl);
1169 return cmd_port_unsplit(dl);
1170 }
1171 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1172 return -ENOENT;
1173 }
1174
1175 static void cmd_sb_help(void)
1176 {
1177 pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
1178 pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
1179 pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
1180 pr_out(" size POOL_SIZE thtype { static | dynamic }\n");
1181 pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1182 pr_out(" pool POOL_INDEX ]\n");
1183 pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1184 pr_out(" pool POOL_INDEX th THRESHOLD\n");
1185 pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1186 pr_out(" type { ingress | egress } ]\n");
1187 pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1188 pr_out(" type { ingress | egress } pool POOL_INDEX\n");
1189 pr_out(" th THRESHOLD\n");
1190 pr_out(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
1191 pr_out(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
1192 pr_out(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
1193 }
1194
1195 static void pr_out_sb(struct nlattr **tb)
1196 {
1197 pr_out_handle(tb);
1198 pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n",
1199 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1200 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]),
1201 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]),
1202 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]),
1203 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]),
1204 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
1205 }
1206
1207 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
1208 {
1209 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1210 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1211
1212 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1213 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1214 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
1215 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
1216 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
1217 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
1218 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
1219 return MNL_CB_ERROR;
1220 pr_out_sb(tb);
1221 return MNL_CB_OK;
1222 }
1223
1224 static int cmd_sb_show(struct dl *dl)
1225 {
1226 struct nlmsghdr *nlh;
1227 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1228 int err;
1229
1230 if (dl_argc(dl) == 0)
1231 flags |= NLM_F_DUMP;
1232
1233 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
1234
1235 if (dl_argc(dl) > 0) {
1236 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
1237 if (err)
1238 return err;
1239 }
1240
1241 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL);
1242 }
1243
1244 static const char *pool_type_name(uint8_t type)
1245 {
1246 switch (type) {
1247 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
1248 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
1249 default: return "<unknown type>";
1250 }
1251 }
1252
1253 static const char *threshold_type_name(uint8_t type)
1254 {
1255 switch (type) {
1256 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
1257 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
1258 default: return "<unknown type>";
1259 }
1260 }
1261
1262 static void pr_out_sb_pool(struct nlattr **tb)
1263 {
1264 pr_out_handle(tb);
1265 pr_out(": sb %u pool %u type %s size %u thtype %s\n",
1266 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1267 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]),
1268 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])),
1269 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]),
1270 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
1271 }
1272
1273 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1274 {
1275 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1276 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1277
1278 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1279 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1280 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
1281 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
1282 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
1283 return MNL_CB_ERROR;
1284 pr_out_sb_pool(tb);
1285 return MNL_CB_OK;
1286 }
1287
1288 static int cmd_sb_pool_show(struct dl *dl)
1289 {
1290 struct nlmsghdr *nlh;
1291 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1292 int err;
1293
1294 if (dl_argc(dl) == 0)
1295 flags |= NLM_F_DUMP;
1296
1297 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
1298
1299 if (dl_argc(dl) > 0) {
1300 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
1301 DL_OPT_SB);
1302 if (err)
1303 return err;
1304 }
1305
1306 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL);
1307 }
1308
1309 static int cmd_sb_pool_set(struct dl *dl)
1310 {
1311 struct nlmsghdr *nlh;
1312 int err;
1313
1314 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
1315 NLM_F_REQUEST | NLM_F_ACK);
1316
1317 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
1318 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
1319 if (err)
1320 return err;
1321
1322 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1323 }
1324
1325 static int cmd_sb_pool(struct dl *dl)
1326 {
1327 if (dl_argv_match(dl, "help")) {
1328 cmd_sb_help();
1329 return 0;
1330 } else if (dl_argv_match(dl, "show") ||
1331 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1332 dl_arg_inc(dl);
1333 return cmd_sb_pool_show(dl);
1334 } else if (dl_argv_match(dl, "set")) {
1335 dl_arg_inc(dl);
1336 return cmd_sb_pool_set(dl);
1337 }
1338 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1339 return -ENOENT;
1340 }
1341
1342 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
1343 {
1344 pr_out_port_handle_nice(dl, tb);
1345 pr_out(": sb %u pool %u threshold %u\n",
1346 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1347 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]),
1348 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
1349 }
1350
1351 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1352 {
1353 struct dl *dl = data;
1354 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1355 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1356
1357 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1358 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1359 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1360 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
1361 return MNL_CB_ERROR;
1362 pr_out_sb_port_pool(dl, tb);
1363 return MNL_CB_OK;
1364 }
1365
1366 static int cmd_sb_port_pool_show(struct dl *dl)
1367 {
1368 struct nlmsghdr *nlh;
1369 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1370 int err;
1371
1372 if (dl_argc(dl) == 0)
1373 flags |= NLM_F_DUMP;
1374
1375 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
1376
1377 if (dl_argc(dl) > 0) {
1378 err = dl_argv_parse_put(nlh, dl,
1379 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
1380 DL_OPT_SB);
1381 if (err)
1382 return err;
1383 }
1384
1385 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
1386 }
1387
1388 static int cmd_sb_port_pool_set(struct dl *dl)
1389 {
1390 struct nlmsghdr *nlh;
1391 int err;
1392
1393 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
1394 NLM_F_REQUEST | NLM_F_ACK);
1395
1396 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
1397 DL_OPT_SB_TH, DL_OPT_SB);
1398 if (err)
1399 return err;
1400
1401 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1402 }
1403
1404 static int cmd_sb_port_pool(struct dl *dl)
1405 {
1406 if (dl_argv_match(dl, "help")) {
1407 cmd_sb_help();
1408 return 0;
1409 } else if (dl_argv_match(dl, "show") ||
1410 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1411 dl_arg_inc(dl);
1412 return cmd_sb_port_pool_show(dl);
1413 } else if (dl_argv_match(dl, "set")) {
1414 dl_arg_inc(dl);
1415 return cmd_sb_port_pool_set(dl);
1416 }
1417 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1418 return -ENOENT;
1419 }
1420
1421 static int cmd_sb_port(struct dl *dl)
1422 {
1423 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1424 cmd_sb_help();
1425 return 0;
1426 } else if (dl_argv_match(dl, "pool")) {
1427 dl_arg_inc(dl);
1428 return cmd_sb_port_pool(dl);
1429 }
1430 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1431 return -ENOENT;
1432 }
1433
1434 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
1435 {
1436 pr_out_port_handle_nice(dl, tb);
1437 pr_out(": sb %u tc %u type %s pool %u threshold %u\n",
1438 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1439 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]),
1440 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])),
1441 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]),
1442 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
1443 }
1444
1445 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
1446 {
1447 struct dl *dl = data;
1448 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1449 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1450
1451 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1452 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1453 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1454 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
1455 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
1456 return MNL_CB_ERROR;
1457 pr_out_sb_tc_bind(dl, tb);
1458 return MNL_CB_OK;
1459 }
1460
1461 static int cmd_sb_tc_bind_show(struct dl *dl)
1462 {
1463 struct nlmsghdr *nlh;
1464 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1465 int err;
1466
1467 if (dl_argc(dl) == 0)
1468 flags |= NLM_F_DUMP;
1469
1470 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
1471
1472 if (dl_argc(dl) > 0) {
1473 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
1474 DL_OPT_SB_TYPE, DL_OPT_SB);
1475 if (err)
1476 return err;
1477 }
1478
1479 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
1480 }
1481
1482 static int cmd_sb_tc_bind_set(struct dl *dl)
1483 {
1484 struct nlmsghdr *nlh;
1485 int err;
1486
1487 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
1488 NLM_F_REQUEST | NLM_F_ACK);
1489
1490 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
1491 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
1492 DL_OPT_SB);
1493 if (err)
1494 return err;
1495
1496 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1497 }
1498
1499 static int cmd_sb_tc_bind(struct dl *dl)
1500 {
1501 if (dl_argv_match(dl, "help")) {
1502 cmd_sb_help();
1503 return 0;
1504 } else if (dl_argv_match(dl, "show") ||
1505 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1506 dl_arg_inc(dl);
1507 return cmd_sb_tc_bind_show(dl);
1508 } else if (dl_argv_match(dl, "set")) {
1509 dl_arg_inc(dl);
1510 return cmd_sb_tc_bind_set(dl);
1511 }
1512 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1513 return -ENOENT;
1514 }
1515
1516 static int cmd_sb_tc(struct dl *dl)
1517 {
1518 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1519 cmd_sb_help();
1520 return 0;
1521 } else if (dl_argv_match(dl, "bind")) {
1522 dl_arg_inc(dl);
1523 return cmd_sb_tc_bind(dl);
1524 }
1525 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1526 return -ENOENT;
1527 }
1528
1529 struct occ_item {
1530 struct list_head list;
1531 uint32_t index;
1532 uint32_t cur;
1533 uint32_t max;
1534 uint32_t bound_pool_index;
1535 };
1536
1537 struct occ_port {
1538 struct list_head list;
1539 char *bus_name;
1540 char *dev_name;
1541 uint32_t port_index;
1542 uint32_t sb_index;
1543 struct list_head pool_list;
1544 struct list_head ing_tc_list;
1545 struct list_head eg_tc_list;
1546 };
1547
1548 struct occ_show {
1549 struct dl *dl;
1550 int err;
1551 struct list_head port_list;
1552 };
1553
1554 static struct occ_item *occ_item_alloc(void)
1555 {
1556 return calloc(1, sizeof(struct occ_item));
1557 }
1558
1559 static void occ_item_free(struct occ_item *occ_item)
1560 {
1561 free(occ_item);
1562 }
1563
1564 static struct occ_port *occ_port_alloc(uint32_t port_index)
1565 {
1566 struct occ_port *occ_port;
1567
1568 occ_port = calloc(1, sizeof(*occ_port));
1569 if (!occ_port)
1570 return NULL;
1571 occ_port->port_index = port_index;
1572 INIT_LIST_HEAD(&occ_port->pool_list);
1573 INIT_LIST_HEAD(&occ_port->ing_tc_list);
1574 INIT_LIST_HEAD(&occ_port->eg_tc_list);
1575 return occ_port;
1576 }
1577
1578 static void occ_port_free(struct occ_port *occ_port)
1579 {
1580 struct occ_item *occ_item, *tmp;
1581
1582 list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
1583 occ_item_free(occ_item);
1584 list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
1585 occ_item_free(occ_item);
1586 list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
1587 occ_item_free(occ_item);
1588 }
1589
1590 static struct occ_show *occ_show_alloc(struct dl *dl)
1591 {
1592 struct occ_show *occ_show;
1593
1594 occ_show = calloc(1, sizeof(*occ_show));
1595 if (!occ_show)
1596 return NULL;
1597 occ_show->dl = dl;
1598 INIT_LIST_HEAD(&occ_show->port_list);
1599 return occ_show;
1600 }
1601
1602 static void occ_show_free(struct occ_show *occ_show)
1603 {
1604 struct occ_port *occ_port, *tmp;
1605
1606 list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
1607 occ_port_free(occ_port);
1608 }
1609
1610 static struct occ_port *occ_port_get(struct occ_show *occ_show,
1611 struct nlattr **tb)
1612 {
1613 struct occ_port *occ_port;
1614 uint32_t port_index;
1615
1616 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
1617
1618 list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
1619 if (occ_port->port_index == port_index)
1620 return occ_port;
1621 }
1622 occ_port = occ_port_alloc(port_index);
1623 if (!occ_port)
1624 return NULL;
1625 list_add_tail(&occ_port->list, &occ_show->port_list);
1626 return occ_port;
1627 }
1628
1629 static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
1630 bool bound_pool)
1631 {
1632 struct occ_item *occ_item;
1633 int i = 1;
1634
1635 pr_out_sp(7, " %s:", label);
1636 list_for_each_entry(occ_item, list, list) {
1637 if ((i - 1) % 4 == 0 && i != 1)
1638 pr_out_sp(7, " ");
1639 if (bound_pool)
1640 pr_out_sp(7, "%2u(%u):", occ_item->index,
1641 occ_item->bound_pool_index);
1642 else
1643 pr_out_sp(7, "%2u:", occ_item->index);
1644 pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max);
1645 if (i++ % 4 == 0)
1646 pr_out("\n");
1647 }
1648 if ((i - 1) % 4 != 0)
1649 pr_out("\n");
1650 }
1651
1652 static void pr_out_occ_show_port(struct occ_port *occ_port)
1653 {
1654 pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
1655 pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
1656 pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
1657 }
1658
1659 static void pr_out_occ_show(struct occ_show *occ_show)
1660 {
1661 struct dl *dl = occ_show->dl;
1662 struct dl_opts *opts = &dl->opts;
1663 struct occ_port *occ_port;
1664
1665 list_for_each_entry(occ_port, &occ_show->port_list, list) {
1666 __pr_out_port_handle_nice(dl, opts->bus_name, opts->dev_name,
1667 occ_port->port_index);
1668 pr_out(":\n");
1669 pr_out_occ_show_port(occ_port);
1670 }
1671 }
1672
1673 static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
1674 struct nlattr **tb)
1675 {
1676 struct occ_port *occ_port;
1677 struct occ_item *occ_item;
1678
1679 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
1680 return;
1681
1682 occ_port = occ_port_get(occ_show, tb);
1683 if (!occ_port) {
1684 occ_show->err = -ENOMEM;
1685 return;
1686 }
1687
1688 occ_item = occ_item_alloc();
1689 if (!occ_item) {
1690 occ_show->err = -ENOMEM;
1691 return;
1692 }
1693 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
1694 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
1695 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
1696 list_add_tail(&occ_item->list, &occ_port->pool_list);
1697 }
1698
1699 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
1700 {
1701 struct occ_show *occ_show = data;
1702 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1703 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1704
1705 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1706 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1707 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1708 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
1709 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
1710 return MNL_CB_ERROR;
1711 cmd_sb_occ_port_pool_process(occ_show, tb);
1712 return MNL_CB_OK;
1713 }
1714
1715 static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
1716 struct nlattr **tb)
1717 {
1718 struct occ_port *occ_port;
1719 struct occ_item *occ_item;
1720 uint8_t pool_type;
1721
1722 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
1723 return;
1724
1725 occ_port = occ_port_get(occ_show, tb);
1726 if (!occ_port) {
1727 occ_show->err = -ENOMEM;
1728 return;
1729 }
1730
1731 occ_item = occ_item_alloc();
1732 if (!occ_item) {
1733 occ_show->err = -ENOMEM;
1734 return;
1735 }
1736 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
1737 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
1738 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
1739 occ_item->bound_pool_index =
1740 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
1741 pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
1742 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
1743 list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
1744 else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
1745 list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
1746 else
1747 occ_item_free(occ_item);
1748 }
1749
1750 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
1751 {
1752 struct occ_show *occ_show = data;
1753 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1754 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1755
1756 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1757 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1758 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1759 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
1760 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
1761 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
1762 return MNL_CB_ERROR;
1763 cmd_sb_occ_tc_pool_process(occ_show, tb);
1764 return MNL_CB_OK;
1765 }
1766
1767 static int cmd_sb_occ_show(struct dl *dl)
1768 {
1769 struct nlmsghdr *nlh;
1770 struct occ_show *occ_show;
1771 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
1772 int err;
1773
1774 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
1775 if (err)
1776 return err;
1777
1778 occ_show = occ_show_alloc(dl);
1779 if (!occ_show)
1780 return -ENOMEM;
1781
1782 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
1783
1784 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
1785 cmd_sb_occ_port_pool_process_cb, occ_show);
1786 if (err)
1787 goto out;
1788
1789 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
1790
1791 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
1792 cmd_sb_occ_tc_pool_process_cb, occ_show);
1793 if (err)
1794 goto out;
1795
1796 pr_out_occ_show(occ_show);
1797
1798 out:
1799 occ_show_free(occ_show);
1800 return err;
1801 }
1802
1803 static int cmd_sb_occ_snapshot(struct dl *dl)
1804 {
1805 struct nlmsghdr *nlh;
1806 int err;
1807
1808 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
1809 NLM_F_REQUEST | NLM_F_ACK);
1810
1811 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
1812 if (err)
1813 return err;
1814
1815 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1816 }
1817
1818 static int cmd_sb_occ_clearmax(struct dl *dl)
1819 {
1820 struct nlmsghdr *nlh;
1821 int err;
1822
1823 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
1824 NLM_F_REQUEST | NLM_F_ACK);
1825
1826 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
1827 if (err)
1828 return err;
1829
1830 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1831 }
1832
1833 static int cmd_sb_occ(struct dl *dl)
1834 {
1835 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1836 cmd_sb_help();
1837 return 0;
1838 } else if (dl_argv_match(dl, "show") ||
1839 dl_argv_match(dl, "list")) {
1840 dl_arg_inc(dl);
1841 return cmd_sb_occ_show(dl);
1842 } else if (dl_argv_match(dl, "snapshot")) {
1843 dl_arg_inc(dl);
1844 return cmd_sb_occ_snapshot(dl);
1845 } else if (dl_argv_match(dl, "clearmax")) {
1846 dl_arg_inc(dl);
1847 return cmd_sb_occ_clearmax(dl);
1848 }
1849 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1850 return -ENOENT;
1851 }
1852
1853 static int cmd_sb(struct dl *dl)
1854 {
1855 if (dl_argv_match(dl, "help")) {
1856 cmd_sb_help();
1857 return 0;
1858 } else if (dl_argv_match(dl, "show") ||
1859 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1860 dl_arg_inc(dl);
1861 return cmd_sb_show(dl);
1862 } else if (dl_argv_match(dl, "pool")) {
1863 dl_arg_inc(dl);
1864 return cmd_sb_pool(dl);
1865 } else if (dl_argv_match(dl, "port")) {
1866 dl_arg_inc(dl);
1867 return cmd_sb_port(dl);
1868 } else if (dl_argv_match(dl, "tc")) {
1869 dl_arg_inc(dl);
1870 return cmd_sb_tc(dl);
1871 } else if (dl_argv_match(dl, "occupancy")) {
1872 dl_arg_inc(dl);
1873 return cmd_sb_occ(dl);
1874 }
1875 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1876 return -ENOENT;
1877 }
1878
1879 static const char *cmd_name(uint8_t cmd)
1880 {
1881 switch (cmd) {
1882 case DEVLINK_CMD_UNSPEC: return "unspec";
1883 case DEVLINK_CMD_GET: return "get";
1884 case DEVLINK_CMD_SET: return "set";
1885 case DEVLINK_CMD_NEW: return "new";
1886 case DEVLINK_CMD_DEL: return "del";
1887 case DEVLINK_CMD_PORT_GET: return "get";
1888 case DEVLINK_CMD_PORT_SET: return "set";
1889 case DEVLINK_CMD_PORT_NEW: return "net";
1890 case DEVLINK_CMD_PORT_DEL: return "del";
1891 default: return "<unknown cmd>";
1892 }
1893 }
1894
1895 static const char *cmd_obj(uint8_t cmd)
1896 {
1897 switch (cmd) {
1898 case DEVLINK_CMD_UNSPEC: return "unspec";
1899 case DEVLINK_CMD_GET:
1900 case DEVLINK_CMD_SET:
1901 case DEVLINK_CMD_NEW:
1902 case DEVLINK_CMD_DEL:
1903 return "dev";
1904 case DEVLINK_CMD_PORT_GET:
1905 case DEVLINK_CMD_PORT_SET:
1906 case DEVLINK_CMD_PORT_NEW:
1907 case DEVLINK_CMD_PORT_DEL:
1908 return "port";
1909 default: return "<unknown obj>";
1910 }
1911 }
1912
1913 static void pr_out_mon_header(uint8_t cmd)
1914 {
1915 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
1916 }
1917
1918 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
1919 {
1920 const char *obj = cmd_obj(cmd);
1921 unsigned int index = 0;
1922 const char *cur_obj;
1923
1924 if (dl_no_arg(dl))
1925 return true;
1926 while ((cur_obj = dl_argv_index(dl, index++))) {
1927 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
1928 return true;
1929 }
1930 return false;
1931 }
1932
1933 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
1934 {
1935 struct dl *dl = data;
1936 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1937 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1938 uint8_t cmd = genl->cmd;
1939
1940 if (!cmd_filter_check(dl, cmd))
1941 return MNL_CB_OK;
1942
1943 switch (cmd) {
1944 case DEVLINK_CMD_GET: /* fall through */
1945 case DEVLINK_CMD_SET: /* fall through */
1946 case DEVLINK_CMD_NEW: /* fall through */
1947 case DEVLINK_CMD_DEL:
1948 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1949 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
1950 return MNL_CB_ERROR;
1951 pr_out_mon_header(genl->cmd);
1952 pr_out_dev(tb);
1953 break;
1954 case DEVLINK_CMD_PORT_GET: /* fall through */
1955 case DEVLINK_CMD_PORT_SET: /* fall through */
1956 case DEVLINK_CMD_PORT_NEW: /* fall through */
1957 case DEVLINK_CMD_PORT_DEL:
1958 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1959 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1960 !tb[DEVLINK_ATTR_PORT_INDEX])
1961 return MNL_CB_ERROR;
1962 pr_out_mon_header(genl->cmd);
1963 pr_out_port(tb);
1964 break;
1965 }
1966 return MNL_CB_OK;
1967 }
1968
1969 static int cmd_mon_show(struct dl *dl)
1970 {
1971 int err;
1972 unsigned int index = 0;
1973 const char *cur_obj;
1974
1975 while ((cur_obj = dl_argv_index(dl, index++))) {
1976 if (strcmp(cur_obj, "all") != 0 &&
1977 strcmp(cur_obj, "dev") != 0 &&
1978 strcmp(cur_obj, "port") != 0) {
1979 pr_err("Unknown object \"%s\"\n", cur_obj);
1980 return -EINVAL;
1981 }
1982 }
1983 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
1984 if (err)
1985 return err;
1986 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
1987 if (err)
1988 return err;
1989 return 0;
1990 }
1991
1992 static void cmd_mon_help(void)
1993 {
1994 pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
1995 "where OBJECT-LIST := { dev | port }\n");
1996 }
1997
1998 static int cmd_mon(struct dl *dl)
1999 {
2000 if (dl_argv_match(dl, "help")) {
2001 cmd_mon_help();
2002 return 0;
2003 } else if (dl_no_arg(dl)) {
2004 dl_arg_inc(dl);
2005 return cmd_mon_show(dl);
2006 }
2007 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2008 return -ENOENT;
2009 }
2010
2011 static void help(void)
2012 {
2013 pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
2014 "where OBJECT := { dev | port | sb | monitor }\n"
2015 " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n");
2016 }
2017
2018 static int dl_cmd(struct dl *dl)
2019 {
2020 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2021 help();
2022 return 0;
2023 } else if (dl_argv_match(dl, "dev")) {
2024 dl_arg_inc(dl);
2025 return cmd_dev(dl);
2026 } else if (dl_argv_match(dl, "port")) {
2027 dl_arg_inc(dl);
2028 return cmd_port(dl);
2029 } else if (dl_argv_match(dl, "sb")) {
2030 dl_arg_inc(dl);
2031 return cmd_sb(dl);
2032 } else if (dl_argv_match(dl, "monitor")) {
2033 dl_arg_inc(dl);
2034 return cmd_mon(dl);
2035 }
2036 pr_err("Object \"%s\" not found\n", dl_argv(dl));
2037 return -ENOENT;
2038 }
2039
2040 static int dl_init(struct dl *dl, int argc, char **argv)
2041 {
2042 int err;
2043
2044 dl->argc = argc;
2045 dl->argv = argv;
2046
2047 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
2048 if (!dl->nlg) {
2049 pr_err("Failed to connect to devlink Netlink\n");
2050 return -errno;
2051 }
2052
2053 err = ifname_map_init(dl);
2054 if (err) {
2055 pr_err("Failed to create index map\n");
2056 goto err_ifname_map_create;
2057 }
2058 return 0;
2059
2060 err_ifname_map_create:
2061 mnlg_socket_close(dl->nlg);
2062 return err;
2063 }
2064
2065 static void dl_fini(struct dl *dl)
2066 {
2067 ifname_map_fini(dl);
2068 mnlg_socket_close(dl->nlg);
2069 }
2070
2071 static struct dl *dl_alloc(void)
2072 {
2073 struct dl *dl;
2074
2075 dl = calloc(1, sizeof(*dl));
2076 if (!dl)
2077 return NULL;
2078 return dl;
2079 }
2080
2081 static void dl_free(struct dl *dl)
2082 {
2083 free(dl);
2084 }
2085
2086 int main(int argc, char **argv)
2087 {
2088 static const struct option long_options[] = {
2089 { "Version", no_argument, NULL, 'V' },
2090 { "no-nice-names", no_argument, NULL, 'n' },
2091 { NULL, 0, NULL, 0 }
2092 };
2093 struct dl *dl;
2094 int opt;
2095 int err;
2096 int ret;
2097
2098 dl = dl_alloc();
2099 if (!dl) {
2100 pr_err("Failed to allocate memory for devlink\n");
2101 return EXIT_FAILURE;
2102 }
2103
2104 while ((opt = getopt_long(argc, argv, "Vn",
2105 long_options, NULL)) >= 0) {
2106
2107 switch (opt) {
2108 case 'V':
2109 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
2110 return EXIT_SUCCESS;
2111 case 'n':
2112 dl->no_nice_names = true;
2113 break;
2114 default:
2115 pr_err("Unknown option.\n");
2116 help();
2117 return EXIT_FAILURE;
2118 }
2119 }
2120
2121 argc -= optind;
2122 argv += optind;
2123
2124 err = dl_init(dl, argc, argv);
2125 if (err) {
2126 ret = EXIT_FAILURE;
2127 goto dl_free;
2128 }
2129
2130 err = dl_cmd(dl);
2131 if (err) {
2132 ret = EXIT_FAILURE;
2133 goto dl_fini;
2134 }
2135
2136 ret = EXIT_SUCCESS;
2137
2138 dl_fini:
2139 dl_fini(dl);
2140 dl_free:
2141 dl_free(dl);
2142
2143 return ret;
2144 }