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