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