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