]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
devlink: implement shared buffer support
[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
862 static void cmd_dev_help(void)
863 {
864 pr_out("Usage: devlink dev show [ DEV ]\n");
865 }
866
867 static void __pr_out_handle(const char *bus_name, const char *dev_name)
868 {
869 pr_out("%s/%s", bus_name, dev_name);
870 }
871
872 static void pr_out_handle(struct nlattr **tb)
873 {
874 __pr_out_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
875 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]));
876 }
877
878 static void __pr_out_port_handle(const char *bus_name, const char *dev_name,
879 uint32_t port_index)
880 {
881 __pr_out_handle(bus_name, dev_name);
882 pr_out("/%d", port_index);
883 }
884
885 static void pr_out_port_handle(struct nlattr **tb)
886 {
887 __pr_out_port_handle(mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]),
888 mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]),
889 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]));
890 }
891
892 static void __pr_out_port_handle_nice(struct dl *dl, const char *bus_name,
893 const char *dev_name, uint32_t port_index)
894 {
895 char *ifname;
896 int err;
897
898 if (dl->no_nice_names)
899 goto no_nice_names;
900
901 err = ifname_map_rev_lookup(dl, bus_name, dev_name,
902 port_index, &ifname);
903 if (err)
904 goto no_nice_names;
905 pr_out("%s", ifname);
906 return;
907
908 no_nice_names:
909 __pr_out_port_handle(bus_name, dev_name, port_index);
910 }
911
912 static void pr_out_port_handle_nice(struct dl *dl, struct nlattr **tb)
913 {
914 const char *bus_name;
915 const char *dev_name;
916 uint32_t port_index;
917
918 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
919 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
920 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
921
922 __pr_out_port_handle_nice(dl, bus_name, dev_name, port_index);
923 }
924
925 static void pr_out_dev(struct nlattr **tb)
926 {
927 pr_out_handle(tb);
928 pr_out("\n");
929 }
930
931 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
932 {
933 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
934 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
935
936 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
937 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
938 return MNL_CB_ERROR;
939 pr_out_dev(tb);
940 return MNL_CB_OK;
941 }
942
943 static int cmd_dev_show(struct dl *dl)
944 {
945 struct nlmsghdr *nlh;
946 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
947 int err;
948
949 if (dl_argc(dl) == 0)
950 flags |= NLM_F_DUMP;
951
952 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
953
954 if (dl_argc(dl) > 0) {
955 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
956 if (err)
957 return err;
958 }
959
960 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, NULL);
961 }
962
963 static int cmd_dev(struct dl *dl)
964 {
965 if (dl_argv_match(dl, "help")) {
966 cmd_dev_help();
967 return 0;
968 } else if (dl_argv_match(dl, "show") ||
969 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
970 dl_arg_inc(dl);
971 return cmd_dev_show(dl);
972 }
973 pr_err("Command \"%s\" not found\n", dl_argv(dl));
974 return -ENOENT;
975 }
976
977 static void cmd_port_help(void)
978 {
979 pr_out("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
980 pr_out(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
981 pr_out(" devlink port split DEV/PORT_INDEX count COUNT\n");
982 pr_out(" devlink port unsplit DEV/PORT_INDEX\n");
983 }
984
985 static const char *port_type_name(uint32_t type)
986 {
987 switch (type) {
988 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
989 case DEVLINK_PORT_TYPE_AUTO: return "auto";
990 case DEVLINK_PORT_TYPE_ETH: return "eth";
991 case DEVLINK_PORT_TYPE_IB: return "ib";
992 default: return "<unknown type>";
993 }
994 }
995
996 static void pr_out_port(struct nlattr **tb)
997 {
998 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
999 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
1000
1001 pr_out_port_handle(tb);
1002 pr_out(":");
1003 if (pt_attr) {
1004 uint16_t port_type = mnl_attr_get_u16(pt_attr);
1005
1006 pr_out(" type %s", port_type_name(port_type));
1007 if (dpt_attr) {
1008 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
1009
1010 if (port_type != des_port_type)
1011 pr_out("(%s)", port_type_name(des_port_type));
1012 }
1013 }
1014 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
1015 pr_out(" netdev %s",
1016 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
1017 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
1018 pr_out(" ibdev %s",
1019 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
1020 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
1021 pr_out(" split_group %u",
1022 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
1023 pr_out("\n");
1024 }
1025
1026 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
1027 {
1028 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1029 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1030
1031 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1032 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1033 !tb[DEVLINK_ATTR_PORT_INDEX])
1034 return MNL_CB_ERROR;
1035 pr_out_port(tb);
1036 return MNL_CB_OK;
1037 }
1038
1039 static int cmd_port_show(struct dl *dl)
1040 {
1041 struct nlmsghdr *nlh;
1042 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1043 int err;
1044
1045 if (dl_argc(dl) == 0)
1046 flags |= NLM_F_DUMP;
1047
1048 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
1049
1050 if (dl_argc(dl) > 0) {
1051 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1052 if (err)
1053 return err;
1054 }
1055
1056 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, NULL);
1057 }
1058
1059 static int cmd_port_set(struct dl *dl)
1060 {
1061 struct nlmsghdr *nlh;
1062 int err;
1063
1064 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
1065 NLM_F_REQUEST | NLM_F_ACK);
1066
1067 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
1068 if (err)
1069 return err;
1070
1071 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1072 }
1073
1074 static int cmd_port_split(struct dl *dl)
1075 {
1076 struct nlmsghdr *nlh;
1077 int err;
1078
1079 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
1080 NLM_F_REQUEST | NLM_F_ACK);
1081
1082 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
1083 if (err)
1084 return err;
1085
1086 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1087 }
1088
1089 static int cmd_port_unsplit(struct dl *dl)
1090 {
1091 struct nlmsghdr *nlh;
1092 int err;
1093
1094 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
1095 NLM_F_REQUEST | NLM_F_ACK);
1096
1097 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1098 if (err)
1099 return err;
1100
1101 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1102 }
1103
1104 static int cmd_port(struct dl *dl)
1105 {
1106 if (dl_argv_match(dl, "help")) {
1107 cmd_port_help();
1108 return 0;
1109 } else if (dl_argv_match(dl, "show") ||
1110 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1111 dl_arg_inc(dl);
1112 return cmd_port_show(dl);
1113 } else if (dl_argv_match(dl, "set")) {
1114 dl_arg_inc(dl);
1115 return cmd_port_set(dl);
1116 } else if (dl_argv_match(dl, "split")) {
1117 dl_arg_inc(dl);
1118 return cmd_port_split(dl);
1119 } else if (dl_argv_match(dl, "unsplit")) {
1120 dl_arg_inc(dl);
1121 return cmd_port_unsplit(dl);
1122 }
1123 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1124 return -ENOENT;
1125 }
1126
1127 static void cmd_sb_help(void)
1128 {
1129 pr_out("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
1130 pr_out(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
1131 pr_out(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
1132 pr_out(" size POOL_SIZE thtype { static | dynamic }\n");
1133 pr_out(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1134 pr_out(" pool POOL_INDEX ]\n");
1135 pr_out(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1136 pr_out(" pool POOL_INDEX th THRESHOLD\n");
1137 pr_out(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1138 pr_out(" type { ingress | egress } ]\n");
1139 pr_out(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1140 pr_out(" type { ingress | egress } pool POOL_INDEX\n");
1141 pr_out(" th THRESHOLD\n");
1142 }
1143
1144 static void pr_out_sb(struct nlattr **tb)
1145 {
1146 pr_out_handle(tb);
1147 pr_out(": sb %u size %u ing_pools %u eg_pools %u ing_tcs %u eg_tcs %u\n",
1148 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1149 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]),
1150 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]),
1151 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]),
1152 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]),
1153 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
1154 }
1155
1156 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
1157 {
1158 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1159 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1160
1161 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1162 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1163 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
1164 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
1165 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
1166 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
1167 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
1168 return MNL_CB_ERROR;
1169 pr_out_sb(tb);
1170 return MNL_CB_OK;
1171 }
1172
1173 static int cmd_sb_show(struct dl *dl)
1174 {
1175 struct nlmsghdr *nlh;
1176 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1177 int err;
1178
1179 if (dl_argc(dl) == 0)
1180 flags |= NLM_F_DUMP;
1181
1182 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
1183
1184 if (dl_argc(dl) > 0) {
1185 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
1186 if (err)
1187 return err;
1188 }
1189
1190 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, NULL);
1191 }
1192
1193 static const char *pool_type_name(uint8_t type)
1194 {
1195 switch (type) {
1196 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
1197 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
1198 default: return "<unknown type>";
1199 }
1200 }
1201
1202 static const char *threshold_type_name(uint8_t type)
1203 {
1204 switch (type) {
1205 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
1206 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
1207 default: return "<unknown type>";
1208 }
1209 }
1210
1211 static void pr_out_sb_pool(struct nlattr **tb)
1212 {
1213 pr_out_handle(tb);
1214 pr_out(": sb %u pool %u type %s size %u thtype %s\n",
1215 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1216 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]),
1217 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])),
1218 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]),
1219 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
1220 }
1221
1222 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1223 {
1224 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1225 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1226
1227 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1228 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1229 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
1230 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
1231 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
1232 return MNL_CB_ERROR;
1233 pr_out_sb_pool(tb);
1234 return MNL_CB_OK;
1235 }
1236
1237 static int cmd_sb_pool_show(struct dl *dl)
1238 {
1239 struct nlmsghdr *nlh;
1240 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1241 int err;
1242
1243 if (dl_argc(dl) == 0)
1244 flags |= NLM_F_DUMP;
1245
1246 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
1247
1248 if (dl_argc(dl) > 0) {
1249 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
1250 DL_OPT_SB);
1251 if (err)
1252 return err;
1253 }
1254
1255 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, NULL);
1256 }
1257
1258 static int cmd_sb_pool_set(struct dl *dl)
1259 {
1260 struct nlmsghdr *nlh;
1261 int err;
1262
1263 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
1264 NLM_F_REQUEST | NLM_F_ACK);
1265
1266 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
1267 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
1268 if (err)
1269 return err;
1270
1271 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1272 }
1273
1274 static int cmd_sb_pool(struct dl *dl)
1275 {
1276 if (dl_argv_match(dl, "help")) {
1277 cmd_sb_help();
1278 return 0;
1279 } else if (dl_argv_match(dl, "show") ||
1280 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1281 dl_arg_inc(dl);
1282 return cmd_sb_pool_show(dl);
1283 } else if (dl_argv_match(dl, "set")) {
1284 dl_arg_inc(dl);
1285 return cmd_sb_pool_set(dl);
1286 }
1287 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1288 return -ENOENT;
1289 }
1290
1291 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
1292 {
1293 pr_out_port_handle_nice(dl, tb);
1294 pr_out(": sb %u pool %u threshold %u\n",
1295 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1296 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]),
1297 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
1298 }
1299
1300 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1301 {
1302 struct dl *dl = data;
1303 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1304 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1305
1306 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1307 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1308 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1309 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
1310 return MNL_CB_ERROR;
1311 pr_out_sb_port_pool(dl, tb);
1312 return MNL_CB_OK;
1313 }
1314
1315 static int cmd_sb_port_pool_show(struct dl *dl)
1316 {
1317 struct nlmsghdr *nlh;
1318 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1319 int err;
1320
1321 if (dl_argc(dl) == 0)
1322 flags |= NLM_F_DUMP;
1323
1324 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
1325
1326 if (dl_argc(dl) > 0) {
1327 err = dl_argv_parse_put(nlh, dl,
1328 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
1329 DL_OPT_SB);
1330 if (err)
1331 return err;
1332 }
1333
1334 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
1335 }
1336
1337 static int cmd_sb_port_pool_set(struct dl *dl)
1338 {
1339 struct nlmsghdr *nlh;
1340 int err;
1341
1342 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
1343 NLM_F_REQUEST | NLM_F_ACK);
1344
1345 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
1346 DL_OPT_SB_TH, DL_OPT_SB);
1347 if (err)
1348 return err;
1349
1350 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1351 }
1352
1353 static int cmd_sb_port_pool(struct dl *dl)
1354 {
1355 if (dl_argv_match(dl, "help")) {
1356 cmd_sb_help();
1357 return 0;
1358 } else if (dl_argv_match(dl, "show") ||
1359 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1360 dl_arg_inc(dl);
1361 return cmd_sb_port_pool_show(dl);
1362 } else if (dl_argv_match(dl, "set")) {
1363 dl_arg_inc(dl);
1364 return cmd_sb_port_pool_set(dl);
1365 }
1366 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1367 return -ENOENT;
1368 }
1369
1370 static int cmd_sb_port(struct dl *dl)
1371 {
1372 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1373 cmd_sb_help();
1374 return 0;
1375 } else if (dl_argv_match(dl, "pool")) {
1376 dl_arg_inc(dl);
1377 return cmd_sb_port_pool(dl);
1378 }
1379 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1380 return -ENOENT;
1381 }
1382
1383 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
1384 {
1385 pr_out_port_handle_nice(dl, tb);
1386 pr_out(": sb %u tc %u type %s pool %u threshold %u\n",
1387 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]),
1388 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]),
1389 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])),
1390 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]),
1391 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
1392 }
1393
1394 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
1395 {
1396 struct dl *dl = data;
1397 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1398 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1399
1400 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1401 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1402 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1403 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
1404 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
1405 return MNL_CB_ERROR;
1406 pr_out_sb_tc_bind(dl, tb);
1407 return MNL_CB_OK;
1408 }
1409
1410 static int cmd_sb_tc_bind_show(struct dl *dl)
1411 {
1412 struct nlmsghdr *nlh;
1413 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1414 int err;
1415
1416 if (dl_argc(dl) == 0)
1417 flags |= NLM_F_DUMP;
1418
1419 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
1420
1421 if (dl_argc(dl) > 0) {
1422 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
1423 DL_OPT_SB_TYPE, DL_OPT_SB);
1424 if (err)
1425 return err;
1426 }
1427
1428 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
1429 }
1430
1431 static int cmd_sb_tc_bind_set(struct dl *dl)
1432 {
1433 struct nlmsghdr *nlh;
1434 int err;
1435
1436 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
1437 NLM_F_REQUEST | NLM_F_ACK);
1438
1439 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
1440 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
1441 DL_OPT_SB);
1442 if (err)
1443 return err;
1444
1445 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1446 }
1447
1448 static int cmd_sb_tc_bind(struct dl *dl)
1449 {
1450 if (dl_argv_match(dl, "help")) {
1451 cmd_sb_help();
1452 return 0;
1453 } else if (dl_argv_match(dl, "show") ||
1454 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1455 dl_arg_inc(dl);
1456 return cmd_sb_tc_bind_show(dl);
1457 } else if (dl_argv_match(dl, "set")) {
1458 dl_arg_inc(dl);
1459 return cmd_sb_tc_bind_set(dl);
1460 }
1461 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1462 return -ENOENT;
1463 }
1464
1465 static int cmd_sb_tc(struct dl *dl)
1466 {
1467 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1468 cmd_sb_help();
1469 return 0;
1470 } else if (dl_argv_match(dl, "bind")) {
1471 dl_arg_inc(dl);
1472 return cmd_sb_tc_bind(dl);
1473 }
1474 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1475 return -ENOENT;
1476 }
1477
1478 static int cmd_sb(struct dl *dl)
1479 {
1480 if (dl_argv_match(dl, "help")) {
1481 cmd_sb_help();
1482 return 0;
1483 } else if (dl_argv_match(dl, "show") ||
1484 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1485 dl_arg_inc(dl);
1486 return cmd_sb_show(dl);
1487 } else if (dl_argv_match(dl, "pool")) {
1488 dl_arg_inc(dl);
1489 return cmd_sb_pool(dl);
1490 } else if (dl_argv_match(dl, "port")) {
1491 dl_arg_inc(dl);
1492 return cmd_sb_port(dl);
1493 } else if (dl_argv_match(dl, "tc")) {
1494 dl_arg_inc(dl);
1495 return cmd_sb_tc(dl);
1496 }
1497 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1498 return -ENOENT;
1499 }
1500
1501 static const char *cmd_name(uint8_t cmd)
1502 {
1503 switch (cmd) {
1504 case DEVLINK_CMD_UNSPEC: return "unspec";
1505 case DEVLINK_CMD_GET: return "get";
1506 case DEVLINK_CMD_SET: return "set";
1507 case DEVLINK_CMD_NEW: return "new";
1508 case DEVLINK_CMD_DEL: return "del";
1509 case DEVLINK_CMD_PORT_GET: return "get";
1510 case DEVLINK_CMD_PORT_SET: return "set";
1511 case DEVLINK_CMD_PORT_NEW: return "net";
1512 case DEVLINK_CMD_PORT_DEL: return "del";
1513 default: return "<unknown cmd>";
1514 }
1515 }
1516
1517 static const char *cmd_obj(uint8_t cmd)
1518 {
1519 switch (cmd) {
1520 case DEVLINK_CMD_UNSPEC: return "unspec";
1521 case DEVLINK_CMD_GET:
1522 case DEVLINK_CMD_SET:
1523 case DEVLINK_CMD_NEW:
1524 case DEVLINK_CMD_DEL:
1525 return "dev";
1526 case DEVLINK_CMD_PORT_GET:
1527 case DEVLINK_CMD_PORT_SET:
1528 case DEVLINK_CMD_PORT_NEW:
1529 case DEVLINK_CMD_PORT_DEL:
1530 return "port";
1531 default: return "<unknown obj>";
1532 }
1533 }
1534
1535 static void pr_out_mon_header(uint8_t cmd)
1536 {
1537 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
1538 }
1539
1540 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
1541 {
1542 const char *obj = cmd_obj(cmd);
1543 unsigned int index = 0;
1544 const char *cur_obj;
1545
1546 if (dl_no_arg(dl))
1547 return true;
1548 while ((cur_obj = dl_argv_index(dl, index++))) {
1549 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
1550 return true;
1551 }
1552 return false;
1553 }
1554
1555 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
1556 {
1557 struct dl *dl = data;
1558 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1559 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1560 uint8_t cmd = genl->cmd;
1561
1562 if (!cmd_filter_check(dl, cmd))
1563 return MNL_CB_OK;
1564
1565 switch (cmd) {
1566 case DEVLINK_CMD_GET: /* fall through */
1567 case DEVLINK_CMD_SET: /* fall through */
1568 case DEVLINK_CMD_NEW: /* fall through */
1569 case DEVLINK_CMD_DEL:
1570 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1571 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
1572 return MNL_CB_ERROR;
1573 pr_out_mon_header(genl->cmd);
1574 pr_out_dev(tb);
1575 break;
1576 case DEVLINK_CMD_PORT_GET: /* fall through */
1577 case DEVLINK_CMD_PORT_SET: /* fall through */
1578 case DEVLINK_CMD_PORT_NEW: /* fall through */
1579 case DEVLINK_CMD_PORT_DEL:
1580 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1581 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1582 !tb[DEVLINK_ATTR_PORT_INDEX])
1583 return MNL_CB_ERROR;
1584 pr_out_mon_header(genl->cmd);
1585 pr_out_port(tb);
1586 break;
1587 }
1588 return MNL_CB_OK;
1589 }
1590
1591 static int cmd_mon_show(struct dl *dl)
1592 {
1593 int err;
1594 unsigned int index = 0;
1595 const char *cur_obj;
1596
1597 while ((cur_obj = dl_argv_index(dl, index++))) {
1598 if (strcmp(cur_obj, "all") != 0 &&
1599 strcmp(cur_obj, "dev") != 0 &&
1600 strcmp(cur_obj, "port") != 0) {
1601 pr_err("Unknown object \"%s\"\n", cur_obj);
1602 return -EINVAL;
1603 }
1604 }
1605 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
1606 if (err)
1607 return err;
1608 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
1609 if (err)
1610 return err;
1611 return 0;
1612 }
1613
1614 static void cmd_mon_help(void)
1615 {
1616 pr_out("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
1617 "where OBJECT-LIST := { dev | port }\n");
1618 }
1619
1620 static int cmd_mon(struct dl *dl)
1621 {
1622 if (dl_argv_match(dl, "help")) {
1623 cmd_mon_help();
1624 return 0;
1625 } else if (dl_no_arg(dl)) {
1626 dl_arg_inc(dl);
1627 return cmd_mon_show(dl);
1628 }
1629 pr_err("Command \"%s\" not found\n", dl_argv(dl));
1630 return -ENOENT;
1631 }
1632
1633 static void help(void)
1634 {
1635 pr_out("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
1636 "where OBJECT := { dev | port | sb | monitor }\n"
1637 " OPTIONS := { -V[ersion] | -n[no-nice-names] }\n");
1638 }
1639
1640 static int dl_cmd(struct dl *dl)
1641 {
1642 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1643 help();
1644 return 0;
1645 } else if (dl_argv_match(dl, "dev")) {
1646 dl_arg_inc(dl);
1647 return cmd_dev(dl);
1648 } else if (dl_argv_match(dl, "port")) {
1649 dl_arg_inc(dl);
1650 return cmd_port(dl);
1651 } else if (dl_argv_match(dl, "sb")) {
1652 dl_arg_inc(dl);
1653 return cmd_sb(dl);
1654 } else if (dl_argv_match(dl, "monitor")) {
1655 dl_arg_inc(dl);
1656 return cmd_mon(dl);
1657 }
1658 pr_err("Object \"%s\" not found\n", dl_argv(dl));
1659 return -ENOENT;
1660 }
1661
1662 static int dl_init(struct dl *dl, int argc, char **argv)
1663 {
1664 int err;
1665
1666 dl->argc = argc;
1667 dl->argv = argv;
1668
1669 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
1670 if (!dl->nlg) {
1671 pr_err("Failed to connect to devlink Netlink\n");
1672 return -errno;
1673 }
1674
1675 err = ifname_map_init(dl);
1676 if (err) {
1677 pr_err("Failed to create index map\n");
1678 goto err_ifname_map_create;
1679 }
1680 return 0;
1681
1682 err_ifname_map_create:
1683 mnlg_socket_close(dl->nlg);
1684 return err;
1685 }
1686
1687 static void dl_fini(struct dl *dl)
1688 {
1689 ifname_map_fini(dl);
1690 mnlg_socket_close(dl->nlg);
1691 }
1692
1693 static struct dl *dl_alloc(void)
1694 {
1695 struct dl *dl;
1696
1697 dl = calloc(1, sizeof(*dl));
1698 if (!dl)
1699 return NULL;
1700 return dl;
1701 }
1702
1703 static void dl_free(struct dl *dl)
1704 {
1705 free(dl);
1706 }
1707
1708 int main(int argc, char **argv)
1709 {
1710 static const struct option long_options[] = {
1711 { "Version", no_argument, NULL, 'V' },
1712 { "no-nice-names", no_argument, NULL, 'n' },
1713 { NULL, 0, NULL, 0 }
1714 };
1715 struct dl *dl;
1716 int opt;
1717 int err;
1718 int ret;
1719
1720 dl = dl_alloc();
1721 if (!dl) {
1722 pr_err("Failed to allocate memory for devlink\n");
1723 return EXIT_FAILURE;
1724 }
1725
1726 while ((opt = getopt_long(argc, argv, "Vn",
1727 long_options, NULL)) >= 0) {
1728
1729 switch (opt) {
1730 case 'V':
1731 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
1732 return EXIT_SUCCESS;
1733 case 'n':
1734 dl->no_nice_names = true;
1735 break;
1736 default:
1737 pr_err("Unknown option.\n");
1738 help();
1739 return EXIT_FAILURE;
1740 }
1741 }
1742
1743 argc -= optind;
1744 argv += optind;
1745
1746 err = dl_init(dl, argc, argv);
1747 if (err) {
1748 ret = EXIT_FAILURE;
1749 goto dl_free;
1750 }
1751
1752 err = dl_cmd(dl);
1753 if (err) {
1754 ret = EXIT_FAILURE;
1755 goto dl_fini;
1756 }
1757
1758 ret = EXIT_SUCCESS;
1759
1760 dl_fini:
1761 dl_fini(dl);
1762 dl_free:
1763 dl_free(dl);
1764
1765 return ret;
1766 }