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