]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
a2e066441e8a6161ee015c2b38b9b2dda17abc40
[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 <signal.h>
23 #include <time.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <sys/sysinfo.h>
27 #define _LINUX_SYSINFO_H /* avoid collision with musl header */
28 #include <linux/genetlink.h>
29 #include <linux/devlink.h>
30 #include <linux/netlink.h>
31 #include <libmnl/libmnl.h>
32 #include <netinet/ether.h>
33 #include <sys/select.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
36 #include <sys/time.h>
37 #include <rt_names.h>
38
39 #include "version.h"
40 #include "list.h"
41 #include "mnlg.h"
42 #include "json_print.h"
43 #include "utils.h"
44 #include "namespace.h"
45
46 #define ESWITCH_MODE_LEGACY "legacy"
47 #define ESWITCH_MODE_SWITCHDEV "switchdev"
48 #define ESWITCH_INLINE_MODE_NONE "none"
49 #define ESWITCH_INLINE_MODE_LINK "link"
50 #define ESWITCH_INLINE_MODE_NETWORK "network"
51 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
52
53 #define ESWITCH_ENCAP_MODE_NONE "none"
54 #define ESWITCH_ENCAP_MODE_BASIC "basic"
55
56 #define PARAM_CMODE_RUNTIME_STR "runtime"
57 #define PARAM_CMODE_DRIVERINIT_STR "driverinit"
58 #define PARAM_CMODE_PERMANENT_STR "permanent"
59 #define DL_ARGS_REQUIRED_MAX_ERR_LEN 80
60
61 #define HEALTH_REPORTER_STATE_HEALTHY_STR "healthy"
62 #define HEALTH_REPORTER_STATE_ERROR_STR "error"
63 #define HEALTH_REPORTER_TIMESTAMP_FMT_LEN 80
64
65 static int g_new_line_count;
66 static int g_indent_level;
67 static bool g_indent_newline;
68
69 #define INDENT_STR_STEP 2
70 #define INDENT_STR_MAXLEN 32
71 static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
72
73 static void __attribute__((format(printf, 1, 2)))
74 pr_err(const char *fmt, ...)
75 {
76 va_list ap;
77
78 va_start(ap, fmt);
79 vfprintf(stderr, fmt, ap);
80 va_end(ap);
81 }
82
83 static void __attribute__((format(printf, 1, 2)))
84 pr_out(const char *fmt, ...)
85 {
86 va_list ap;
87
88 if (g_indent_newline) {
89 printf("%s", g_indent_str);
90 g_indent_newline = false;
91 }
92 va_start(ap, fmt);
93 vprintf(fmt, ap);
94 va_end(ap);
95 g_new_line_count = 0;
96 }
97
98 static void __attribute__((format(printf, 2, 3)))
99 pr_out_sp(unsigned int num, const char *fmt, ...)
100 {
101 va_list ap;
102 int ret;
103
104 va_start(ap, fmt);
105 ret = vprintf(fmt, ap);
106 va_end(ap);
107
108 if (ret < num)
109 printf("%*s", num - ret, "");
110 g_new_line_count = 0; \
111 }
112
113 static void __attribute__((format(printf, 1, 2)))
114 pr_out_tty(const char *fmt, ...)
115 {
116 va_list ap;
117
118 if (!isatty(STDOUT_FILENO))
119 return;
120 va_start(ap, fmt);
121 vprintf(fmt, ap);
122 va_end(ap);
123 }
124
125 static void __pr_out_indent_inc(void)
126 {
127 if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
128 return;
129 g_indent_level += INDENT_STR_STEP;
130 memset(g_indent_str, ' ', sizeof(g_indent_str));
131 g_indent_str[g_indent_level] = '\0';
132 }
133
134 static void __pr_out_indent_dec(void)
135 {
136 if (g_indent_level - INDENT_STR_STEP < 0)
137 return;
138 g_indent_level -= INDENT_STR_STEP;
139 g_indent_str[g_indent_level] = '\0';
140 }
141
142 static void __pr_out_newline(void)
143 {
144 if (g_new_line_count < 1) {
145 pr_out("\n");
146 g_indent_newline = true;
147 }
148 g_new_line_count++;
149 }
150
151 static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
152 mnl_cb_t data_cb, void *data)
153 {
154 int err;
155
156 err = mnlg_socket_recv_run(nlg, data_cb, data);
157 if (err < 0) {
158 pr_err("devlink answers: %s\n", strerror(errno));
159 return -errno;
160 }
161 return 0;
162 }
163
164 static void dummy_signal_handler(int signum)
165 {
166 }
167
168 static int _mnlg_socket_recv_run_intr(struct mnlg_socket *nlg,
169 mnl_cb_t data_cb, void *data)
170 {
171 struct sigaction act, oact;
172 int err;
173
174 act.sa_handler = dummy_signal_handler;
175 sigemptyset(&act.sa_mask);
176 act.sa_flags = SA_NODEFER;
177
178 sigaction(SIGINT, &act, &oact);
179 err = mnlg_socket_recv_run(nlg, data_cb, data);
180 sigaction(SIGINT, &oact, NULL);
181 if (err < 0 && errno != EINTR) {
182 pr_err("devlink answers: %s\n", strerror(errno));
183 return -errno;
184 }
185 return 0;
186 }
187
188 static int _mnlg_socket_send(struct mnlg_socket *nlg,
189 const struct nlmsghdr *nlh)
190 {
191 int err;
192
193 err = mnlg_socket_send(nlg, nlh);
194 if (err < 0) {
195 pr_err("Failed to call mnlg_socket_send\n");
196 return -errno;
197 }
198 return 0;
199 }
200
201 static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
202 const struct nlmsghdr *nlh,
203 mnl_cb_t data_cb, void *data)
204 {
205 int err;
206
207 err = _mnlg_socket_send(nlg, nlh);
208 if (err)
209 return err;
210 return _mnlg_socket_recv_run(nlg, data_cb, data);
211 }
212
213 static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
214 const char *group_name)
215 {
216 int err;
217
218 err = mnlg_socket_group_add(nlg, group_name);
219 if (err < 0) {
220 pr_err("Failed to call mnlg_socket_group_add\n");
221 return -errno;
222 }
223 return 0;
224 }
225
226 struct ifname_map {
227 struct list_head list;
228 char *bus_name;
229 char *dev_name;
230 uint32_t port_index;
231 char *ifname;
232 };
233
234 static struct ifname_map *ifname_map_alloc(const char *bus_name,
235 const char *dev_name,
236 uint32_t port_index,
237 const char *ifname)
238 {
239 struct ifname_map *ifname_map;
240
241 ifname_map = calloc(1, sizeof(*ifname_map));
242 if (!ifname_map)
243 return NULL;
244 ifname_map->bus_name = strdup(bus_name);
245 ifname_map->dev_name = strdup(dev_name);
246 ifname_map->port_index = port_index;
247 ifname_map->ifname = strdup(ifname);
248 if (!ifname_map->bus_name || !ifname_map->dev_name ||
249 !ifname_map->ifname) {
250 free(ifname_map->ifname);
251 free(ifname_map->dev_name);
252 free(ifname_map->bus_name);
253 free(ifname_map);
254 return NULL;
255 }
256 return ifname_map;
257 }
258
259 static void ifname_map_free(struct ifname_map *ifname_map)
260 {
261 free(ifname_map->ifname);
262 free(ifname_map->dev_name);
263 free(ifname_map->bus_name);
264 free(ifname_map);
265 }
266
267 #define DL_OPT_HANDLE BIT(0)
268 #define DL_OPT_HANDLEP BIT(1)
269 #define DL_OPT_PORT_TYPE BIT(2)
270 #define DL_OPT_PORT_COUNT BIT(3)
271 #define DL_OPT_SB BIT(4)
272 #define DL_OPT_SB_POOL BIT(5)
273 #define DL_OPT_SB_SIZE BIT(6)
274 #define DL_OPT_SB_TYPE BIT(7)
275 #define DL_OPT_SB_THTYPE BIT(8)
276 #define DL_OPT_SB_TH BIT(9)
277 #define DL_OPT_SB_TC BIT(10)
278 #define DL_OPT_ESWITCH_MODE BIT(11)
279 #define DL_OPT_ESWITCH_INLINE_MODE BIT(12)
280 #define DL_OPT_DPIPE_TABLE_NAME BIT(13)
281 #define DL_OPT_DPIPE_TABLE_COUNTERS BIT(14)
282 #define DL_OPT_ESWITCH_ENCAP_MODE BIT(15)
283 #define DL_OPT_RESOURCE_PATH BIT(16)
284 #define DL_OPT_RESOURCE_SIZE BIT(17)
285 #define DL_OPT_PARAM_NAME BIT(18)
286 #define DL_OPT_PARAM_VALUE BIT(19)
287 #define DL_OPT_PARAM_CMODE BIT(20)
288 #define DL_OPT_HANDLE_REGION BIT(21)
289 #define DL_OPT_REGION_SNAPSHOT_ID BIT(22)
290 #define DL_OPT_REGION_ADDRESS BIT(23)
291 #define DL_OPT_REGION_LENGTH BIT(24)
292 #define DL_OPT_FLASH_FILE_NAME BIT(25)
293 #define DL_OPT_FLASH_COMPONENT BIT(26)
294 #define DL_OPT_HEALTH_REPORTER_NAME BIT(27)
295 #define DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD BIT(28)
296 #define DL_OPT_HEALTH_REPORTER_AUTO_RECOVER BIT(29)
297 #define DL_OPT_TRAP_NAME BIT(30)
298 #define DL_OPT_TRAP_ACTION BIT(31)
299 #define DL_OPT_TRAP_GROUP_NAME BIT(32)
300 #define DL_OPT_NETNS BIT(33)
301 #define DL_OPT_TRAP_POLICER_ID BIT(34)
302 #define DL_OPT_TRAP_POLICER_RATE BIT(35)
303 #define DL_OPT_TRAP_POLICER_BURST BIT(36)
304 #define DL_OPT_HEALTH_REPORTER_AUTO_DUMP BIT(37)
305 #define DL_OPT_PORT_FUNCTION_HW_ADDR BIT(38)
306 #define DL_OPT_FLASH_OVERWRITE BIT(39)
307 #define DL_OPT_RELOAD_ACTION BIT(40)
308 #define DL_OPT_RELOAD_LIMIT BIT(41)
309
310 struct dl_opts {
311 uint64_t present; /* flags of present items */
312 char *bus_name;
313 char *dev_name;
314 uint32_t port_index;
315 enum devlink_port_type port_type;
316 uint32_t port_count;
317 uint32_t sb_index;
318 uint16_t sb_pool_index;
319 uint32_t sb_pool_size;
320 enum devlink_sb_pool_type sb_pool_type;
321 enum devlink_sb_threshold_type sb_pool_thtype;
322 uint32_t sb_threshold;
323 uint16_t sb_tc_index;
324 enum devlink_eswitch_mode eswitch_mode;
325 enum devlink_eswitch_inline_mode eswitch_inline_mode;
326 const char *dpipe_table_name;
327 bool dpipe_counters_enabled;
328 enum devlink_eswitch_encap_mode eswitch_encap_mode;
329 const char *resource_path;
330 uint64_t resource_size;
331 uint32_t resource_id;
332 bool resource_id_valid;
333 const char *param_name;
334 const char *param_value;
335 enum devlink_param_cmode cmode;
336 char *region_name;
337 uint32_t region_snapshot_id;
338 uint64_t region_address;
339 uint64_t region_length;
340 const char *flash_file_name;
341 const char *flash_component;
342 const char *reporter_name;
343 uint64_t reporter_graceful_period;
344 bool reporter_auto_recover;
345 bool reporter_auto_dump;
346 const char *trap_name;
347 const char *trap_group_name;
348 enum devlink_trap_action trap_action;
349 bool netns_is_pid;
350 uint32_t netns;
351 uint32_t trap_policer_id;
352 uint64_t trap_policer_rate;
353 uint64_t trap_policer_burst;
354 char port_function_hw_addr[MAX_ADDR_LEN];
355 uint32_t port_function_hw_addr_len;
356 uint32_t overwrite_mask;
357 enum devlink_reload_action reload_action;
358 enum devlink_reload_limit reload_limit;
359 };
360
361 struct dl {
362 struct mnlg_socket *nlg;
363 struct list_head ifname_map_list;
364 int argc;
365 char **argv;
366 bool no_nice_names;
367 struct dl_opts opts;
368 bool json_output;
369 bool pretty_output;
370 bool verbose;
371 bool stats;
372 struct {
373 bool present;
374 char *bus_name;
375 char *dev_name;
376 uint32_t port_index;
377 } arr_last;
378 };
379
380 static int dl_argc(struct dl *dl)
381 {
382 return dl->argc;
383 }
384
385 static char *dl_argv(struct dl *dl)
386 {
387 if (dl_argc(dl) == 0)
388 return NULL;
389 return *dl->argv;
390 }
391
392 static void dl_arg_inc(struct dl *dl)
393 {
394 if (dl_argc(dl) == 0)
395 return;
396 dl->argc--;
397 dl->argv++;
398 }
399
400 static void dl_arg_dec(struct dl *dl)
401 {
402 dl->argc++;
403 dl->argv--;
404 }
405
406 static char *dl_argv_next(struct dl *dl)
407 {
408 char *ret;
409
410 if (dl_argc(dl) == 0)
411 return NULL;
412
413 ret = *dl->argv;
414 dl_arg_inc(dl);
415 return ret;
416 }
417
418 static char *dl_argv_index(struct dl *dl, unsigned int index)
419 {
420 if (index >= dl_argc(dl))
421 return NULL;
422 return dl->argv[index];
423 }
424
425 static int strcmpx(const char *str1, const char *str2)
426 {
427 if (strlen(str1) > strlen(str2))
428 return -1;
429 return strncmp(str1, str2, strlen(str1));
430 }
431
432 static bool dl_argv_match(struct dl *dl, const char *pattern)
433 {
434 if (dl_argc(dl) == 0)
435 return false;
436 return strcmpx(dl_argv(dl), pattern) == 0;
437 }
438
439 static bool dl_no_arg(struct dl *dl)
440 {
441 return dl_argc(dl) == 0;
442 }
443
444 static void __pr_out_indent_newline(struct dl *dl)
445 {
446 if (!g_indent_newline && !dl->json_output)
447 pr_out(" ");
448 }
449
450 static bool is_binary_eol(int i)
451 {
452 return !(i%16);
453 }
454
455 static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len)
456 {
457 int i = 0;
458
459 while (i < len) {
460 if (dl->json_output)
461 print_int(PRINT_JSON, NULL, NULL, data[i]);
462 else
463 pr_out("%02x ", data[i]);
464 i++;
465 if (!dl->json_output && is_binary_eol(i))
466 __pr_out_newline();
467 }
468 if (!dl->json_output && !is_binary_eol(i))
469 __pr_out_newline();
470 }
471
472 static void pr_out_name(struct dl *dl, const char *name)
473 {
474 __pr_out_indent_newline(dl);
475 if (dl->json_output)
476 print_string(PRINT_JSON, name, NULL, NULL);
477 else
478 pr_out("%s:", name);
479 }
480
481 static void pr_out_u64(struct dl *dl, const char *name, uint64_t val)
482 {
483 __pr_out_indent_newline(dl);
484 if (val == (uint64_t) -1)
485 return print_string_name_value(name, "unlimited");
486
487 if (dl->json_output)
488 print_u64(PRINT_JSON, name, NULL, val);
489 else
490 pr_out("%s %"PRIu64, name, val);
491 }
492
493 static void pr_out_section_start(struct dl *dl, const char *name)
494 {
495 if (dl->json_output) {
496 open_json_object(NULL);
497 open_json_object(name);
498 }
499 }
500
501 static void pr_out_section_end(struct dl *dl)
502 {
503 if (dl->json_output) {
504 if (dl->arr_last.present)
505 close_json_array(PRINT_JSON, NULL);
506 close_json_object();
507 close_json_object();
508 }
509 }
510
511 static void pr_out_array_start(struct dl *dl, const char *name)
512 {
513 if (dl->json_output) {
514 open_json_array(PRINT_JSON, name);
515 } else {
516 __pr_out_indent_inc();
517 __pr_out_newline();
518 pr_out("%s:", name);
519 __pr_out_indent_inc();
520 __pr_out_newline();
521 }
522 }
523
524 static void pr_out_array_end(struct dl *dl)
525 {
526 if (dl->json_output) {
527 close_json_array(PRINT_JSON, NULL);
528 } else {
529 __pr_out_indent_dec();
530 __pr_out_indent_dec();
531 }
532 }
533
534 static void pr_out_object_start(struct dl *dl, const char *name)
535 {
536 if (dl->json_output) {
537 open_json_object(name);
538 } else {
539 __pr_out_indent_inc();
540 __pr_out_newline();
541 pr_out("%s:", name);
542 __pr_out_indent_inc();
543 __pr_out_newline();
544 }
545 }
546
547 static void pr_out_object_end(struct dl *dl)
548 {
549 if (dl->json_output) {
550 close_json_object();
551 } else {
552 __pr_out_indent_dec();
553 __pr_out_indent_dec();
554 }
555 }
556
557 static void pr_out_entry_start(struct dl *dl)
558 {
559 if (dl->json_output)
560 open_json_object(NULL);
561 }
562
563 static void pr_out_entry_end(struct dl *dl)
564 {
565 if (dl->json_output)
566 close_json_object();
567 else
568 __pr_out_newline();
569 }
570
571 static void check_indent_newline(struct dl *dl)
572 {
573 __pr_out_indent_newline(dl);
574
575 if (g_indent_newline && !is_json_context()) {
576 printf("%s", g_indent_str);
577 g_indent_newline = false;
578 }
579 g_new_line_count = 0;
580 }
581
582 static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
583 [DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
584 [DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
585 [DEVLINK_ATTR_PORT_INDEX] = MNL_TYPE_U32,
586 [DEVLINK_ATTR_PORT_TYPE] = MNL_TYPE_U16,
587 [DEVLINK_ATTR_PORT_DESIRED_TYPE] = MNL_TYPE_U16,
588 [DEVLINK_ATTR_PORT_NETDEV_IFINDEX] = MNL_TYPE_U32,
589 [DEVLINK_ATTR_PORT_NETDEV_NAME] = MNL_TYPE_NUL_STRING,
590 [DEVLINK_ATTR_PORT_IBDEV_NAME] = MNL_TYPE_NUL_STRING,
591 [DEVLINK_ATTR_PORT_LANES] = MNL_TYPE_U32,
592 [DEVLINK_ATTR_PORT_SPLITTABLE] = MNL_TYPE_U8,
593 [DEVLINK_ATTR_SB_INDEX] = MNL_TYPE_U32,
594 [DEVLINK_ATTR_SB_SIZE] = MNL_TYPE_U32,
595 [DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] = MNL_TYPE_U16,
596 [DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] = MNL_TYPE_U16,
597 [DEVLINK_ATTR_SB_INGRESS_TC_COUNT] = MNL_TYPE_U16,
598 [DEVLINK_ATTR_SB_EGRESS_TC_COUNT] = MNL_TYPE_U16,
599 [DEVLINK_ATTR_SB_POOL_INDEX] = MNL_TYPE_U16,
600 [DEVLINK_ATTR_SB_POOL_TYPE] = MNL_TYPE_U8,
601 [DEVLINK_ATTR_SB_POOL_SIZE] = MNL_TYPE_U32,
602 [DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = MNL_TYPE_U8,
603 [DEVLINK_ATTR_SB_THRESHOLD] = MNL_TYPE_U32,
604 [DEVLINK_ATTR_SB_TC_INDEX] = MNL_TYPE_U16,
605 [DEVLINK_ATTR_SB_OCC_CUR] = MNL_TYPE_U32,
606 [DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
607 [DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
608 [DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
609 [DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = MNL_TYPE_U8,
610 [DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED,
611 [DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED,
612 [DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING,
613 [DEVLINK_ATTR_DPIPE_TABLE_SIZE] = MNL_TYPE_U64,
614 [DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = MNL_TYPE_NESTED,
615 [DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = MNL_TYPE_NESTED,
616 [DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] = MNL_TYPE_U8,
617 [DEVLINK_ATTR_DPIPE_ENTRIES] = MNL_TYPE_NESTED,
618 [DEVLINK_ATTR_DPIPE_ENTRY] = MNL_TYPE_NESTED,
619 [DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = MNL_TYPE_U64,
620 [DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = MNL_TYPE_NESTED,
621 [DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = MNL_TYPE_NESTED,
622 [DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = MNL_TYPE_U64,
623 [DEVLINK_ATTR_DPIPE_MATCH] = MNL_TYPE_NESTED,
624 [DEVLINK_ATTR_DPIPE_MATCH_VALUE] = MNL_TYPE_NESTED,
625 [DEVLINK_ATTR_DPIPE_MATCH_TYPE] = MNL_TYPE_U32,
626 [DEVLINK_ATTR_DPIPE_ACTION] = MNL_TYPE_NESTED,
627 [DEVLINK_ATTR_DPIPE_ACTION_VALUE] = MNL_TYPE_NESTED,
628 [DEVLINK_ATTR_DPIPE_ACTION_TYPE] = MNL_TYPE_U32,
629 [DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = MNL_TYPE_U32,
630 [DEVLINK_ATTR_DPIPE_HEADERS] = MNL_TYPE_NESTED,
631 [DEVLINK_ATTR_DPIPE_HEADER] = MNL_TYPE_NESTED,
632 [DEVLINK_ATTR_DPIPE_HEADER_NAME] = MNL_TYPE_STRING,
633 [DEVLINK_ATTR_DPIPE_HEADER_ID] = MNL_TYPE_U32,
634 [DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = MNL_TYPE_NESTED,
635 [DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = MNL_TYPE_U8,
636 [DEVLINK_ATTR_DPIPE_HEADER_INDEX] = MNL_TYPE_U32,
637 [DEVLINK_ATTR_DPIPE_FIELD] = MNL_TYPE_NESTED,
638 [DEVLINK_ATTR_DPIPE_FIELD_NAME] = MNL_TYPE_STRING,
639 [DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
640 [DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
641 [DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
642 [DEVLINK_ATTR_PARAM] = MNL_TYPE_NESTED,
643 [DEVLINK_ATTR_PARAM_NAME] = MNL_TYPE_STRING,
644 [DEVLINK_ATTR_PARAM_TYPE] = MNL_TYPE_U8,
645 [DEVLINK_ATTR_PARAM_VALUES_LIST] = MNL_TYPE_NESTED,
646 [DEVLINK_ATTR_PARAM_VALUE] = MNL_TYPE_NESTED,
647 [DEVLINK_ATTR_PARAM_VALUE_CMODE] = MNL_TYPE_U8,
648 [DEVLINK_ATTR_REGION_NAME] = MNL_TYPE_STRING,
649 [DEVLINK_ATTR_REGION_SIZE] = MNL_TYPE_U64,
650 [DEVLINK_ATTR_REGION_SNAPSHOTS] = MNL_TYPE_NESTED,
651 [DEVLINK_ATTR_REGION_SNAPSHOT] = MNL_TYPE_NESTED,
652 [DEVLINK_ATTR_REGION_SNAPSHOT_ID] = MNL_TYPE_U32,
653 [DEVLINK_ATTR_REGION_CHUNKS] = MNL_TYPE_NESTED,
654 [DEVLINK_ATTR_REGION_CHUNK] = MNL_TYPE_NESTED,
655 [DEVLINK_ATTR_REGION_CHUNK_DATA] = MNL_TYPE_BINARY,
656 [DEVLINK_ATTR_REGION_CHUNK_ADDR] = MNL_TYPE_U64,
657 [DEVLINK_ATTR_REGION_CHUNK_LEN] = MNL_TYPE_U64,
658 [DEVLINK_ATTR_INFO_DRIVER_NAME] = MNL_TYPE_STRING,
659 [DEVLINK_ATTR_INFO_SERIAL_NUMBER] = MNL_TYPE_STRING,
660 [DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] = MNL_TYPE_STRING,
661 [DEVLINK_ATTR_INFO_VERSION_FIXED] = MNL_TYPE_NESTED,
662 [DEVLINK_ATTR_INFO_VERSION_RUNNING] = MNL_TYPE_NESTED,
663 [DEVLINK_ATTR_INFO_VERSION_STORED] = MNL_TYPE_NESTED,
664 [DEVLINK_ATTR_INFO_VERSION_NAME] = MNL_TYPE_STRING,
665 [DEVLINK_ATTR_INFO_VERSION_VALUE] = MNL_TYPE_STRING,
666 [DEVLINK_ATTR_HEALTH_REPORTER] = MNL_TYPE_NESTED,
667 [DEVLINK_ATTR_HEALTH_REPORTER_NAME] = MNL_TYPE_STRING,
668 [DEVLINK_ATTR_HEALTH_REPORTER_STATE] = MNL_TYPE_U8,
669 [DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] = MNL_TYPE_U64,
670 [DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] = MNL_TYPE_U64,
671 [DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS] = MNL_TYPE_U64,
672 [DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD] = MNL_TYPE_U64,
673 [DEVLINK_ATTR_FLASH_UPDATE_COMPONENT] = MNL_TYPE_STRING,
674 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG] = MNL_TYPE_STRING,
675 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE] = MNL_TYPE_U64,
676 [DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL] = MNL_TYPE_U64,
677 [DEVLINK_ATTR_STATS] = MNL_TYPE_NESTED,
678 [DEVLINK_ATTR_TRAP_NAME] = MNL_TYPE_STRING,
679 [DEVLINK_ATTR_TRAP_ACTION] = MNL_TYPE_U8,
680 [DEVLINK_ATTR_TRAP_TYPE] = MNL_TYPE_U8,
681 [DEVLINK_ATTR_TRAP_GENERIC] = MNL_TYPE_FLAG,
682 [DEVLINK_ATTR_TRAP_METADATA] = MNL_TYPE_NESTED,
683 [DEVLINK_ATTR_TRAP_GROUP_NAME] = MNL_TYPE_STRING,
684 [DEVLINK_ATTR_RELOAD_FAILED] = MNL_TYPE_U8,
685 [DEVLINK_ATTR_DEV_STATS] = MNL_TYPE_NESTED,
686 [DEVLINK_ATTR_RELOAD_STATS] = MNL_TYPE_NESTED,
687 [DEVLINK_ATTR_RELOAD_STATS_ENTRY] = MNL_TYPE_NESTED,
688 [DEVLINK_ATTR_RELOAD_ACTION] = MNL_TYPE_U8,
689 [DEVLINK_ATTR_RELOAD_STATS_LIMIT] = MNL_TYPE_U8,
690 [DEVLINK_ATTR_RELOAD_STATS_VALUE] = MNL_TYPE_U32,
691 [DEVLINK_ATTR_REMOTE_RELOAD_STATS] = MNL_TYPE_NESTED,
692 [DEVLINK_ATTR_RELOAD_ACTION_INFO] = MNL_TYPE_NESTED,
693 [DEVLINK_ATTR_RELOAD_ACTION_STATS] = MNL_TYPE_NESTED,
694 [DEVLINK_ATTR_TRAP_POLICER_ID] = MNL_TYPE_U32,
695 [DEVLINK_ATTR_TRAP_POLICER_RATE] = MNL_TYPE_U64,
696 [DEVLINK_ATTR_TRAP_POLICER_BURST] = MNL_TYPE_U64,
697 };
698
699 static const enum mnl_attr_data_type
700 devlink_stats_policy[DEVLINK_ATTR_STATS_MAX + 1] = {
701 [DEVLINK_ATTR_STATS_RX_PACKETS] = MNL_TYPE_U64,
702 [DEVLINK_ATTR_STATS_RX_BYTES] = MNL_TYPE_U64,
703 [DEVLINK_ATTR_STATS_RX_DROPPED] = MNL_TYPE_U64,
704 };
705
706 static int attr_cb(const struct nlattr *attr, void *data)
707 {
708 const struct nlattr **tb = data;
709 int type;
710
711 if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
712 return MNL_CB_OK;
713
714 type = mnl_attr_get_type(attr);
715 if (mnl_attr_validate(attr, devlink_policy[type]) < 0)
716 return MNL_CB_ERROR;
717
718 tb[type] = attr;
719 return MNL_CB_OK;
720 }
721
722 static int attr_stats_cb(const struct nlattr *attr, void *data)
723 {
724 const struct nlattr **tb = data;
725 int type;
726
727 /* Allow the tool to work on top of newer kernels that might contain
728 * more attributes.
729 */
730 if (mnl_attr_type_valid(attr, DEVLINK_ATTR_STATS_MAX) < 0)
731 return MNL_CB_OK;
732
733 type = mnl_attr_get_type(attr);
734 if (mnl_attr_validate(attr, devlink_stats_policy[type]) < 0)
735 return MNL_CB_ERROR;
736
737 tb[type] = attr;
738 return MNL_CB_OK;
739 }
740
741 static const enum mnl_attr_data_type
742 devlink_function_policy[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {
743 [DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR ] = MNL_TYPE_BINARY,
744 };
745
746 static int function_attr_cb(const struct nlattr *attr, void *data)
747 {
748 const struct nlattr **tb = data;
749 int type;
750
751 /* Allow the tool to work on top of newer kernels that might contain
752 * more attributes.
753 */
754 if (mnl_attr_type_valid(attr, DEVLINK_PORT_FUNCTION_ATTR_MAX) < 0)
755 return MNL_CB_OK;
756
757 type = mnl_attr_get_type(attr);
758 if (mnl_attr_validate(attr, devlink_function_policy[type]) < 0)
759 return MNL_CB_ERROR;
760
761 tb[type] = attr;
762 return MNL_CB_OK;
763 }
764
765 static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
766 {
767 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
768 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
769 struct dl *dl = data;
770 struct ifname_map *ifname_map;
771 const char *bus_name;
772 const char *dev_name;
773 uint32_t port_ifindex;
774 const char *port_ifname;
775
776 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
777 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
778 !tb[DEVLINK_ATTR_PORT_INDEX])
779 return MNL_CB_ERROR;
780
781 if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
782 return MNL_CB_OK;
783
784 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
785 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
786 port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
787 port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
788 ifname_map = ifname_map_alloc(bus_name, dev_name,
789 port_ifindex, port_ifname);
790 if (!ifname_map)
791 return MNL_CB_ERROR;
792 list_add(&ifname_map->list, &dl->ifname_map_list);
793
794 return MNL_CB_OK;
795 }
796
797 static void ifname_map_fini(struct dl *dl)
798 {
799 struct ifname_map *ifname_map, *tmp;
800
801 list_for_each_entry_safe(ifname_map, tmp,
802 &dl->ifname_map_list, list) {
803 list_del(&ifname_map->list);
804 ifname_map_free(ifname_map);
805 }
806 }
807
808 static int ifname_map_init(struct dl *dl)
809 {
810 struct nlmsghdr *nlh;
811 int err;
812
813 INIT_LIST_HEAD(&dl->ifname_map_list);
814
815 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
816 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
817
818 err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl);
819 if (err) {
820 ifname_map_fini(dl);
821 return err;
822 }
823 return 0;
824 }
825
826 static int ifname_map_lookup(struct dl *dl, const char *ifname,
827 char **p_bus_name, char **p_dev_name,
828 uint32_t *p_port_index)
829 {
830 struct ifname_map *ifname_map;
831
832 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
833 if (strcmp(ifname, ifname_map->ifname) == 0) {
834 *p_bus_name = ifname_map->bus_name;
835 *p_dev_name = ifname_map->dev_name;
836 *p_port_index = ifname_map->port_index;
837 return 0;
838 }
839 }
840 return -ENOENT;
841 }
842
843 static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name,
844 const char *dev_name, uint32_t port_index,
845 char **p_ifname)
846 {
847 struct ifname_map *ifname_map;
848
849 list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
850 if (strcmp(bus_name, ifname_map->bus_name) == 0 &&
851 strcmp(dev_name, ifname_map->dev_name) == 0 &&
852 port_index == ifname_map->port_index) {
853 *p_ifname = ifname_map->ifname;
854 return 0;
855 }
856 }
857 return -ENOENT;
858 }
859
860 static unsigned int strslashcount(char *str)
861 {
862 unsigned int count = 0;
863 char *pos = str;
864
865 while ((pos = strchr(pos, '/'))) {
866 count++;
867 pos++;
868 }
869 return count;
870 }
871
872 static int strslashrsplit(char *str, char **before, char **after)
873 {
874 char *slash;
875
876 slash = strrchr(str, '/');
877 if (!slash)
878 return -EINVAL;
879 *slash = '\0';
880 *before = str;
881 *after = slash + 1;
882 return 0;
883 }
884
885 static int strtouint64_t(const char *str, uint64_t *p_val)
886 {
887 char *endptr;
888 unsigned long long int val;
889
890 val = strtoull(str, &endptr, 10);
891 if (endptr == str || *endptr != '\0')
892 return -EINVAL;
893 if (val > ULONG_MAX)
894 return -ERANGE;
895 *p_val = val;
896 return 0;
897 }
898
899 static int strtouint32_t(const char *str, uint32_t *p_val)
900 {
901 char *endptr;
902 unsigned long int val;
903
904 val = strtoul(str, &endptr, 10);
905 if (endptr == str || *endptr != '\0')
906 return -EINVAL;
907 if (val > UINT_MAX)
908 return -ERANGE;
909 *p_val = val;
910 return 0;
911 }
912
913 static int strtouint16_t(const char *str, uint16_t *p_val)
914 {
915 char *endptr;
916 unsigned long int val;
917
918 val = strtoul(str, &endptr, 10);
919 if (endptr == str || *endptr != '\0')
920 return -EINVAL;
921 if (val > USHRT_MAX)
922 return -ERANGE;
923 *p_val = val;
924 return 0;
925 }
926
927 static int strtouint8_t(const char *str, uint8_t *p_val)
928 {
929 char *endptr;
930 unsigned long int val;
931
932 val = strtoul(str, &endptr, 10);
933 if (endptr == str || *endptr != '\0')
934 return -EINVAL;
935 if (val > UCHAR_MAX)
936 return -ERANGE;
937 *p_val = val;
938 return 0;
939 }
940
941 static int strtobool(const char *str, bool *p_val)
942 {
943 bool val;
944
945 if (!strcmp(str, "true") || !strcmp(str, "1") ||
946 !strcmp(str, "enable"))
947 val = true;
948 else if (!strcmp(str, "false") || !strcmp(str, "0") ||
949 !strcmp(str, "disable"))
950 val = false;
951 else
952 return -EINVAL;
953 *p_val = val;
954 return 0;
955 }
956
957 static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
958 {
959 strslashrsplit(str, p_bus_name, p_dev_name);
960 return 0;
961 }
962
963 static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
964 {
965 char *str = dl_argv_next(dl);
966
967 if (!str) {
968 pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
969 return -EINVAL;
970 }
971 if (strslashcount(str) != 1) {
972 pr_err("Wrong devlink identification string format.\n");
973 pr_err("Expected \"bus_name/dev_name\".\n");
974 return -EINVAL;
975 }
976 return __dl_argv_handle(str, p_bus_name, p_dev_name);
977 }
978
979 static int __dl_argv_handle_port(char *str,
980 char **p_bus_name, char **p_dev_name,
981 uint32_t *p_port_index)
982 {
983 char *handlestr;
984 char *portstr;
985 int err;
986
987 err = strslashrsplit(str, &handlestr, &portstr);
988 if (err) {
989 pr_err("Port identification \"%s\" is invalid\n", str);
990 return err;
991 }
992 err = strtouint32_t(portstr, p_port_index);
993 if (err) {
994 pr_err("Port index \"%s\" is not a number or not within range\n",
995 portstr);
996 return err;
997 }
998 err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
999 if (err) {
1000 pr_err("Port identification \"%s\" is invalid\n", str);
1001 return err;
1002 }
1003 return 0;
1004 }
1005
1006 static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
1007 char **p_bus_name, char **p_dev_name,
1008 uint32_t *p_port_index)
1009 {
1010 int err;
1011
1012 err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
1013 p_port_index);
1014 if (err) {
1015 pr_err("Netdevice \"%s\" not found\n", str);
1016 return err;
1017 }
1018 return 0;
1019 }
1020
1021 static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
1022 char **p_dev_name, uint32_t *p_port_index)
1023 {
1024 char *str = dl_argv_next(dl);
1025 unsigned int slash_count;
1026
1027 if (!str) {
1028 pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
1029 return -EINVAL;
1030 }
1031 slash_count = strslashcount(str);
1032 switch (slash_count) {
1033 case 0:
1034 return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
1035 p_dev_name, p_port_index);
1036 case 2:
1037 return __dl_argv_handle_port(str, p_bus_name,
1038 p_dev_name, p_port_index);
1039 default:
1040 pr_err("Wrong port identification string format.\n");
1041 pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1042 return -EINVAL;
1043 }
1044 }
1045
1046 static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
1047 char **p_dev_name, uint32_t *p_port_index,
1048 uint64_t *p_handle_bit)
1049 {
1050 char *str = dl_argv_next(dl);
1051 unsigned int slash_count;
1052 int err;
1053
1054 if (!str) {
1055 pr_err("One of following identifications expected:\n"
1056 "Devlink identification (\"bus_name/dev_name\")\n"
1057 "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
1058 return -EINVAL;
1059 }
1060 slash_count = strslashcount(str);
1061 if (slash_count == 1) {
1062 err = __dl_argv_handle(str, p_bus_name, p_dev_name);
1063 if (err)
1064 return err;
1065 *p_handle_bit = DL_OPT_HANDLE;
1066 } else if (slash_count == 2) {
1067 err = __dl_argv_handle_port(str, p_bus_name,
1068 p_dev_name, p_port_index);
1069 if (err)
1070 return err;
1071 *p_handle_bit = DL_OPT_HANDLEP;
1072 } else if (slash_count == 0) {
1073 err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
1074 p_dev_name, p_port_index);
1075 if (err)
1076 return err;
1077 *p_handle_bit = DL_OPT_HANDLEP;
1078 } else {
1079 pr_err("Wrong port identification string format.\n");
1080 pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
1081 return -EINVAL;
1082 }
1083 return 0;
1084 }
1085
1086 static int __dl_argv_handle_region(char *str, char **p_bus_name,
1087 char **p_dev_name, char **p_region)
1088 {
1089 char *handlestr;
1090 int err;
1091
1092 err = strslashrsplit(str, &handlestr, p_region);
1093 if (err) {
1094 pr_err("Region identification \"%s\" is invalid\n", str);
1095 return err;
1096 }
1097 err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
1098 if (err) {
1099 pr_err("Region identification \"%s\" is invalid\n", str);
1100 return err;
1101 }
1102 return 0;
1103 }
1104
1105 static int dl_argv_handle_region(struct dl *dl, char **p_bus_name,
1106 char **p_dev_name, char **p_region)
1107 {
1108 char *str = dl_argv_next(dl);
1109 unsigned int slash_count;
1110
1111 if (!str) {
1112 pr_err("Expected \"bus_name/dev_name/region\" identification.\n");
1113 return -EINVAL;
1114 }
1115
1116 slash_count = strslashcount(str);
1117 if (slash_count != 2) {
1118 pr_err("Wrong region identification string format.\n");
1119 pr_err("Expected \"bus_name/dev_name/region\" identification.\n"".\n");
1120 return -EINVAL;
1121 }
1122
1123 return __dl_argv_handle_region(str, p_bus_name, p_dev_name, p_region);
1124 }
1125
1126 static int dl_argv_uint64_t(struct dl *dl, uint64_t *p_val)
1127 {
1128 char *str = dl_argv_next(dl);
1129 int err;
1130
1131 if (!str) {
1132 pr_err("Unsigned number argument expected\n");
1133 return -EINVAL;
1134 }
1135
1136 err = strtouint64_t(str, p_val);
1137 if (err) {
1138 pr_err("\"%s\" is not a number or not within range\n", str);
1139 return err;
1140 }
1141 return 0;
1142 }
1143
1144 static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
1145 {
1146 char *str = dl_argv_next(dl);
1147 int err;
1148
1149 if (!str) {
1150 pr_err("Unsigned number argument expected\n");
1151 return -EINVAL;
1152 }
1153
1154 err = strtouint32_t(str, p_val);
1155 if (err) {
1156 pr_err("\"%s\" is not a number or not within range\n", str);
1157 return err;
1158 }
1159 return 0;
1160 }
1161
1162 static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val)
1163 {
1164 char *str = dl_argv_next(dl);
1165 int err;
1166
1167 if (!str) {
1168 pr_err("Unsigned number argument expected\n");
1169 return -EINVAL;
1170 }
1171
1172 err = strtouint16_t(str, p_val);
1173 if (err) {
1174 pr_err("\"%s\" is not a number or not within range\n", str);
1175 return err;
1176 }
1177 return 0;
1178 }
1179
1180 static int dl_argv_bool(struct dl *dl, bool *p_val)
1181 {
1182 char *str = dl_argv_next(dl);
1183 int err;
1184
1185 if (!str) {
1186 pr_err("Boolean argument expected\n");
1187 return -EINVAL;
1188 }
1189
1190 err = strtobool(str, p_val);
1191 if (err) {
1192 pr_err("\"%s\" is not a valid boolean value\n", str);
1193 return err;
1194 }
1195 return 0;
1196 }
1197
1198 static int dl_argv_str(struct dl *dl, const char **p_str)
1199 {
1200 const char *str = dl_argv_next(dl);
1201
1202 if (!str) {
1203 pr_err("String parameter expected\n");
1204 return -EINVAL;
1205 }
1206 *p_str = str;
1207 return 0;
1208 }
1209
1210 static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
1211 {
1212 if (strcmp(typestr, "auto") == 0) {
1213 *p_type = DEVLINK_PORT_TYPE_AUTO;
1214 } else if (strcmp(typestr, "eth") == 0) {
1215 *p_type = DEVLINK_PORT_TYPE_ETH;
1216 } else if (strcmp(typestr, "ib") == 0) {
1217 *p_type = DEVLINK_PORT_TYPE_IB;
1218 } else {
1219 pr_err("Unknown port type \"%s\"\n", typestr);
1220 return -EINVAL;
1221 }
1222 return 0;
1223 }
1224
1225 static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type)
1226 {
1227 if (strcmp(typestr, "ingress") == 0) {
1228 *p_type = DEVLINK_SB_POOL_TYPE_INGRESS;
1229 } else if (strcmp(typestr, "egress") == 0) {
1230 *p_type = DEVLINK_SB_POOL_TYPE_EGRESS;
1231 } else {
1232 pr_err("Unknown pool type \"%s\"\n", typestr);
1233 return -EINVAL;
1234 }
1235 return 0;
1236 }
1237
1238 static int threshold_type_get(const char *typestr,
1239 enum devlink_sb_threshold_type *p_type)
1240 {
1241 if (strcmp(typestr, "static") == 0) {
1242 *p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC;
1243 } else if (strcmp(typestr, "dynamic") == 0) {
1244 *p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC;
1245 } else {
1246 pr_err("Unknown threshold type \"%s\"\n", typestr);
1247 return -EINVAL;
1248 }
1249 return 0;
1250 }
1251
1252 static int eswitch_mode_get(const char *typestr,
1253 enum devlink_eswitch_mode *p_mode)
1254 {
1255 if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) {
1256 *p_mode = DEVLINK_ESWITCH_MODE_LEGACY;
1257 } else if (strcmp(typestr, ESWITCH_MODE_SWITCHDEV) == 0) {
1258 *p_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
1259 } else {
1260 pr_err("Unknown eswitch mode \"%s\"\n", typestr);
1261 return -EINVAL;
1262 }
1263 return 0;
1264 }
1265
1266 static int eswitch_inline_mode_get(const char *typestr,
1267 enum devlink_eswitch_inline_mode *p_mode)
1268 {
1269 if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) {
1270 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
1271 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) {
1272 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
1273 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) {
1274 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
1275 } else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) {
1276 *p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
1277 } else {
1278 pr_err("Unknown eswitch inline mode \"%s\"\n", typestr);
1279 return -EINVAL;
1280 }
1281 return 0;
1282 }
1283
1284 static int
1285 eswitch_encap_mode_get(const char *typestr,
1286 enum devlink_eswitch_encap_mode *p_encap_mode)
1287 {
1288 /* The initial implementation incorrectly accepted "enable"/"disable".
1289 * Carry it to maintain backward compatibility.
1290 */
1291 if (strcmp(typestr, "disable") == 0 ||
1292 strcmp(typestr, ESWITCH_ENCAP_MODE_NONE) == 0) {
1293 *p_encap_mode = DEVLINK_ESWITCH_ENCAP_MODE_NONE;
1294 } else if (strcmp(typestr, "enable") == 0 ||
1295 strcmp(typestr, ESWITCH_ENCAP_MODE_BASIC) == 0) {
1296 *p_encap_mode = DEVLINK_ESWITCH_ENCAP_MODE_BASIC;
1297 } else {
1298 pr_err("Unknown eswitch encap mode \"%s\"\n", typestr);
1299 return -EINVAL;
1300 }
1301 return 0;
1302 }
1303
1304 static int flash_overwrite_section_get(const char *sectionstr, uint32_t *mask)
1305 {
1306 if (strcmp(sectionstr, "settings") == 0) {
1307 *mask |= DEVLINK_FLASH_OVERWRITE_SETTINGS;
1308 } else if (strcmp(sectionstr, "identifiers") == 0) {
1309 *mask |= DEVLINK_FLASH_OVERWRITE_IDENTIFIERS;
1310 } else {
1311 pr_err("Unknown overwrite section \"%s\"\n", sectionstr);
1312 return -EINVAL;
1313 }
1314 return 0;
1315 }
1316
1317 static int param_cmode_get(const char *cmodestr,
1318 enum devlink_param_cmode *cmode)
1319 {
1320 if (strcmp(cmodestr, PARAM_CMODE_RUNTIME_STR) == 0) {
1321 *cmode = DEVLINK_PARAM_CMODE_RUNTIME;
1322 } else if (strcmp(cmodestr, PARAM_CMODE_DRIVERINIT_STR) == 0) {
1323 *cmode = DEVLINK_PARAM_CMODE_DRIVERINIT;
1324 } else if (strcmp(cmodestr, PARAM_CMODE_PERMANENT_STR) == 0) {
1325 *cmode = DEVLINK_PARAM_CMODE_PERMANENT;
1326 } else {
1327 pr_err("Unknown configuration mode \"%s\"\n", cmodestr);
1328 return -EINVAL;
1329 }
1330 return 0;
1331 }
1332
1333 static int trap_action_get(const char *actionstr,
1334 enum devlink_trap_action *p_action)
1335 {
1336 if (strcmp(actionstr, "drop") == 0) {
1337 *p_action = DEVLINK_TRAP_ACTION_DROP;
1338 } else if (strcmp(actionstr, "trap") == 0) {
1339 *p_action = DEVLINK_TRAP_ACTION_TRAP;
1340 } else if (strcmp(actionstr, "mirror") == 0) {
1341 *p_action = DEVLINK_TRAP_ACTION_MIRROR;
1342 } else {
1343 pr_err("Unknown trap action \"%s\"\n", actionstr);
1344 return -EINVAL;
1345 }
1346 return 0;
1347 }
1348
1349 static int hw_addr_parse(const char *addrstr, char *hw_addr, uint32_t *len)
1350 {
1351 int alen;
1352
1353 alen = ll_addr_a2n(hw_addr, MAX_ADDR_LEN, addrstr);
1354 if (alen < 0)
1355 return -EINVAL;
1356 *len = alen;
1357 return 0;
1358 }
1359
1360 static int reload_action_get(struct dl *dl, const char *actionstr,
1361 enum devlink_reload_action *action)
1362 {
1363 if (strcmp(actionstr, "driver_reinit") == 0) {
1364 *action = DEVLINK_RELOAD_ACTION_DRIVER_REINIT;
1365 } else if (strcmp(actionstr, "fw_activate") == 0) {
1366 *action = DEVLINK_RELOAD_ACTION_FW_ACTIVATE;
1367 } else {
1368 pr_err("Unknown reload action \"%s\"\n", actionstr);
1369 return -EINVAL;
1370 }
1371 return 0;
1372 }
1373
1374 static int reload_limit_get(struct dl *dl, const char *limitstr,
1375 enum devlink_reload_limit *limit)
1376 {
1377 if (strcmp(limitstr, "no_reset") == 0) {
1378 *limit = DEVLINK_RELOAD_LIMIT_NO_RESET;
1379 } else {
1380 pr_err("Unknown reload limit \"%s\"\n", limitstr);
1381 return -EINVAL;
1382 }
1383 return 0;
1384 }
1385
1386 struct dl_args_metadata {
1387 uint64_t o_flag;
1388 char err_msg[DL_ARGS_REQUIRED_MAX_ERR_LEN];
1389 };
1390
1391 static const struct dl_args_metadata dl_args_required[] = {
1392 {DL_OPT_PORT_TYPE, "Port type not set."},
1393 {DL_OPT_PORT_COUNT, "Port split count option expected."},
1394 {DL_OPT_SB_POOL, "Pool index option expected."},
1395 {DL_OPT_SB_SIZE, "Pool size option expected."},
1396 {DL_OPT_SB_TYPE, "Pool type option expected."},
1397 {DL_OPT_SB_THTYPE, "Pool threshold type option expected."},
1398 {DL_OPT_SB_TH, "Threshold option expected."},
1399 {DL_OPT_SB_TC, "TC index option expected."},
1400 {DL_OPT_ESWITCH_MODE, "E-Switch mode option expected."},
1401 {DL_OPT_ESWITCH_INLINE_MODE, "E-Switch inline-mode option expected."},
1402 {DL_OPT_DPIPE_TABLE_NAME, "Dpipe table name expected."},
1403 {DL_OPT_DPIPE_TABLE_COUNTERS, "Dpipe table counter state expected."},
1404 {DL_OPT_ESWITCH_ENCAP_MODE, "E-Switch encapsulation option expected."},
1405 {DL_OPT_RESOURCE_PATH, "Resource path expected."},
1406 {DL_OPT_RESOURCE_SIZE, "Resource size expected."},
1407 {DL_OPT_PARAM_NAME, "Parameter name expected."},
1408 {DL_OPT_PARAM_VALUE, "Value to set expected."},
1409 {DL_OPT_PARAM_CMODE, "Configuration mode expected."},
1410 {DL_OPT_REGION_SNAPSHOT_ID, "Region snapshot id expected."},
1411 {DL_OPT_REGION_ADDRESS, "Region address value expected."},
1412 {DL_OPT_REGION_LENGTH, "Region length value expected."},
1413 {DL_OPT_HEALTH_REPORTER_NAME, "Reporter's name is expected."},
1414 {DL_OPT_TRAP_NAME, "Trap's name is expected."},
1415 {DL_OPT_TRAP_GROUP_NAME, "Trap group's name is expected."},
1416 {DL_OPT_PORT_FUNCTION_HW_ADDR, "Port function's hardware address is expected."},
1417 };
1418
1419 static int dl_args_finding_required_validate(uint64_t o_required,
1420 uint64_t o_found)
1421 {
1422 uint64_t o_flag;
1423 int i;
1424
1425 for (i = 0; i < ARRAY_SIZE(dl_args_required); i++) {
1426 o_flag = dl_args_required[i].o_flag;
1427 if ((o_required & o_flag) && !(o_found & o_flag)) {
1428 pr_err("%s\n", dl_args_required[i].err_msg);
1429 return -EINVAL;
1430 }
1431 }
1432 if (o_required & ~o_found) {
1433 pr_err("BUG: unknown argument required but not found\n");
1434 return -EINVAL;
1435 }
1436 return 0;
1437 }
1438
1439 static int dl_argv_parse(struct dl *dl, uint64_t o_required,
1440 uint64_t o_optional)
1441 {
1442 struct dl_opts *opts = &dl->opts;
1443 uint64_t o_all = o_required | o_optional;
1444 uint64_t o_found = 0;
1445 int err;
1446
1447 if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
1448 uint64_t handle_bit;
1449
1450 err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
1451 &opts->port_index, &handle_bit);
1452 if (err)
1453 return err;
1454 o_required &= ~(DL_OPT_HANDLE | DL_OPT_HANDLEP) | handle_bit;
1455 o_found |= handle_bit;
1456 } else if (o_required & DL_OPT_HANDLE) {
1457 err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
1458 if (err)
1459 return err;
1460 o_found |= DL_OPT_HANDLE;
1461 } else if (o_required & DL_OPT_HANDLEP) {
1462 err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
1463 &opts->port_index);
1464 if (err)
1465 return err;
1466 o_found |= DL_OPT_HANDLEP;
1467 } else if (o_required & DL_OPT_HANDLE_REGION) {
1468 err = dl_argv_handle_region(dl, &opts->bus_name,
1469 &opts->dev_name,
1470 &opts->region_name);
1471 if (err)
1472 return err;
1473 o_found |= DL_OPT_HANDLE_REGION;
1474 }
1475
1476 while (dl_argc(dl)) {
1477 if (dl_argv_match(dl, "type") &&
1478 (o_all & DL_OPT_PORT_TYPE)) {
1479 const char *typestr;
1480
1481 dl_arg_inc(dl);
1482 err = dl_argv_str(dl, &typestr);
1483 if (err)
1484 return err;
1485 err = port_type_get(typestr, &opts->port_type);
1486 if (err)
1487 return err;
1488 o_found |= DL_OPT_PORT_TYPE;
1489 } else if (dl_argv_match(dl, "count") &&
1490 (o_all & DL_OPT_PORT_COUNT)) {
1491 dl_arg_inc(dl);
1492 err = dl_argv_uint32_t(dl, &opts->port_count);
1493 if (err)
1494 return err;
1495 o_found |= DL_OPT_PORT_COUNT;
1496 } else if (dl_argv_match(dl, "sb") &&
1497 (o_all & DL_OPT_SB)) {
1498 dl_arg_inc(dl);
1499 err = dl_argv_uint32_t(dl, &opts->sb_index);
1500 if (err)
1501 return err;
1502 o_found |= DL_OPT_SB;
1503 } else if (dl_argv_match(dl, "pool") &&
1504 (o_all & DL_OPT_SB_POOL)) {
1505 dl_arg_inc(dl);
1506 err = dl_argv_uint16_t(dl, &opts->sb_pool_index);
1507 if (err)
1508 return err;
1509 o_found |= DL_OPT_SB_POOL;
1510 } else if (dl_argv_match(dl, "size") &&
1511 (o_all & DL_OPT_SB_SIZE)) {
1512 dl_arg_inc(dl);
1513 err = dl_argv_uint32_t(dl, &opts->sb_pool_size);
1514 if (err)
1515 return err;
1516 o_found |= DL_OPT_SB_SIZE;
1517 } else if (dl_argv_match(dl, "type") &&
1518 (o_all & DL_OPT_SB_TYPE)) {
1519 const char *typestr;
1520
1521 dl_arg_inc(dl);
1522 err = dl_argv_str(dl, &typestr);
1523 if (err)
1524 return err;
1525 err = pool_type_get(typestr, &opts->sb_pool_type);
1526 if (err)
1527 return err;
1528 o_found |= DL_OPT_SB_TYPE;
1529 } else if (dl_argv_match(dl, "thtype") &&
1530 (o_all & DL_OPT_SB_THTYPE)) {
1531 const char *typestr;
1532
1533 dl_arg_inc(dl);
1534 err = dl_argv_str(dl, &typestr);
1535 if (err)
1536 return err;
1537 err = threshold_type_get(typestr,
1538 &opts->sb_pool_thtype);
1539 if (err)
1540 return err;
1541 o_found |= DL_OPT_SB_THTYPE;
1542 } else if (dl_argv_match(dl, "th") &&
1543 (o_all & DL_OPT_SB_TH)) {
1544 dl_arg_inc(dl);
1545 err = dl_argv_uint32_t(dl, &opts->sb_threshold);
1546 if (err)
1547 return err;
1548 o_found |= DL_OPT_SB_TH;
1549 } else if (dl_argv_match(dl, "tc") &&
1550 (o_all & DL_OPT_SB_TC)) {
1551 dl_arg_inc(dl);
1552 err = dl_argv_uint16_t(dl, &opts->sb_tc_index);
1553 if (err)
1554 return err;
1555 o_found |= DL_OPT_SB_TC;
1556 } else if (dl_argv_match(dl, "mode") &&
1557 (o_all & DL_OPT_ESWITCH_MODE)) {
1558 const char *typestr;
1559
1560 dl_arg_inc(dl);
1561 err = dl_argv_str(dl, &typestr);
1562 if (err)
1563 return err;
1564 err = eswitch_mode_get(typestr, &opts->eswitch_mode);
1565 if (err)
1566 return err;
1567 o_found |= DL_OPT_ESWITCH_MODE;
1568 } else if (dl_argv_match(dl, "inline-mode") &&
1569 (o_all & DL_OPT_ESWITCH_INLINE_MODE)) {
1570 const char *typestr;
1571
1572 dl_arg_inc(dl);
1573 err = dl_argv_str(dl, &typestr);
1574 if (err)
1575 return err;
1576 err = eswitch_inline_mode_get(
1577 typestr, &opts->eswitch_inline_mode);
1578 if (err)
1579 return err;
1580 o_found |= DL_OPT_ESWITCH_INLINE_MODE;
1581 } else if (dl_argv_match(dl, "name") &&
1582 (o_all & DL_OPT_DPIPE_TABLE_NAME)) {
1583 dl_arg_inc(dl);
1584 err = dl_argv_str(dl, &opts->dpipe_table_name);
1585 if (err)
1586 return err;
1587 o_found |= DL_OPT_DPIPE_TABLE_NAME;
1588 } else if ((dl_argv_match(dl, "counters") ||
1589 dl_argv_match(dl, "counters_enabled")) &&
1590 (o_all & DL_OPT_DPIPE_TABLE_COUNTERS)) {
1591 dl_arg_inc(dl);
1592 err = dl_argv_bool(dl, &opts->dpipe_counters_enabled);
1593 if (err)
1594 return err;
1595 o_found |= DL_OPT_DPIPE_TABLE_COUNTERS;
1596 } else if ((dl_argv_match(dl, "encap") || /* Original incorrect implementation */
1597 dl_argv_match(dl, "encap-mode")) &&
1598 (o_all & DL_OPT_ESWITCH_ENCAP_MODE)) {
1599 const char *typestr;
1600
1601 dl_arg_inc(dl);
1602 err = dl_argv_str(dl, &typestr);
1603 if (err)
1604 return err;
1605 err = eswitch_encap_mode_get(typestr,
1606 &opts->eswitch_encap_mode);
1607 if (err)
1608 return err;
1609 o_found |= DL_OPT_ESWITCH_ENCAP_MODE;
1610 } else if (dl_argv_match(dl, "path") &&
1611 (o_all & DL_OPT_RESOURCE_PATH)) {
1612 dl_arg_inc(dl);
1613 err = dl_argv_str(dl, &opts->resource_path);
1614 if (err)
1615 return err;
1616 o_found |= DL_OPT_RESOURCE_PATH;
1617 } else if (dl_argv_match(dl, "size") &&
1618 (o_all & DL_OPT_RESOURCE_SIZE)) {
1619 dl_arg_inc(dl);
1620 err = dl_argv_uint64_t(dl, &opts->resource_size);
1621 if (err)
1622 return err;
1623 o_found |= DL_OPT_RESOURCE_SIZE;
1624 } else if (dl_argv_match(dl, "name") &&
1625 (o_all & DL_OPT_PARAM_NAME)) {
1626 dl_arg_inc(dl);
1627 err = dl_argv_str(dl, &opts->param_name);
1628 if (err)
1629 return err;
1630 o_found |= DL_OPT_PARAM_NAME;
1631 } else if (dl_argv_match(dl, "value") &&
1632 (o_all & DL_OPT_PARAM_VALUE)) {
1633 dl_arg_inc(dl);
1634 err = dl_argv_str(dl, &opts->param_value);
1635 if (err)
1636 return err;
1637 o_found |= DL_OPT_PARAM_VALUE;
1638 } else if (dl_argv_match(dl, "cmode") &&
1639 (o_all & DL_OPT_PARAM_CMODE)) {
1640 const char *cmodestr;
1641
1642 dl_arg_inc(dl);
1643 err = dl_argv_str(dl, &cmodestr);
1644 if (err)
1645 return err;
1646 err = param_cmode_get(cmodestr, &opts->cmode);
1647 if (err)
1648 return err;
1649 o_found |= DL_OPT_PARAM_CMODE;
1650 } else if (dl_argv_match(dl, "snapshot") &&
1651 (o_all & DL_OPT_REGION_SNAPSHOT_ID)) {
1652 dl_arg_inc(dl);
1653 err = dl_argv_uint32_t(dl, &opts->region_snapshot_id);
1654 if (err)
1655 return err;
1656 o_found |= DL_OPT_REGION_SNAPSHOT_ID;
1657 } else if (dl_argv_match(dl, "address") &&
1658 (o_all & DL_OPT_REGION_ADDRESS)) {
1659 dl_arg_inc(dl);
1660 err = dl_argv_uint64_t(dl, &opts->region_address);
1661 if (err)
1662 return err;
1663 o_found |= DL_OPT_REGION_ADDRESS;
1664 } else if (dl_argv_match(dl, "length") &&
1665 (o_all & DL_OPT_REGION_LENGTH)) {
1666 dl_arg_inc(dl);
1667 err = dl_argv_uint64_t(dl, &opts->region_length);
1668 if (err)
1669 return err;
1670 o_found |= DL_OPT_REGION_LENGTH;
1671 } else if (dl_argv_match(dl, "file") &&
1672 (o_all & DL_OPT_FLASH_FILE_NAME)) {
1673 dl_arg_inc(dl);
1674 err = dl_argv_str(dl, &opts->flash_file_name);
1675 if (err)
1676 return err;
1677 o_found |= DL_OPT_FLASH_FILE_NAME;
1678 } else if (dl_argv_match(dl, "component") &&
1679 (o_all & DL_OPT_FLASH_COMPONENT)) {
1680 dl_arg_inc(dl);
1681 err = dl_argv_str(dl, &opts->flash_component);
1682 if (err)
1683 return err;
1684 o_found |= DL_OPT_FLASH_COMPONENT;
1685
1686 } else if (dl_argv_match(dl, "overwrite") &&
1687 (o_all & DL_OPT_FLASH_OVERWRITE)) {
1688 const char *sectionstr;
1689
1690 dl_arg_inc(dl);
1691 err = dl_argv_str(dl, &sectionstr);
1692 if(err)
1693 return err;
1694 err = flash_overwrite_section_get(sectionstr,
1695 &opts->overwrite_mask);
1696 if (err)
1697 return err;
1698 o_found |= DL_OPT_FLASH_OVERWRITE;
1699
1700 } else if (dl_argv_match(dl, "reporter") &&
1701 (o_all & DL_OPT_HEALTH_REPORTER_NAME)) {
1702 dl_arg_inc(dl);
1703 err = dl_argv_str(dl, &opts->reporter_name);
1704 if (err)
1705 return err;
1706 o_found |= DL_OPT_HEALTH_REPORTER_NAME;
1707 } else if (dl_argv_match(dl, "grace_period") &&
1708 (o_all & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)) {
1709 dl_arg_inc(dl);
1710 err = dl_argv_uint64_t(dl,
1711 &opts->reporter_graceful_period);
1712 if (err)
1713 return err;
1714 o_found |= DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD;
1715 } else if (dl_argv_match(dl, "auto_recover") &&
1716 (o_all & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)) {
1717 dl_arg_inc(dl);
1718 err = dl_argv_bool(dl, &opts->reporter_auto_recover);
1719 if (err)
1720 return err;
1721 o_found |= DL_OPT_HEALTH_REPORTER_AUTO_RECOVER;
1722 } else if (dl_argv_match(dl, "auto_dump") &&
1723 (o_all & DL_OPT_HEALTH_REPORTER_AUTO_DUMP)) {
1724 dl_arg_inc(dl);
1725 err = dl_argv_bool(dl, &opts->reporter_auto_dump);
1726 if (err)
1727 return err;
1728 o_found |= DL_OPT_HEALTH_REPORTER_AUTO_DUMP;
1729 } else if (dl_argv_match(dl, "trap") &&
1730 (o_all & DL_OPT_TRAP_NAME)) {
1731 dl_arg_inc(dl);
1732 err = dl_argv_str(dl, &opts->trap_name);
1733 if (err)
1734 return err;
1735 o_found |= DL_OPT_TRAP_NAME;
1736 } else if (dl_argv_match(dl, "group") &&
1737 (o_all & DL_OPT_TRAP_GROUP_NAME)) {
1738 dl_arg_inc(dl);
1739 err = dl_argv_str(dl, &opts->trap_group_name);
1740 if (err)
1741 return err;
1742 o_found |= DL_OPT_TRAP_GROUP_NAME;
1743 } else if (dl_argv_match(dl, "action") &&
1744 (o_all & DL_OPT_TRAP_ACTION)) {
1745 const char *actionstr;
1746
1747 dl_arg_inc(dl);
1748 err = dl_argv_str(dl, &actionstr);
1749 if (err)
1750 return err;
1751 err = trap_action_get(actionstr, &opts->trap_action);
1752 if (err)
1753 return err;
1754 o_found |= DL_OPT_TRAP_ACTION;
1755 } else if (dl_argv_match(dl, "netns") &&
1756 (o_all & DL_OPT_NETNS)) {
1757 const char *netns_str;
1758
1759 dl_arg_inc(dl);
1760 err = dl_argv_str(dl, &netns_str);
1761 if (err)
1762 return err;
1763 opts->netns = netns_get_fd(netns_str);
1764 if ((int)opts->netns < 0) {
1765 dl_arg_dec(dl);
1766 err = dl_argv_uint32_t(dl, &opts->netns);
1767 if (err)
1768 return err;
1769 opts->netns_is_pid = true;
1770 }
1771 o_found |= DL_OPT_NETNS;
1772 } else if (dl_argv_match(dl, "action") &&
1773 (o_all & DL_OPT_RELOAD_ACTION)) {
1774 const char *actionstr;
1775
1776 dl_arg_inc(dl);
1777 err = dl_argv_str(dl, &actionstr);
1778 if (err)
1779 return err;
1780 err = reload_action_get(dl, actionstr, &opts->reload_action);
1781 if (err)
1782 return err;
1783 o_found |= DL_OPT_RELOAD_ACTION;
1784 } else if (dl_argv_match(dl, "limit") &&
1785 (o_all & DL_OPT_RELOAD_LIMIT)) {
1786 const char *limitstr;
1787
1788 dl_arg_inc(dl);
1789 err = dl_argv_str(dl, &limitstr);
1790 if (err)
1791 return err;
1792 err = reload_limit_get(dl, limitstr, &opts->reload_limit);
1793 if (err)
1794 return err;
1795 o_found |= DL_OPT_RELOAD_LIMIT;
1796 } else if (dl_argv_match(dl, "policer") &&
1797 (o_all & DL_OPT_TRAP_POLICER_ID)) {
1798 dl_arg_inc(dl);
1799 err = dl_argv_uint32_t(dl, &opts->trap_policer_id);
1800 if (err)
1801 return err;
1802 o_found |= DL_OPT_TRAP_POLICER_ID;
1803 } else if (dl_argv_match(dl, "nopolicer") &&
1804 (o_all & DL_OPT_TRAP_POLICER_ID)) {
1805 dl_arg_inc(dl);
1806 opts->trap_policer_id = 0;
1807 o_found |= DL_OPT_TRAP_POLICER_ID;
1808 } else if (dl_argv_match(dl, "rate") &&
1809 (o_all & DL_OPT_TRAP_POLICER_RATE)) {
1810 dl_arg_inc(dl);
1811 err = dl_argv_uint64_t(dl, &opts->trap_policer_rate);
1812 if (err)
1813 return err;
1814 o_found |= DL_OPT_TRAP_POLICER_RATE;
1815 } else if (dl_argv_match(dl, "burst") &&
1816 (o_all & DL_OPT_TRAP_POLICER_BURST)) {
1817 dl_arg_inc(dl);
1818 err = dl_argv_uint64_t(dl, &opts->trap_policer_burst);
1819 if (err)
1820 return err;
1821 o_found |= DL_OPT_TRAP_POLICER_BURST;
1822 } else if (dl_argv_match(dl, "hw_addr") &&
1823 (o_all & DL_OPT_PORT_FUNCTION_HW_ADDR)) {
1824 const char *addrstr;
1825
1826 dl_arg_inc(dl);
1827 err = dl_argv_str(dl, &addrstr);
1828 if (err)
1829 return err;
1830 err = hw_addr_parse(addrstr, opts->port_function_hw_addr,
1831 &opts->port_function_hw_addr_len);
1832 if (err)
1833 return err;
1834 o_found |= DL_OPT_PORT_FUNCTION_HW_ADDR;
1835
1836 } else {
1837 pr_err("Unknown option \"%s\"\n", dl_argv(dl));
1838 return -EINVAL;
1839 }
1840 }
1841
1842 opts->present = o_found;
1843
1844 if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) {
1845 opts->sb_index = 0;
1846 opts->present |= DL_OPT_SB;
1847 }
1848
1849 return dl_args_finding_required_validate(o_required, o_found);
1850 }
1851
1852 static void
1853 dl_function_attr_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
1854 {
1855 struct nlattr *nest;
1856
1857 nest = mnl_attr_nest_start(nlh, DEVLINK_ATTR_PORT_FUNCTION);
1858 mnl_attr_put(nlh, DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR,
1859 opts->port_function_hw_addr_len,
1860 opts->port_function_hw_addr);
1861 mnl_attr_nest_end(nlh, nest);
1862 }
1863
1864 static void
1865 dl_flash_update_overwrite_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
1866 {
1867 struct nla_bitfield32 overwrite_mask;
1868
1869 overwrite_mask.selector = DEVLINK_SUPPORTED_FLASH_OVERWRITE_SECTIONS;
1870 overwrite_mask.value = opts->overwrite_mask;
1871
1872 mnl_attr_put(nlh, DEVLINK_ATTR_FLASH_UPDATE_OVERWRITE_MASK,
1873 sizeof(overwrite_mask), &overwrite_mask);
1874 }
1875
1876 static void
1877 dl_reload_limits_put(struct nlmsghdr *nlh, const struct dl_opts *opts)
1878 {
1879 struct nla_bitfield32 limits;
1880
1881 limits.selector = DEVLINK_RELOAD_LIMITS_VALID_MASK;
1882 limits.value = BIT(opts->reload_limit);
1883 mnl_attr_put(nlh, DEVLINK_ATTR_RELOAD_LIMITS, sizeof(limits), &limits);
1884 }
1885
1886 static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
1887 {
1888 struct dl_opts *opts = &dl->opts;
1889
1890 if (opts->present & DL_OPT_HANDLE) {
1891 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1892 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1893 } else if (opts->present & DL_OPT_HANDLEP) {
1894 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1895 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1896 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
1897 opts->port_index);
1898 } else if (opts->present & DL_OPT_HANDLE_REGION) {
1899 mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1900 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1901 mnl_attr_put_strz(nlh, DEVLINK_ATTR_REGION_NAME,
1902 opts->region_name);
1903 }
1904 if (opts->present & DL_OPT_PORT_TYPE)
1905 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
1906 opts->port_type);
1907 if (opts->present & DL_OPT_PORT_COUNT)
1908 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
1909 opts->port_count);
1910 if (opts->present & DL_OPT_SB)
1911 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX,
1912 opts->sb_index);
1913 if (opts->present & DL_OPT_SB_POOL)
1914 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX,
1915 opts->sb_pool_index);
1916 if (opts->present & DL_OPT_SB_SIZE)
1917 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE,
1918 opts->sb_pool_size);
1919 if (opts->present & DL_OPT_SB_TYPE)
1920 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE,
1921 opts->sb_pool_type);
1922 if (opts->present & DL_OPT_SB_THTYPE)
1923 mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1924 opts->sb_pool_thtype);
1925 if (opts->present & DL_OPT_SB_TH)
1926 mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD,
1927 opts->sb_threshold);
1928 if (opts->present & DL_OPT_SB_TC)
1929 mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX,
1930 opts->sb_tc_index);
1931 if (opts->present & DL_OPT_ESWITCH_MODE)
1932 mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
1933 opts->eswitch_mode);
1934 if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
1935 mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1936 opts->eswitch_inline_mode);
1937 if (opts->present & DL_OPT_DPIPE_TABLE_NAME)
1938 mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME,
1939 opts->dpipe_table_name);
1940 if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS)
1941 mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1942 opts->dpipe_counters_enabled);
1943 if (opts->present & DL_OPT_ESWITCH_ENCAP_MODE)
1944 mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE,
1945 opts->eswitch_encap_mode);
1946 if ((opts->present & DL_OPT_RESOURCE_PATH) && opts->resource_id_valid)
1947 mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_ID,
1948 opts->resource_id);
1949 if (opts->present & DL_OPT_RESOURCE_SIZE)
1950 mnl_attr_put_u64(nlh, DEVLINK_ATTR_RESOURCE_SIZE,
1951 opts->resource_size);
1952 if (opts->present & DL_OPT_PARAM_NAME)
1953 mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_NAME,
1954 opts->param_name);
1955 if (opts->present & DL_OPT_PARAM_CMODE)
1956 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_CMODE,
1957 opts->cmode);
1958 if (opts->present & DL_OPT_REGION_SNAPSHOT_ID)
1959 mnl_attr_put_u32(nlh, DEVLINK_ATTR_REGION_SNAPSHOT_ID,
1960 opts->region_snapshot_id);
1961 if (opts->present & DL_OPT_REGION_ADDRESS)
1962 mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_ADDR,
1963 opts->region_address);
1964 if (opts->present & DL_OPT_REGION_LENGTH)
1965 mnl_attr_put_u64(nlh, DEVLINK_ATTR_REGION_CHUNK_LEN,
1966 opts->region_length);
1967 if (opts->present & DL_OPT_FLASH_FILE_NAME)
1968 mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_FILE_NAME,
1969 opts->flash_file_name);
1970 if (opts->present & DL_OPT_FLASH_COMPONENT)
1971 mnl_attr_put_strz(nlh, DEVLINK_ATTR_FLASH_UPDATE_COMPONENT,
1972 opts->flash_component);
1973 if (opts->present & DL_OPT_FLASH_OVERWRITE)
1974 dl_flash_update_overwrite_put(nlh, opts);
1975 if (opts->present & DL_OPT_HEALTH_REPORTER_NAME)
1976 mnl_attr_put_strz(nlh, DEVLINK_ATTR_HEALTH_REPORTER_NAME,
1977 opts->reporter_name);
1978 if (opts->present & DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD)
1979 mnl_attr_put_u64(nlh,
1980 DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD,
1981 opts->reporter_graceful_period);
1982 if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_RECOVER)
1983 mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER,
1984 opts->reporter_auto_recover);
1985 if (opts->present & DL_OPT_HEALTH_REPORTER_AUTO_DUMP)
1986 mnl_attr_put_u8(nlh, DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP,
1987 opts->reporter_auto_dump);
1988 if (opts->present & DL_OPT_TRAP_NAME)
1989 mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_NAME,
1990 opts->trap_name);
1991 if (opts->present & DL_OPT_TRAP_GROUP_NAME)
1992 mnl_attr_put_strz(nlh, DEVLINK_ATTR_TRAP_GROUP_NAME,
1993 opts->trap_group_name);
1994 if (opts->present & DL_OPT_TRAP_ACTION)
1995 mnl_attr_put_u8(nlh, DEVLINK_ATTR_TRAP_ACTION,
1996 opts->trap_action);
1997 if (opts->present & DL_OPT_NETNS)
1998 mnl_attr_put_u32(nlh,
1999 opts->netns_is_pid ? DEVLINK_ATTR_NETNS_PID :
2000 DEVLINK_ATTR_NETNS_FD,
2001 opts->netns);
2002 if (opts->present & DL_OPT_RELOAD_ACTION)
2003 mnl_attr_put_u8(nlh, DEVLINK_ATTR_RELOAD_ACTION,
2004 opts->reload_action);
2005 if (opts->present & DL_OPT_RELOAD_LIMIT)
2006 dl_reload_limits_put(nlh, opts);
2007 if (opts->present & DL_OPT_TRAP_POLICER_ID)
2008 mnl_attr_put_u32(nlh, DEVLINK_ATTR_TRAP_POLICER_ID,
2009 opts->trap_policer_id);
2010 if (opts->present & DL_OPT_TRAP_POLICER_RATE)
2011 mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_RATE,
2012 opts->trap_policer_rate);
2013 if (opts->present & DL_OPT_TRAP_POLICER_BURST)
2014 mnl_attr_put_u64(nlh, DEVLINK_ATTR_TRAP_POLICER_BURST,
2015 opts->trap_policer_burst);
2016 if (opts->present & DL_OPT_PORT_FUNCTION_HW_ADDR)
2017 dl_function_attr_put(nlh, opts);
2018 }
2019
2020 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
2021 uint64_t o_required, uint64_t o_optional)
2022 {
2023 int err;
2024
2025 err = dl_argv_parse(dl, o_required, o_optional);
2026 if (err)
2027 return err;
2028 dl_opts_put(nlh, dl);
2029 return 0;
2030 }
2031
2032 static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
2033 {
2034 struct dl_opts *opts = &dl->opts;
2035 struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME];
2036 struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME];
2037 struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX];
2038 struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX];
2039
2040 if (opts->present & DL_OPT_HANDLE &&
2041 attr_bus_name && attr_dev_name) {
2042 const char *bus_name = mnl_attr_get_str(attr_bus_name);
2043 const char *dev_name = mnl_attr_get_str(attr_dev_name);
2044
2045 if (strcmp(bus_name, opts->bus_name) != 0 ||
2046 strcmp(dev_name, opts->dev_name) != 0)
2047 return false;
2048 }
2049 if (opts->present & DL_OPT_HANDLEP &&
2050 attr_bus_name && attr_dev_name && attr_port_index) {
2051 const char *bus_name = mnl_attr_get_str(attr_bus_name);
2052 const char *dev_name = mnl_attr_get_str(attr_dev_name);
2053 uint32_t port_index = mnl_attr_get_u32(attr_port_index);
2054
2055 if (strcmp(bus_name, opts->bus_name) != 0 ||
2056 strcmp(dev_name, opts->dev_name) != 0 ||
2057 port_index != opts->port_index)
2058 return false;
2059 }
2060 if (opts->present & DL_OPT_SB && attr_sb_index) {
2061 uint32_t sb_index = mnl_attr_get_u32(attr_sb_index);
2062
2063 if (sb_index != opts->sb_index)
2064 return false;
2065 }
2066 return true;
2067 }
2068
2069 static void cmd_dev_help(void)
2070 {
2071 pr_err("Usage: devlink dev show [ DEV ]\n");
2072 pr_err(" devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
2073 pr_err(" [ inline-mode { none | link | network | transport } ]\n");
2074 pr_err(" [ encap-mode { none | basic } ]\n");
2075 pr_err(" devlink dev eswitch show DEV\n");
2076 pr_err(" devlink dev param set DEV name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
2077 pr_err(" devlink dev param show [DEV name PARAMETER]\n");
2078 pr_err(" devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
2079 pr_err(" [ action { driver_reinit | fw_activate } ] [ limit no_reset ]\n");
2080 pr_err(" devlink dev info [ DEV ]\n");
2081 pr_err(" devlink dev flash DEV file PATH [ component NAME ] [ overwrite SECTION ]\n");
2082 }
2083
2084 static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
2085 const char *dev_name)
2086 {
2087 if (!dl->arr_last.present)
2088 return false;
2089 return strcmp(dl->arr_last.bus_name, bus_name) == 0 &&
2090 strcmp(dl->arr_last.dev_name, dev_name) == 0;
2091 }
2092
2093 static void arr_last_handle_set(struct dl *dl, const char *bus_name,
2094 const char *dev_name)
2095 {
2096 dl->arr_last.present = true;
2097 free(dl->arr_last.dev_name);
2098 free(dl->arr_last.bus_name);
2099 dl->arr_last.bus_name = strdup(bus_name);
2100 dl->arr_last.dev_name = strdup(dev_name);
2101 }
2102
2103 static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name,
2104 const char *dev_name)
2105 {
2106 return !cmp_arr_last_handle(dl, bus_name, dev_name);
2107 }
2108
2109 static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name,
2110 const char *dev_name)
2111 {
2112 return dl->arr_last.present &&
2113 !cmp_arr_last_handle(dl, bus_name, dev_name);
2114 }
2115
2116 static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb,
2117 bool content, bool array)
2118 {
2119 const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2120 const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2121 char buf[64];
2122
2123 sprintf(buf, "%s/%s", bus_name, dev_name);
2124
2125 if (dl->json_output) {
2126 if (array) {
2127 if (should_arr_last_handle_end(dl, bus_name, dev_name))
2128 close_json_array(PRINT_JSON, NULL);
2129 if (should_arr_last_handle_start(dl, bus_name,
2130 dev_name)) {
2131 open_json_array(PRINT_JSON, buf);
2132 open_json_object(NULL);
2133 arr_last_handle_set(dl, bus_name, dev_name);
2134 } else {
2135 open_json_object(NULL);
2136 }
2137 } else {
2138 open_json_object(buf);
2139 }
2140 } else {
2141 if (array) {
2142 if (should_arr_last_handle_end(dl, bus_name, dev_name))
2143 __pr_out_indent_dec();
2144 if (should_arr_last_handle_start(dl, bus_name,
2145 dev_name)) {
2146 pr_out("%s%s", buf, content ? ":" : "");
2147 __pr_out_newline();
2148 __pr_out_indent_inc();
2149 arr_last_handle_set(dl, bus_name, dev_name);
2150 }
2151 } else {
2152 pr_out("%s%s", buf, content ? ":" : "");
2153 }
2154 }
2155 }
2156
2157 static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb)
2158 {
2159 __pr_out_handle_start(dl, tb, true, true);
2160 }
2161
2162 static void pr_out_handle_end(struct dl *dl)
2163 {
2164 if (dl->json_output)
2165 close_json_object();
2166 else
2167 __pr_out_newline();
2168 }
2169
2170 static void pr_out_handle(struct dl *dl, struct nlattr **tb)
2171 {
2172 __pr_out_handle_start(dl, tb, false, false);
2173 pr_out_handle_end(dl);
2174 }
2175
2176 static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name,
2177 const char *dev_name, uint32_t port_index)
2178 {
2179 return cmp_arr_last_handle(dl, bus_name, dev_name) &&
2180 dl->arr_last.port_index == port_index;
2181 }
2182
2183 static void arr_last_port_handle_set(struct dl *dl, const char *bus_name,
2184 const char *dev_name, uint32_t port_index)
2185 {
2186 arr_last_handle_set(dl, bus_name, dev_name);
2187 dl->arr_last.port_index = port_index;
2188 }
2189
2190 static bool should_arr_last_port_handle_start(struct dl *dl,
2191 const char *bus_name,
2192 const char *dev_name,
2193 uint32_t port_index)
2194 {
2195 return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
2196 }
2197
2198 static bool should_arr_last_port_handle_end(struct dl *dl,
2199 const char *bus_name,
2200 const char *dev_name,
2201 uint32_t port_index)
2202 {
2203 return dl->arr_last.present &&
2204 !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
2205 }
2206
2207 static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name,
2208 const char *dev_name,
2209 uint32_t port_index, bool try_nice,
2210 bool array)
2211 {
2212 static char buf[64];
2213 char *ifname = NULL;
2214
2215 if (dl->no_nice_names || !try_nice ||
2216 ifname_map_rev_lookup(dl, bus_name, dev_name,
2217 port_index, &ifname) != 0)
2218 sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index);
2219 else
2220 sprintf(buf, "%s", ifname);
2221
2222 if (dl->json_output) {
2223 if (array) {
2224 if (should_arr_last_port_handle_end(dl, bus_name,
2225 dev_name,
2226 port_index))
2227 close_json_array(PRINT_JSON, NULL);
2228 if (should_arr_last_port_handle_start(dl, bus_name,
2229 dev_name,
2230 port_index)) {
2231 open_json_array(PRINT_JSON, buf);
2232 open_json_object(NULL);
2233 arr_last_port_handle_set(dl, bus_name, dev_name,
2234 port_index);
2235 } else {
2236 open_json_object(NULL);
2237 }
2238 } else {
2239 open_json_object(buf);
2240 }
2241 } else {
2242 if (array) {
2243 if (should_arr_last_port_handle_end(dl, bus_name, dev_name, port_index))
2244 __pr_out_indent_dec();
2245 if (should_arr_last_port_handle_start(dl, bus_name,
2246 dev_name, port_index)) {
2247 pr_out("%s:", buf);
2248 __pr_out_newline();
2249 __pr_out_indent_inc();
2250 arr_last_port_handle_set(dl, bus_name, dev_name, port_index);
2251 }
2252 } else {
2253 pr_out("%s:", buf);
2254 }
2255 }
2256 }
2257
2258 static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
2259 {
2260 const char *bus_name;
2261 const char *dev_name;
2262 uint32_t port_index;
2263
2264 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2265 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2266 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2267 __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false);
2268 }
2269
2270 static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice)
2271 {
2272 const char *bus_name;
2273 const char *dev_name;
2274 uint32_t port_index;
2275
2276 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2277 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2278 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2279 __pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true);
2280 }
2281
2282 static void pr_out_port_handle_end(struct dl *dl)
2283 {
2284 if (dl->json_output)
2285 close_json_object();
2286 else
2287 pr_out("\n");
2288 }
2289
2290 static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr)
2291 {
2292 if (dl->json_output) {
2293 print_uint(PRINT_JSON, "address", NULL, addr);
2294 open_json_array(PRINT_JSON, "data");
2295 }
2296 }
2297
2298 static void pr_out_region_chunk_end(struct dl *dl)
2299 {
2300 if (dl->json_output)
2301 close_json_array(PRINT_JSON, NULL);
2302 }
2303
2304 static void pr_out_region_chunk(struct dl *dl, uint8_t *data, uint32_t len,
2305 uint64_t addr)
2306 {
2307 static uint64_t align_val;
2308 uint32_t i = 0;
2309
2310 pr_out_region_chunk_start(dl, addr);
2311 while (i < len) {
2312 if (!dl->json_output)
2313 if (!(align_val % 16))
2314 pr_out("%s%016"PRIx64" ",
2315 align_val ? "\n" : "",
2316 addr);
2317
2318 align_val++;
2319
2320 if (dl->json_output)
2321 print_int(PRINT_JSON, NULL, NULL, data[i]);
2322 else
2323 pr_out("%02x ", data[i]);
2324
2325 addr++;
2326 i++;
2327 }
2328 pr_out_region_chunk_end(dl);
2329 }
2330
2331 static void pr_out_stats(struct dl *dl, struct nlattr *nla_stats)
2332 {
2333 struct nlattr *tb[DEVLINK_ATTR_STATS_MAX + 1] = {};
2334 int err;
2335
2336 if (!dl->stats)
2337 return;
2338
2339 err = mnl_attr_parse_nested(nla_stats, attr_stats_cb, tb);
2340 if (err != MNL_CB_OK)
2341 return;
2342
2343 pr_out_object_start(dl, "stats");
2344 pr_out_object_start(dl, "rx");
2345 if (tb[DEVLINK_ATTR_STATS_RX_BYTES])
2346 pr_out_u64(dl, "bytes",
2347 mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_BYTES]));
2348 if (tb[DEVLINK_ATTR_STATS_RX_PACKETS])
2349 pr_out_u64(dl, "packets",
2350 mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_PACKETS]));
2351 if (tb[DEVLINK_ATTR_STATS_RX_DROPPED])
2352 pr_out_u64(dl, "dropped",
2353 mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_DROPPED]));
2354 pr_out_object_end(dl);
2355 pr_out_object_end(dl);
2356 }
2357
2358 static const char *param_cmode_name(uint8_t cmode)
2359 {
2360 switch (cmode) {
2361 case DEVLINK_PARAM_CMODE_RUNTIME:
2362 return PARAM_CMODE_RUNTIME_STR;
2363 case DEVLINK_PARAM_CMODE_DRIVERINIT:
2364 return PARAM_CMODE_DRIVERINIT_STR;
2365 case DEVLINK_PARAM_CMODE_PERMANENT:
2366 return PARAM_CMODE_PERMANENT_STR;
2367 default: return "<unknown type>";
2368 }
2369 }
2370
2371 static const char *reload_action_name(uint8_t reload_action)
2372 {
2373 switch (reload_action) {
2374 case DEVLINK_RELOAD_ACTION_DRIVER_REINIT:
2375 return "driver_reinit";
2376 case DEVLINK_RELOAD_ACTION_FW_ACTIVATE:
2377 return "fw_activate";
2378 default:
2379 return "<unknown reload action>";
2380 }
2381 }
2382
2383 static const char *reload_limit_name(uint8_t reload_limit)
2384 {
2385 switch (reload_limit) {
2386 case DEVLINK_RELOAD_LIMIT_UNSPEC:
2387 return "unspecified";
2388 case DEVLINK_RELOAD_LIMIT_NO_RESET:
2389 return "no_reset";
2390 default:
2391 return "<unknown reload action>";
2392 }
2393 }
2394
2395 static const char *eswitch_mode_name(uint32_t mode)
2396 {
2397 switch (mode) {
2398 case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY;
2399 case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV;
2400 default: return "<unknown mode>";
2401 }
2402 }
2403
2404 static const char *eswitch_inline_mode_name(uint32_t mode)
2405 {
2406 switch (mode) {
2407 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
2408 return ESWITCH_INLINE_MODE_NONE;
2409 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
2410 return ESWITCH_INLINE_MODE_LINK;
2411 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
2412 return ESWITCH_INLINE_MODE_NETWORK;
2413 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
2414 return ESWITCH_INLINE_MODE_TRANSPORT;
2415 default:
2416 return "<unknown mode>";
2417 }
2418 }
2419
2420 static const char *eswitch_encap_mode_name(uint32_t mode)
2421 {
2422 switch (mode) {
2423 case DEVLINK_ESWITCH_ENCAP_MODE_NONE:
2424 return ESWITCH_ENCAP_MODE_NONE;
2425 case DEVLINK_ESWITCH_ENCAP_MODE_BASIC:
2426 return ESWITCH_ENCAP_MODE_BASIC;
2427 default:
2428 return "<unknown mode>";
2429 }
2430 }
2431
2432 static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
2433 {
2434 __pr_out_handle_start(dl, tb, true, false);
2435
2436 if (tb[DEVLINK_ATTR_ESWITCH_MODE]) {
2437 check_indent_newline(dl);
2438 print_string(PRINT_ANY, "mode", "mode %s",
2439 eswitch_mode_name(mnl_attr_get_u16(
2440 tb[DEVLINK_ATTR_ESWITCH_MODE])));
2441 }
2442 if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
2443 check_indent_newline(dl);
2444 print_string(PRINT_ANY, "inline-mode", "inline-mode %s",
2445 eswitch_inline_mode_name(mnl_attr_get_u8(
2446 tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
2447 }
2448 if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
2449 check_indent_newline(dl);
2450 print_string(PRINT_ANY, "encap-mode", "encap-mode %s",
2451 eswitch_encap_mode_name(mnl_attr_get_u8(
2452 tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE])));
2453 }
2454
2455 pr_out_handle_end(dl);
2456 }
2457
2458 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data)
2459 {
2460 struct dl *dl = data;
2461 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2462 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2463
2464 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2465 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2466 return MNL_CB_ERROR;
2467 pr_out_eswitch(dl, tb);
2468 return MNL_CB_OK;
2469 }
2470
2471 static int cmd_dev_eswitch_show(struct dl *dl)
2472 {
2473 struct nlmsghdr *nlh;
2474 int err;
2475
2476 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_GET,
2477 NLM_F_REQUEST | NLM_F_ACK);
2478
2479 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2480 if (err)
2481 return err;
2482
2483 pr_out_section_start(dl, "dev");
2484 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl);
2485 pr_out_section_end(dl);
2486 return err;
2487 }
2488
2489 static int cmd_dev_eswitch_set(struct dl *dl)
2490 {
2491 struct nlmsghdr *nlh;
2492 int err;
2493
2494 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_SET,
2495 NLM_F_REQUEST | NLM_F_ACK);
2496
2497 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
2498 DL_OPT_ESWITCH_MODE |
2499 DL_OPT_ESWITCH_INLINE_MODE |
2500 DL_OPT_ESWITCH_ENCAP_MODE);
2501
2502 if (err)
2503 return err;
2504
2505 if (dl->opts.present == 1) {
2506 pr_err("Need to set at least one option\n");
2507 return -ENOENT;
2508 }
2509
2510 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2511 }
2512
2513 static int cmd_dev_eswitch(struct dl *dl)
2514 {
2515 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2516 cmd_dev_help();
2517 return 0;
2518 } else if (dl_argv_match(dl, "set")) {
2519 dl_arg_inc(dl);
2520 return cmd_dev_eswitch_set(dl);
2521 } else if (dl_argv_match(dl, "show")) {
2522 dl_arg_inc(dl);
2523 return cmd_dev_eswitch_show(dl);
2524 }
2525 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2526 return -ENOENT;
2527 }
2528
2529 struct param_val_conv {
2530 const char *name;
2531 const char *vstr;
2532 uint32_t vuint;
2533 };
2534
2535 static bool param_val_conv_exists(const struct param_val_conv *param_val_conv,
2536 uint32_t len, const char *name)
2537 {
2538 uint32_t i;
2539
2540 for (i = 0; i < len; i++)
2541 if (!strcmp(param_val_conv[i].name, name))
2542 return true;
2543
2544 return false;
2545 }
2546
2547 static int
2548 param_val_conv_uint_get(const struct param_val_conv *param_val_conv,
2549 uint32_t len, const char *name, const char *vstr,
2550 uint32_t *vuint)
2551 {
2552 uint32_t i;
2553
2554 for (i = 0; i < len; i++)
2555 if (!strcmp(param_val_conv[i].name, name) &&
2556 !strcmp(param_val_conv[i].vstr, vstr)) {
2557 *vuint = param_val_conv[i].vuint;
2558 return 0;
2559 }
2560
2561 return -ENOENT;
2562 }
2563
2564 static int
2565 param_val_conv_str_get(const struct param_val_conv *param_val_conv,
2566 uint32_t len, const char *name, uint32_t vuint,
2567 const char **vstr)
2568 {
2569 uint32_t i;
2570
2571 for (i = 0; i < len; i++)
2572 if (!strcmp(param_val_conv[i].name, name) &&
2573 param_val_conv[i].vuint == vuint) {
2574 *vstr = param_val_conv[i].vstr;
2575 return 0;
2576 }
2577
2578 return -ENOENT;
2579 }
2580
2581 static const struct param_val_conv param_val_conv[] = {
2582 {
2583 .name = "fw_load_policy",
2584 .vstr = "driver",
2585 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
2586 },
2587 {
2588 .name = "fw_load_policy",
2589 .vstr = "flash",
2590 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
2591 },
2592 {
2593 .name = "fw_load_policy",
2594 .vstr = "disk",
2595 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DISK,
2596 },
2597 {
2598 .name = "reset_dev_on_drv_probe",
2599 .vstr = "unknown",
2600 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN,
2601 },
2602 {
2603 .name = "fw_load_policy",
2604 .vstr = "unknown",
2605 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN,
2606 },
2607 {
2608 .name = "reset_dev_on_drv_probe",
2609 .vstr = "always",
2610 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS,
2611 },
2612 {
2613 .name = "reset_dev_on_drv_probe",
2614 .vstr = "never",
2615 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER,
2616 },
2617 {
2618 .name = "reset_dev_on_drv_probe",
2619 .vstr = "disk",
2620 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK,
2621 },
2622 };
2623
2624 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2625
2626 static void pr_out_param_value(struct dl *dl, const char *nla_name,
2627 int nla_type, struct nlattr *nl)
2628 {
2629 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2630 struct nlattr *val_attr;
2631 const char *vstr;
2632 bool conv_exists;
2633 int err;
2634
2635 err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
2636 if (err != MNL_CB_OK)
2637 return;
2638
2639 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2640 (nla_type != MNL_TYPE_FLAG &&
2641 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2642 return;
2643
2644 check_indent_newline(dl);
2645 print_string(PRINT_ANY, "cmode", "cmode %s",
2646 param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
2647
2648 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2649
2650 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2651 nla_name);
2652
2653 switch (nla_type) {
2654 case MNL_TYPE_U8:
2655 if (conv_exists) {
2656 err = param_val_conv_str_get(param_val_conv,
2657 PARAM_VAL_CONV_LEN,
2658 nla_name,
2659 mnl_attr_get_u8(val_attr),
2660 &vstr);
2661 if (err)
2662 return;
2663 print_string(PRINT_ANY, "value", " value %s", vstr);
2664 } else {
2665 print_uint(PRINT_ANY, "value", " value %u",
2666 mnl_attr_get_u8(val_attr));
2667 }
2668 break;
2669 case MNL_TYPE_U16:
2670 if (conv_exists) {
2671 err = param_val_conv_str_get(param_val_conv,
2672 PARAM_VAL_CONV_LEN,
2673 nla_name,
2674 mnl_attr_get_u16(val_attr),
2675 &vstr);
2676 if (err)
2677 return;
2678 print_string(PRINT_ANY, "value", " value %s", vstr);
2679 } else {
2680 print_uint(PRINT_ANY, "value", " value %u",
2681 mnl_attr_get_u16(val_attr));
2682 }
2683 break;
2684 case MNL_TYPE_U32:
2685 if (conv_exists) {
2686 err = param_val_conv_str_get(param_val_conv,
2687 PARAM_VAL_CONV_LEN,
2688 nla_name,
2689 mnl_attr_get_u32(val_attr),
2690 &vstr);
2691 if (err)
2692 return;
2693 print_string(PRINT_ANY, "value", " value %s", vstr);
2694 } else {
2695 print_uint(PRINT_ANY, "value", " value %u",
2696 mnl_attr_get_u32(val_attr));
2697 }
2698 break;
2699 case MNL_TYPE_STRING:
2700 print_string(PRINT_ANY, "value", " value %s",
2701 mnl_attr_get_str(val_attr));
2702 break;
2703 case MNL_TYPE_FLAG:
2704 print_bool(PRINT_ANY, "value", " value %s", val_attr);
2705 break;
2706 }
2707 }
2708
2709 static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
2710 {
2711 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2712 struct nlattr *param_value_attr;
2713 const char *nla_name;
2714 int nla_type;
2715 int err;
2716
2717 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2718 if (err != MNL_CB_OK)
2719 return;
2720 if (!nla_param[DEVLINK_ATTR_PARAM_NAME] ||
2721 !nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2722 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2723 return;
2724
2725 if (array)
2726 pr_out_handle_start_arr(dl, tb);
2727 else
2728 __pr_out_handle_start(dl, tb, true, false);
2729
2730 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2731
2732 nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
2733 check_indent_newline(dl);
2734 print_string(PRINT_ANY, "name", "name %s ", nla_name);
2735 if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
2736 print_string(PRINT_ANY, "type", "type %s", "driver-specific");
2737 else
2738 print_string(PRINT_ANY, "type", "type %s", "generic");
2739
2740 pr_out_array_start(dl, "values");
2741 mnl_attr_for_each_nested(param_value_attr,
2742 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2743 pr_out_entry_start(dl);
2744 pr_out_param_value(dl, nla_name, nla_type, param_value_attr);
2745 pr_out_entry_end(dl);
2746 }
2747 pr_out_array_end(dl);
2748 pr_out_handle_end(dl);
2749 }
2750
2751 static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
2752 {
2753 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2754 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2755 struct dl *dl = data;
2756
2757 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2758 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2759 !tb[DEVLINK_ATTR_PARAM])
2760 return MNL_CB_ERROR;
2761 pr_out_param(dl, tb, true);
2762 return MNL_CB_OK;
2763 }
2764
2765 struct param_ctx {
2766 struct dl *dl;
2767 int nla_type;
2768 union {
2769 uint8_t vu8;
2770 uint16_t vu16;
2771 uint32_t vu32;
2772 const char *vstr;
2773 bool vbool;
2774 } value;
2775 };
2776
2777 static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
2778 {
2779 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2780 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2781 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2782 struct nlattr *param_value_attr;
2783 enum devlink_param_cmode cmode;
2784 struct param_ctx *ctx = data;
2785 struct dl *dl = ctx->dl;
2786 int nla_type;
2787 int err;
2788
2789 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2790 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2791 !tb[DEVLINK_ATTR_PARAM])
2792 return MNL_CB_ERROR;
2793
2794 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2795 if (err != MNL_CB_OK)
2796 return MNL_CB_ERROR;
2797
2798 if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2799 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2800 return MNL_CB_ERROR;
2801
2802 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2803 mnl_attr_for_each_nested(param_value_attr,
2804 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2805 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2806 struct nlattr *val_attr;
2807
2808 err = mnl_attr_parse_nested(param_value_attr,
2809 attr_cb, nla_value);
2810 if (err != MNL_CB_OK)
2811 return MNL_CB_ERROR;
2812
2813 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2814 (nla_type != MNL_TYPE_FLAG &&
2815 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2816 return MNL_CB_ERROR;
2817
2818 cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
2819 if (cmode == dl->opts.cmode) {
2820 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2821 switch (nla_type) {
2822 case MNL_TYPE_U8:
2823 ctx->value.vu8 = mnl_attr_get_u8(val_attr);
2824 break;
2825 case MNL_TYPE_U16:
2826 ctx->value.vu16 = mnl_attr_get_u16(val_attr);
2827 break;
2828 case MNL_TYPE_U32:
2829 ctx->value.vu32 = mnl_attr_get_u32(val_attr);
2830 break;
2831 case MNL_TYPE_STRING:
2832 ctx->value.vstr = mnl_attr_get_str(val_attr);
2833 break;
2834 case MNL_TYPE_FLAG:
2835 ctx->value.vbool = val_attr ? true : false;
2836 break;
2837 }
2838 break;
2839 }
2840 }
2841 ctx->nla_type = nla_type;
2842 return MNL_CB_OK;
2843 }
2844
2845 static int cmd_dev_param_set(struct dl *dl)
2846 {
2847 struct param_ctx ctx = {};
2848 struct nlmsghdr *nlh;
2849 bool conv_exists;
2850 uint32_t val_u32 = 0;
2851 uint16_t val_u16;
2852 uint8_t val_u8;
2853 bool val_bool;
2854 int err;
2855
2856 err = dl_argv_parse(dl, DL_OPT_HANDLE |
2857 DL_OPT_PARAM_NAME |
2858 DL_OPT_PARAM_VALUE |
2859 DL_OPT_PARAM_CMODE, 0);
2860 if (err)
2861 return err;
2862
2863 /* Get value type */
2864 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET,
2865 NLM_F_REQUEST | NLM_F_ACK);
2866 dl_opts_put(nlh, dl);
2867
2868 ctx.dl = dl;
2869 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
2870 if (err)
2871 return err;
2872
2873 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_SET,
2874 NLM_F_REQUEST | NLM_F_ACK);
2875 dl_opts_put(nlh, dl);
2876
2877 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2878 dl->opts.param_name);
2879
2880 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
2881 switch (ctx.nla_type) {
2882 case MNL_TYPE_U8:
2883 if (conv_exists) {
2884 err = param_val_conv_uint_get(param_val_conv,
2885 PARAM_VAL_CONV_LEN,
2886 dl->opts.param_name,
2887 dl->opts.param_value,
2888 &val_u32);
2889 val_u8 = val_u32;
2890 } else {
2891 err = strtouint8_t(dl->opts.param_value, &val_u8);
2892 }
2893 if (err)
2894 goto err_param_value_parse;
2895 if (val_u8 == ctx.value.vu8)
2896 return 0;
2897 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
2898 break;
2899 case MNL_TYPE_U16:
2900 if (conv_exists) {
2901 err = param_val_conv_uint_get(param_val_conv,
2902 PARAM_VAL_CONV_LEN,
2903 dl->opts.param_name,
2904 dl->opts.param_value,
2905 &val_u32);
2906 val_u16 = val_u32;
2907 } else {
2908 err = strtouint16_t(dl->opts.param_value, &val_u16);
2909 }
2910 if (err)
2911 goto err_param_value_parse;
2912 if (val_u16 == ctx.value.vu16)
2913 return 0;
2914 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
2915 break;
2916 case MNL_TYPE_U32:
2917 if (conv_exists)
2918 err = param_val_conv_uint_get(param_val_conv,
2919 PARAM_VAL_CONV_LEN,
2920 dl->opts.param_name,
2921 dl->opts.param_value,
2922 &val_u32);
2923 else
2924 err = strtouint32_t(dl->opts.param_value, &val_u32);
2925 if (err)
2926 goto err_param_value_parse;
2927 if (val_u32 == ctx.value.vu32)
2928 return 0;
2929 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
2930 break;
2931 case MNL_TYPE_FLAG:
2932 err = strtobool(dl->opts.param_value, &val_bool);
2933 if (err)
2934 goto err_param_value_parse;
2935 if (val_bool == ctx.value.vbool)
2936 return 0;
2937 if (val_bool)
2938 mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2939 0, NULL);
2940 break;
2941 case MNL_TYPE_STRING:
2942 mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2943 dl->opts.param_value);
2944 if (!strcmp(dl->opts.param_value, ctx.value.vstr))
2945 return 0;
2946 break;
2947 default:
2948 printf("Value type not supported\n");
2949 return -ENOTSUP;
2950 }
2951 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2952
2953 err_param_value_parse:
2954 pr_err("Value \"%s\" is not a number or not within range\n",
2955 dl->opts.param_value);
2956 return err;
2957 }
2958
2959 static int cmd_dev_param_show(struct dl *dl)
2960 {
2961 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2962 struct nlmsghdr *nlh;
2963 int err;
2964
2965 if (dl_argc(dl) == 0)
2966 flags |= NLM_F_DUMP;
2967
2968 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
2969
2970 if (dl_argc(dl) > 0) {
2971 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
2972 DL_OPT_PARAM_NAME, 0);
2973 if (err)
2974 return err;
2975 }
2976
2977 pr_out_section_start(dl, "param");
2978 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_show_cb, dl);
2979 pr_out_section_end(dl);
2980 return err;
2981 }
2982
2983 static int cmd_dev_param(struct dl *dl)
2984 {
2985 if (dl_argv_match(dl, "help")) {
2986 cmd_dev_help();
2987 return 0;
2988 } else if (dl_argv_match(dl, "show") ||
2989 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2990 dl_arg_inc(dl);
2991 return cmd_dev_param_show(dl);
2992 } else if (dl_argv_match(dl, "set")) {
2993 dl_arg_inc(dl);
2994 return cmd_dev_param_set(dl);
2995 }
2996 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2997 return -ENOENT;
2998 }
2999
3000 static void pr_out_action_stats(struct dl *dl, struct nlattr *action_stats)
3001 {
3002 struct nlattr *tb_stats_entry[DEVLINK_ATTR_MAX + 1] = {};
3003 struct nlattr *nla_reload_stats_entry, *nla_limit, *nla_value;
3004 enum devlink_reload_limit limit;
3005 uint32_t value;
3006 int err;
3007
3008 mnl_attr_for_each_nested(nla_reload_stats_entry, action_stats) {
3009 err = mnl_attr_parse_nested(nla_reload_stats_entry, attr_cb,
3010 tb_stats_entry);
3011 if (err != MNL_CB_OK)
3012 return;
3013
3014 nla_limit = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_LIMIT];
3015 nla_value = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_VALUE];
3016 if (!nla_limit || !nla_value)
3017 return;
3018
3019 check_indent_newline(dl);
3020 limit = mnl_attr_get_u8(nla_limit);
3021 value = mnl_attr_get_u32(nla_value);
3022 print_uint_name_value(reload_limit_name(limit), value);
3023 }
3024 }
3025
3026 static void pr_out_reload_stats(struct dl *dl, struct nlattr *reload_stats)
3027 {
3028 struct nlattr *nla_action_info, *nla_action, *nla_action_stats;
3029 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3030 enum devlink_reload_action action;
3031 int err;
3032
3033 mnl_attr_for_each_nested(nla_action_info, reload_stats) {
3034 err = mnl_attr_parse_nested(nla_action_info, attr_cb, tb);
3035 if (err != MNL_CB_OK)
3036 return;
3037 nla_action = tb[DEVLINK_ATTR_RELOAD_ACTION];
3038 nla_action_stats = tb[DEVLINK_ATTR_RELOAD_ACTION_STATS];
3039 if (!nla_action || !nla_action_stats)
3040 return;
3041
3042 action = mnl_attr_get_u8(nla_action);
3043 pr_out_object_start(dl, reload_action_name(action));
3044 pr_out_action_stats(dl, nla_action_stats);
3045 pr_out_object_end(dl);
3046 }
3047 }
3048
3049 static void pr_out_reload_data(struct dl *dl, struct nlattr **tb)
3050 {
3051 struct nlattr *nla_reload_stats, *nla_remote_reload_stats;
3052 struct nlattr *tb_stats[DEVLINK_ATTR_MAX + 1] = {};
3053 uint8_t reload_failed = 0;
3054 int err;
3055
3056 if (tb[DEVLINK_ATTR_RELOAD_FAILED])
3057 reload_failed = mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED]);
3058
3059 if (reload_failed) {
3060 check_indent_newline(dl);
3061 print_bool(PRINT_ANY, "reload_failed", "reload_failed %s", true);
3062 }
3063 if (!tb[DEVLINK_ATTR_DEV_STATS] || !dl->stats)
3064 return;
3065 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_DEV_STATS], attr_cb,
3066 tb_stats);
3067 if (err != MNL_CB_OK)
3068 return;
3069
3070 pr_out_object_start(dl, "stats");
3071
3072 nla_reload_stats = tb_stats[DEVLINK_ATTR_RELOAD_STATS];
3073 if (nla_reload_stats) {
3074 pr_out_object_start(dl, "reload");
3075 pr_out_reload_stats(dl, nla_reload_stats);
3076 pr_out_object_end(dl);
3077 }
3078 nla_remote_reload_stats = tb_stats[DEVLINK_ATTR_REMOTE_RELOAD_STATS];
3079 if (nla_remote_reload_stats) {
3080 pr_out_object_start(dl, "remote_reload");
3081 pr_out_reload_stats(dl, nla_remote_reload_stats);
3082 pr_out_object_end(dl);
3083 }
3084
3085 pr_out_object_end(dl);
3086 }
3087
3088
3089 static void pr_out_dev(struct dl *dl, struct nlattr **tb)
3090 {
3091 if ((tb[DEVLINK_ATTR_RELOAD_FAILED] && mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED])) ||
3092 (tb[DEVLINK_ATTR_DEV_STATS] && dl->stats)) {
3093 __pr_out_handle_start(dl, tb, true, false);
3094 pr_out_reload_data(dl, tb);
3095 pr_out_handle_end(dl);
3096 } else {
3097 pr_out_handle(dl, tb);
3098 }
3099 }
3100
3101 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
3102 {
3103 struct dl *dl = data;
3104 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3105 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3106
3107 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3108 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3109 return MNL_CB_ERROR;
3110
3111 pr_out_dev(dl, tb);
3112 return MNL_CB_OK;
3113 }
3114
3115 static int cmd_dev_show(struct dl *dl)
3116 {
3117 struct nlmsghdr *nlh;
3118 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3119 int err;
3120
3121 if (dl_argc(dl) == 0)
3122 flags |= NLM_F_DUMP;
3123
3124 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
3125
3126 if (dl_argc(dl) > 0) {
3127 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3128 if (err)
3129 return err;
3130 }
3131
3132 pr_out_section_start(dl, "dev");
3133 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl);
3134 pr_out_section_end(dl);
3135 return err;
3136 }
3137
3138 static void pr_out_reload_actions_performed(struct dl *dl, struct nlattr **tb)
3139 {
3140 struct nlattr *nla_actions_performed;
3141 struct nla_bitfield32 *actions;
3142 uint32_t actions_performed;
3143 uint16_t len;
3144 int action;
3145
3146 if (!tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3147 return;
3148
3149 nla_actions_performed = tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED];
3150 len = mnl_attr_get_payload_len(nla_actions_performed);
3151 if (len != sizeof(*actions))
3152 return;
3153 actions = mnl_attr_get_payload(nla_actions_performed);
3154 if (!actions)
3155 return;
3156 g_new_line_count = 1; /* Avoid extra new line in non-json print */
3157 pr_out_array_start(dl, "reload_actions_performed");
3158 actions_performed = actions->value & actions->selector;
3159 for (action = 0; action <= DEVLINK_RELOAD_ACTION_MAX; action++) {
3160 if (BIT(action) & actions_performed) {
3161 check_indent_newline(dl);
3162 print_string(PRINT_ANY, NULL, "%s",
3163 reload_action_name(action));
3164 }
3165 }
3166 pr_out_array_end(dl);
3167 if (!dl->json_output)
3168 __pr_out_newline();
3169 }
3170
3171 static int cmd_dev_reload_cb(const struct nlmsghdr *nlh, void *data)
3172 {
3173 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3174 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3175 struct dl *dl = data;
3176
3177 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3178 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3179 !tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3180 return MNL_CB_ERROR;
3181
3182 pr_out_section_start(dl, "reload");
3183 pr_out_reload_actions_performed(dl, tb);
3184 pr_out_section_end(dl);
3185
3186 return MNL_CB_OK;
3187 }
3188
3189 static int cmd_dev_reload(struct dl *dl)
3190 {
3191 struct nlmsghdr *nlh;
3192 int err;
3193
3194 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3195 cmd_dev_help();
3196 return 0;
3197 }
3198
3199 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RELOAD,
3200 NLM_F_REQUEST | NLM_F_ACK);
3201
3202 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
3203 DL_OPT_NETNS | DL_OPT_RELOAD_ACTION |
3204 DL_OPT_RELOAD_LIMIT);
3205 if (err)
3206 return err;
3207
3208 return _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_reload_cb, dl);
3209 }
3210
3211 static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
3212 const char *name, int type)
3213 {
3214 struct nlattr *version;
3215
3216 mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) {
3217 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3218 const char *ver_value;
3219 const char *ver_name;
3220 int err;
3221
3222 if (mnl_attr_get_type(version) != type)
3223 continue;
3224
3225 err = mnl_attr_parse_nested(version, attr_cb, tb);
3226 if (err != MNL_CB_OK)
3227 continue;
3228
3229 if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] ||
3230 !tb[DEVLINK_ATTR_INFO_VERSION_VALUE])
3231 continue;
3232
3233 if (name) {
3234 pr_out_object_start(dl, name);
3235 name = NULL;
3236 }
3237
3238 ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
3239 ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
3240
3241 check_indent_newline(dl);
3242 print_string_name_value(ver_name, ver_value);
3243 if (!dl->json_output)
3244 __pr_out_newline();
3245 }
3246
3247 if (!name)
3248 pr_out_object_end(dl);
3249 }
3250
3251 static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh,
3252 struct nlattr **tb, bool has_versions)
3253 {
3254 __pr_out_handle_start(dl, tb, true, false);
3255
3256 __pr_out_indent_inc();
3257 if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) {
3258 struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME];
3259
3260 if (!dl->json_output)
3261 __pr_out_newline();
3262 check_indent_newline(dl);
3263 print_string(PRINT_ANY, "driver", "driver %s",
3264 mnl_attr_get_str(nla_drv));
3265 }
3266
3267 if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
3268 struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER];
3269
3270 if (!dl->json_output)
3271 __pr_out_newline();
3272 check_indent_newline(dl);
3273 print_string(PRINT_ANY, "serial_number", "serial_number %s",
3274 mnl_attr_get_str(nla_sn));
3275 }
3276
3277 if (tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER]) {
3278 struct nlattr *nla_bsn = tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER];
3279
3280 if (!dl->json_output)
3281 __pr_out_newline();
3282 check_indent_newline(dl);
3283 print_string(PRINT_ANY, "board.serial_number", "board.serial_number %s",
3284 mnl_attr_get_str(nla_bsn));
3285 }
3286 __pr_out_indent_dec();
3287
3288 if (has_versions) {
3289 pr_out_object_start(dl, "versions");
3290
3291 pr_out_versions_single(dl, nlh, "fixed",
3292 DEVLINK_ATTR_INFO_VERSION_FIXED);
3293 pr_out_versions_single(dl, nlh, "running",
3294 DEVLINK_ATTR_INFO_VERSION_RUNNING);
3295 pr_out_versions_single(dl, nlh, "stored",
3296 DEVLINK_ATTR_INFO_VERSION_STORED);
3297
3298 pr_out_object_end(dl);
3299 }
3300
3301 pr_out_handle_end(dl);
3302 }
3303
3304 static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data)
3305 {
3306 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3307 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3308 bool has_versions, has_info;
3309 struct dl *dl = data;
3310
3311 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3312
3313 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3314 return MNL_CB_ERROR;
3315
3316 has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] ||
3317 tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] ||
3318 tb[DEVLINK_ATTR_INFO_VERSION_STORED];
3319 has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] ||
3320 tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] ||
3321 tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] ||
3322 has_versions;
3323
3324 if (has_info)
3325 pr_out_info(dl, nlh, tb, has_versions);
3326
3327 return MNL_CB_OK;
3328 }
3329
3330 static int cmd_dev_info(struct dl *dl)
3331 {
3332 struct nlmsghdr *nlh;
3333 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3334 int err;
3335
3336 if (dl_argv_match(dl, "help")) {
3337 cmd_dev_help();
3338 return 0;
3339 }
3340
3341 if (dl_argc(dl) == 0)
3342 flags |= NLM_F_DUMP;
3343
3344 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_INFO_GET, flags);
3345
3346 if (dl_argc(dl) > 0) {
3347 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3348 if (err)
3349 return err;
3350 }
3351
3352 pr_out_section_start(dl, "info");
3353 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_versions_show_cb, dl);
3354 pr_out_section_end(dl);
3355 return err;
3356 }
3357
3358 struct cmd_dev_flash_status_ctx {
3359 struct dl *dl;
3360 struct timespec time_of_last_status;
3361 uint64_t status_msg_timeout;
3362 size_t elapsed_time_msg_len;
3363 char *last_msg;
3364 char *last_component;
3365 uint8_t not_first:1,
3366 last_pc:1,
3367 received_end:1,
3368 flash_done:1;
3369 };
3370
3371 static int nullstrcmp(const char *str1, const char *str2)
3372 {
3373 if (str1 && str2)
3374 return strcmp(str1, str2);
3375 if (!str1 && !str2)
3376 return 0;
3377 return str1 ? 1 : -1;
3378 }
3379
3380 static void cmd_dev_flash_clear_elapsed_time(struct cmd_dev_flash_status_ctx *ctx)
3381 {
3382 int i;
3383
3384 for (i = 0; i < ctx->elapsed_time_msg_len; i++)
3385 pr_out_tty("\b \b");
3386
3387 ctx->elapsed_time_msg_len = 0;
3388 }
3389
3390 static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
3391 {
3392 struct cmd_dev_flash_status_ctx *ctx = data;
3393 struct dl_opts *opts = &ctx->dl->opts;
3394 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3395 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3396 const char *component = NULL;
3397 uint64_t done = 0, total = 0;
3398 const char *msg = NULL;
3399 const char *bus_name;
3400 const char *dev_name;
3401
3402 cmd_dev_flash_clear_elapsed_time(ctx);
3403
3404 if (genl->cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS &&
3405 genl->cmd != DEVLINK_CMD_FLASH_UPDATE_END)
3406 return MNL_CB_STOP;
3407
3408 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3409 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3410 return MNL_CB_ERROR;
3411 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
3412 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
3413 if (strcmp(bus_name, opts->bus_name) ||
3414 strcmp(dev_name, opts->dev_name))
3415 return MNL_CB_ERROR;
3416
3417 if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END && ctx->not_first) {
3418 pr_out("\n");
3419 free(ctx->last_msg);
3420 free(ctx->last_component);
3421 ctx->received_end = 1;
3422 return MNL_CB_STOP;
3423 }
3424
3425 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG])
3426 msg = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]);
3427 if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT])
3428 component = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]);
3429 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
3430 done = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]);
3431 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
3432 total = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]);
3433 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT])
3434 ctx->status_msg_timeout = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT]);
3435 else
3436 ctx->status_msg_timeout = 0;
3437
3438 if (!nullstrcmp(msg, ctx->last_msg) &&
3439 !nullstrcmp(component, ctx->last_component) &&
3440 ctx->last_pc && ctx->not_first) {
3441 pr_out_tty("\b\b\b\b\b"); /* clean percentage */
3442 } else {
3443 /* only update the last status timestamp if the message changed */
3444 clock_gettime(CLOCK_MONOTONIC, &ctx->time_of_last_status);
3445
3446 if (ctx->not_first)
3447 pr_out("\n");
3448 if (component) {
3449 pr_out("[%s] ", component);
3450 free(ctx->last_component);
3451 ctx->last_component = strdup(component);
3452 }
3453 if (msg) {
3454 pr_out("%s", msg);
3455 free(ctx->last_msg);
3456 ctx->last_msg = strdup(msg);
3457 }
3458 }
3459 if (total) {
3460 pr_out_tty(" %3lu%%", (done * 100) / total);
3461 ctx->last_pc = 1;
3462 } else {
3463 ctx->last_pc = 0;
3464 }
3465 fflush(stdout);
3466 ctx->not_first = 1;
3467
3468 return MNL_CB_STOP;
3469 }
3470
3471 static void cmd_dev_flash_time_elapsed(struct cmd_dev_flash_status_ctx *ctx)
3472 {
3473 struct timespec now, res;
3474
3475 clock_gettime(CLOCK_MONOTONIC, &now);
3476
3477 res.tv_sec = now.tv_sec - ctx->time_of_last_status.tv_sec;
3478 res.tv_nsec = now.tv_nsec - ctx->time_of_last_status.tv_nsec;
3479 if (res.tv_nsec < 0) {
3480 res.tv_sec--;
3481 res.tv_nsec += 1000000000L;
3482 }
3483
3484 /* Only begin displaying an elapsed time message if we've waited a few
3485 * seconds with no response, or the status message included a timeout
3486 * value.
3487 */
3488 if (res.tv_sec > 2 || ctx->status_msg_timeout) {
3489 uint64_t elapsed_m, elapsed_s;
3490 char msg[128];
3491 size_t len;
3492
3493 /* clear the last elapsed time message, if we have one */
3494 cmd_dev_flash_clear_elapsed_time(ctx);
3495
3496 elapsed_m = res.tv_sec / 60;
3497 elapsed_s = res.tv_sec % 60;
3498
3499 /**
3500 * If we've elapsed a few seconds without receiving any status
3501 * notification from the device, we display a time elapsed
3502 * message. This has a few possible formats:
3503 *
3504 * 1) just time elapsed, when no timeout was provided
3505 * " ( Xm Ys )"
3506 * 2) time elapsed out of a timeout that came from the device
3507 * driver via DEVLINK_CMD_FLASH_UPDATE_STATUS_TIMEOUT
3508 * " ( Xm Ys : Am Ys)"
3509 * 3) time elapsed if we still receive no status after
3510 * reaching the provided timeout.
3511 * " ( Xm Ys : timeout reached )"
3512 */
3513 if (!ctx->status_msg_timeout) {
3514 len = snprintf(msg, sizeof(msg),
3515 " ( %lum %lus )", elapsed_m, elapsed_s);
3516 } else if (res.tv_sec <= ctx->status_msg_timeout) {
3517 uint64_t timeout_m, timeout_s;
3518
3519 timeout_m = ctx->status_msg_timeout / 60;
3520 timeout_s = ctx->status_msg_timeout % 60;
3521
3522 len = snprintf(msg, sizeof(msg),
3523 " ( %lum %lus : %lum %lus )",
3524 elapsed_m, elapsed_s, timeout_m, timeout_s);
3525 } else {
3526 len = snprintf(msg, sizeof(msg),
3527 " ( %lum %lus : timeout reached )", elapsed_m, elapsed_s);
3528 }
3529
3530 ctx->elapsed_time_msg_len = len;
3531
3532 pr_out_tty("%s", msg);
3533 fflush(stdout);
3534 }
3535 }
3536
3537 static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx,
3538 struct mnlg_socket *nlg_ntf,
3539 int pipe_r)
3540 {
3541 int nlfd = mnlg_socket_get_fd(nlg_ntf);
3542 struct timeval timeout;
3543 fd_set fds[3];
3544 int fdmax;
3545 int i;
3546 int err;
3547 int err2;
3548
3549 for (i = 0; i < 3; i++)
3550 FD_ZERO(&fds[i]);
3551 FD_SET(pipe_r, &fds[0]);
3552 fdmax = pipe_r + 1;
3553 FD_SET(nlfd, &fds[0]);
3554 if (nlfd >= fdmax)
3555 fdmax = nlfd + 1;
3556
3557 /* select only for a short while (1/10th of a second) in order to
3558 * allow periodically updating the screen with an elapsed time
3559 * indicator.
3560 */
3561 timeout.tv_sec = 0;
3562 timeout.tv_usec = 100000;
3563
3564 while (select(fdmax, &fds[0], &fds[1], &fds[2], &timeout) < 0) {
3565 if (errno == EINTR)
3566 continue;
3567 pr_err("select() failed\n");
3568 return -errno;
3569 }
3570 if (FD_ISSET(nlfd, &fds[0])) {
3571 err = _mnlg_socket_recv_run(nlg_ntf,
3572 cmd_dev_flash_status_cb, ctx);
3573 if (err)
3574 return err;
3575 }
3576 if (FD_ISSET(pipe_r, &fds[0])) {
3577 err = read(pipe_r, &err2, sizeof(err2));
3578 if (err == -1) {
3579 pr_err("Failed to read pipe\n");
3580 return -errno;
3581 }
3582 if (err2)
3583 return err2;
3584 ctx->flash_done = 1;
3585 }
3586 cmd_dev_flash_time_elapsed(ctx);
3587 return 0;
3588 }
3589
3590
3591 static int cmd_dev_flash(struct dl *dl)
3592 {
3593 struct cmd_dev_flash_status_ctx ctx = {.dl = dl,};
3594 struct mnlg_socket *nlg_ntf;
3595 struct nlmsghdr *nlh;
3596 int pipe_r, pipe_w;
3597 int pipe_fds[2];
3598 pid_t pid;
3599 int err;
3600
3601 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3602 cmd_dev_help();
3603 return 0;
3604 }
3605
3606 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
3607 NLM_F_REQUEST | NLM_F_ACK);
3608
3609 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
3610 DL_OPT_FLASH_COMPONENT | DL_OPT_FLASH_OVERWRITE);
3611 if (err)
3612 return err;
3613
3614 nlg_ntf = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
3615 if (!nlg_ntf)
3616 return err;
3617
3618 err = _mnlg_socket_group_add(nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME);
3619 if (err)
3620 goto err_socket;
3621
3622 err = pipe(pipe_fds);
3623 if (err == -1) {
3624 err = -errno;
3625 goto err_socket;
3626 }
3627 pipe_r = pipe_fds[0];
3628 pipe_w = pipe_fds[1];
3629
3630 pid = fork();
3631 if (pid == -1) {
3632 close(pipe_w);
3633 err = -errno;
3634 goto out;
3635 } else if (!pid) {
3636 /* In child, just execute the flash and pass returned
3637 * value through pipe once it is done.
3638 */
3639 int cc;
3640
3641 close(pipe_r);
3642 err = _mnlg_socket_send(dl->nlg, nlh);
3643 cc = write(pipe_w, &err, sizeof(err));
3644 close(pipe_w);
3645 exit(cc != sizeof(err));
3646 }
3647 close(pipe_w);
3648
3649 /* initialize starting time to allow comparison for when to begin
3650 * displaying a time elapsed message.
3651 */
3652 clock_gettime(CLOCK_MONOTONIC, &ctx.time_of_last_status);
3653
3654 do {
3655 err = cmd_dev_flash_fds_process(&ctx, nlg_ntf, pipe_r);
3656 if (err)
3657 goto out;
3658 } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end));
3659
3660 err = _mnlg_socket_recv_run(dl->nlg, NULL, NULL);
3661 out:
3662 close(pipe_r);
3663 err_socket:
3664 mnlg_socket_close(nlg_ntf);
3665 return err;
3666 }
3667
3668 static int cmd_dev(struct dl *dl)
3669 {
3670 if (dl_argv_match(dl, "help")) {
3671 cmd_dev_help();
3672 return 0;
3673 } else if (dl_argv_match(dl, "show") ||
3674 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3675 dl_arg_inc(dl);
3676 return cmd_dev_show(dl);
3677 } else if (dl_argv_match(dl, "eswitch")) {
3678 dl_arg_inc(dl);
3679 return cmd_dev_eswitch(dl);
3680 } else if (dl_argv_match(dl, "reload")) {
3681 dl_arg_inc(dl);
3682 return cmd_dev_reload(dl);
3683 } else if (dl_argv_match(dl, "param")) {
3684 dl_arg_inc(dl);
3685 return cmd_dev_param(dl);
3686 } else if (dl_argv_match(dl, "info")) {
3687 dl_arg_inc(dl);
3688 return cmd_dev_info(dl);
3689 } else if (dl_argv_match(dl, "flash")) {
3690 dl_arg_inc(dl);
3691 return cmd_dev_flash(dl);
3692 }
3693 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3694 return -ENOENT;
3695 }
3696
3697 static void cmd_port_help(void)
3698 {
3699 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3700 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3701 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3702 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3703 pr_err(" devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3704 pr_err(" devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
3705 }
3706
3707 static const char *port_type_name(uint32_t type)
3708 {
3709 switch (type) {
3710 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
3711 case DEVLINK_PORT_TYPE_AUTO: return "auto";
3712 case DEVLINK_PORT_TYPE_ETH: return "eth";
3713 case DEVLINK_PORT_TYPE_IB: return "ib";
3714 default: return "<unknown type>";
3715 }
3716 }
3717
3718 static const char *port_flavour_name(uint16_t flavour)
3719 {
3720 switch (flavour) {
3721 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
3722 return "physical";
3723 case DEVLINK_PORT_FLAVOUR_CPU:
3724 return "cpu";
3725 case DEVLINK_PORT_FLAVOUR_DSA:
3726 return "dsa";
3727 case DEVLINK_PORT_FLAVOUR_PCI_PF:
3728 return "pcipf";
3729 case DEVLINK_PORT_FLAVOUR_PCI_VF:
3730 return "pcivf";
3731 case DEVLINK_PORT_FLAVOUR_VIRTUAL:
3732 return "virtual";
3733 default:
3734 return "<unknown flavour>";
3735 }
3736 }
3737
3738 static void pr_out_port_pfvf_num(struct dl *dl, struct nlattr **tb)
3739 {
3740 uint16_t fn_num;
3741
3742 if (tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER])
3743 print_uint(PRINT_ANY, "controller", " controller %u",
3744 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]));
3745 if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
3746 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
3747 print_uint(PRINT_ANY, "pfnum", " pfnum %u", fn_num);
3748 }
3749 if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
3750 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
3751 print_uint(PRINT_ANY, "vfnum", " vfnum %u", fn_num);
3752 }
3753 if (tb[DEVLINK_ATTR_PORT_EXTERNAL]) {
3754 uint8_t external;
3755
3756 external = mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_EXTERNAL]);
3757 print_bool(PRINT_ANY, "external", " external %s", external);
3758 }
3759 }
3760
3761 static void pr_out_port_function(struct dl *dl, struct nlattr **tb_port)
3762 {
3763 struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {};
3764 unsigned char *data;
3765 SPRINT_BUF(hw_addr);
3766 uint32_t len;
3767 int err;
3768
3769 if (!tb_port[DEVLINK_ATTR_PORT_FUNCTION])
3770 return;
3771
3772 err = mnl_attr_parse_nested(tb_port[DEVLINK_ATTR_PORT_FUNCTION],
3773 function_attr_cb, tb);
3774 if (err != MNL_CB_OK)
3775 return;
3776
3777 if (!tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR])
3778 return;
3779
3780 len = mnl_attr_get_payload_len(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
3781 data = mnl_attr_get_payload(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
3782
3783 pr_out_object_start(dl, "function");
3784 check_indent_newline(dl);
3785 print_string(PRINT_ANY, "hw_addr", "hw_addr %s",
3786 ll_addr_n2a(data, len, 0, hw_addr, sizeof(hw_addr)));
3787 if (!dl->json_output)
3788 __pr_out_indent_dec();
3789 pr_out_object_end(dl);
3790 }
3791
3792 static void pr_out_port(struct dl *dl, struct nlattr **tb)
3793 {
3794 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
3795 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
3796
3797 pr_out_port_handle_start(dl, tb, false);
3798 check_indent_newline(dl);
3799 if (pt_attr) {
3800 uint16_t port_type = mnl_attr_get_u16(pt_attr);
3801
3802 print_string(PRINT_ANY, "type", "type %s",
3803 port_type_name(port_type));
3804 if (dpt_attr) {
3805 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
3806
3807 if (port_type != des_port_type)
3808 print_string(PRINT_ANY, "des_type", " des_type %s",
3809 port_type_name(des_port_type));
3810 }
3811 }
3812 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) {
3813 print_string(PRINT_ANY, "netdev", " netdev %s",
3814 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
3815 }
3816 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) {
3817 print_string(PRINT_ANY, "ibdev", " ibdev %s",
3818 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
3819 }
3820 if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
3821 uint16_t port_flavour =
3822 mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
3823
3824 print_string(PRINT_ANY, "flavour", " flavour %s",
3825 port_flavour_name(port_flavour));
3826
3827 switch (port_flavour) {
3828 case DEVLINK_PORT_FLAVOUR_PCI_PF:
3829 case DEVLINK_PORT_FLAVOUR_PCI_VF:
3830 pr_out_port_pfvf_num(dl, tb);
3831 break;
3832 default:
3833 break;
3834 }
3835 }
3836 if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
3837 uint32_t port_number;
3838
3839 port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
3840 print_uint(PRINT_ANY, "port", " port %u", port_number);
3841 }
3842 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
3843 print_uint(PRINT_ANY, "split_group", " split_group %u",
3844 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
3845 if (tb[DEVLINK_ATTR_PORT_SPLITTABLE])
3846 print_bool(PRINT_ANY, "splittable", " splittable %s",
3847 mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_SPLITTABLE]));
3848 if (tb[DEVLINK_ATTR_PORT_LANES])
3849 print_uint(PRINT_ANY, "lanes", " lanes %u",
3850 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_LANES]));
3851
3852 pr_out_port_function(dl, tb);
3853 pr_out_port_handle_end(dl);
3854 }
3855
3856 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
3857 {
3858 struct dl *dl = data;
3859 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3860 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3861
3862 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3863 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3864 !tb[DEVLINK_ATTR_PORT_INDEX])
3865 return MNL_CB_ERROR;
3866 pr_out_port(dl, tb);
3867 return MNL_CB_OK;
3868 }
3869
3870 static int cmd_port_show(struct dl *dl)
3871 {
3872 struct nlmsghdr *nlh;
3873 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3874 int err;
3875
3876 if (dl_argc(dl) == 0)
3877 flags |= NLM_F_DUMP;
3878
3879 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
3880
3881 if (dl_argc(dl) > 0) {
3882 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
3883 if (err)
3884 return err;
3885 }
3886
3887 pr_out_section_start(dl, "port");
3888 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
3889 pr_out_section_end(dl);
3890 return err;
3891 }
3892
3893 static int cmd_port_set(struct dl *dl)
3894 {
3895 struct nlmsghdr *nlh;
3896 int err;
3897
3898 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
3899 NLM_F_REQUEST | NLM_F_ACK);
3900
3901 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
3902 if (err)
3903 return err;
3904
3905 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3906 }
3907
3908 static int cmd_port_split(struct dl *dl)
3909 {
3910 struct nlmsghdr *nlh;
3911 int err;
3912
3913 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
3914 NLM_F_REQUEST | NLM_F_ACK);
3915
3916 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
3917 if (err)
3918 return err;
3919
3920 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3921 }
3922
3923 static int cmd_port_unsplit(struct dl *dl)
3924 {
3925 struct nlmsghdr *nlh;
3926 int err;
3927
3928 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
3929 NLM_F_REQUEST | NLM_F_ACK);
3930
3931 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
3932 if (err)
3933 return err;
3934
3935 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3936 }
3937
3938 static void cmd_port_function_help(void)
3939 {
3940 pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ]\n");
3941 }
3942
3943 static int cmd_port_function_set(struct dl *dl)
3944 {
3945 struct nlmsghdr *nlh;
3946 int err;
3947
3948 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET, NLM_F_REQUEST | NLM_F_ACK);
3949
3950 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_FUNCTION_HW_ADDR, 0);
3951 if (err)
3952 return err;
3953
3954 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3955 }
3956
3957 static int cmd_port_function(struct dl *dl)
3958 {
3959 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3960 cmd_port_function_help();
3961 return 0;
3962 } else if (dl_argv_match(dl, "set")) {
3963 dl_arg_inc(dl);
3964 return cmd_port_function_set(dl);
3965 }
3966 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3967 return -ENOENT;
3968 }
3969
3970 static int cmd_health(struct dl *dl);
3971 static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port);
3972
3973 static int cmd_port(struct dl *dl)
3974 {
3975 if (dl_argv_match(dl, "help")) {
3976 cmd_port_help();
3977 return 0;
3978 } else if (dl_argv_match(dl, "show") ||
3979 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3980 dl_arg_inc(dl);
3981 return cmd_port_show(dl);
3982 } else if (dl_argv_match(dl, "set")) {
3983 dl_arg_inc(dl);
3984 return cmd_port_set(dl);
3985 } else if (dl_argv_match(dl, "split")) {
3986 dl_arg_inc(dl);
3987 return cmd_port_split(dl);
3988 } else if (dl_argv_match(dl, "unsplit")) {
3989 dl_arg_inc(dl);
3990 return cmd_port_unsplit(dl);
3991 } else if (dl_argv_match(dl, "function")) {
3992 dl_arg_inc(dl);
3993 return cmd_port_function(dl);
3994 } else if (dl_argv_match(dl, "health")) {
3995 dl_arg_inc(dl);
3996 if (dl_argv_match(dl, "list") || dl_no_arg(dl)
3997 || (dl_argv_match(dl, "show") && dl_argc(dl) == 1)) {
3998 dl_arg_inc(dl);
3999 return __cmd_health_show(dl, false, true);
4000 } else {
4001 return cmd_health(dl);
4002 }
4003 }
4004 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4005 return -ENOENT;
4006 }
4007
4008 static void cmd_sb_help(void)
4009 {
4010 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
4011 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
4012 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
4013 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
4014 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4015 pr_err(" pool POOL_INDEX ]\n");
4016 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4017 pr_err(" pool POOL_INDEX th THRESHOLD\n");
4018 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4019 pr_err(" type { ingress | egress } ]\n");
4020 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4021 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
4022 pr_err(" th THRESHOLD\n");
4023 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
4024 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
4025 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
4026 }
4027
4028 static void pr_out_sb(struct dl *dl, struct nlattr **tb)
4029 {
4030 pr_out_handle_start_arr(dl, tb);
4031 check_indent_newline(dl);
4032 print_uint(PRINT_ANY, "sb", "sb %u",
4033 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4034 print_uint(PRINT_ANY, "size", " size %u",
4035 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
4036 print_uint(PRINT_ANY, "ing_pools", " ing_pools %u",
4037 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
4038 print_uint(PRINT_ANY, "eg_pools", " eg_pools %u",
4039 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
4040 print_uint(PRINT_ANY, "ing_tcs", " ing_tcs %u",
4041 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
4042 print_uint(PRINT_ANY, "eg_tcs", " eg_tcs %u",
4043 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
4044 pr_out_handle_end(dl);
4045 }
4046
4047 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
4048 {
4049 struct dl *dl = data;
4050 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4051 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4052
4053 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4054 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4055 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
4056 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
4057 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
4058 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
4059 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
4060 return MNL_CB_ERROR;
4061 pr_out_sb(dl, tb);
4062 return MNL_CB_OK;
4063 }
4064
4065 static int cmd_sb_show(struct dl *dl)
4066 {
4067 struct nlmsghdr *nlh;
4068 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4069 int err;
4070
4071 if (dl_argc(dl) == 0)
4072 flags |= NLM_F_DUMP;
4073
4074 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
4075
4076 if (dl_argc(dl) > 0) {
4077 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4078 if (err)
4079 return err;
4080 }
4081
4082 pr_out_section_start(dl, "sb");
4083 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl);
4084 pr_out_section_end(dl);
4085 return err;
4086 }
4087
4088 static const char *pool_type_name(uint8_t type)
4089 {
4090 switch (type) {
4091 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
4092 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
4093 default: return "<unknown type>";
4094 }
4095 }
4096
4097 static const char *threshold_type_name(uint8_t type)
4098 {
4099 switch (type) {
4100 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
4101 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
4102 default: return "<unknown type>";
4103 }
4104 }
4105
4106 static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
4107 {
4108 pr_out_handle_start_arr(dl, tb);
4109 check_indent_newline(dl);
4110 print_uint(PRINT_ANY, "sb", "sb %u",
4111 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4112 print_uint(PRINT_ANY, "pool", " pool %u",
4113 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
4114 print_string(PRINT_ANY, "type", " type %s",
4115 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
4116 print_uint(PRINT_ANY, "size", " size %u",
4117 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
4118 print_string(PRINT_ANY, "thtype", " thtype %s",
4119 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
4120 if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
4121 print_uint(PRINT_ANY, "cell_size", " cell size %u",
4122 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
4123 pr_out_handle_end(dl);
4124 }
4125
4126 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
4127 {
4128 struct dl *dl = data;
4129 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4130 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4131
4132 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4133 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4134 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
4135 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
4136 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
4137 return MNL_CB_ERROR;
4138 pr_out_sb_pool(dl, tb);
4139 return MNL_CB_OK;
4140 }
4141
4142 static int cmd_sb_pool_show(struct dl *dl)
4143 {
4144 struct nlmsghdr *nlh;
4145 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4146 int err;
4147
4148 if (dl_argc(dl) == 0)
4149 flags |= NLM_F_DUMP;
4150
4151 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
4152
4153 if (dl_argc(dl) > 0) {
4154 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
4155 DL_OPT_SB);
4156 if (err)
4157 return err;
4158 }
4159
4160 pr_out_section_start(dl, "pool");
4161 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
4162 pr_out_section_end(dl);
4163 return err;
4164 }
4165
4166 static int cmd_sb_pool_set(struct dl *dl)
4167 {
4168 struct nlmsghdr *nlh;
4169 int err;
4170
4171 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
4172 NLM_F_REQUEST | NLM_F_ACK);
4173
4174 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
4175 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
4176 if (err)
4177 return err;
4178
4179 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4180 }
4181
4182 static int cmd_sb_pool(struct dl *dl)
4183 {
4184 if (dl_argv_match(dl, "help")) {
4185 cmd_sb_help();
4186 return 0;
4187 } else if (dl_argv_match(dl, "show") ||
4188 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4189 dl_arg_inc(dl);
4190 return cmd_sb_pool_show(dl);
4191 } else if (dl_argv_match(dl, "set")) {
4192 dl_arg_inc(dl);
4193 return cmd_sb_pool_set(dl);
4194 }
4195 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4196 return -ENOENT;
4197 }
4198
4199 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
4200 {
4201 pr_out_port_handle_start_arr(dl, tb, true);
4202 check_indent_newline(dl);
4203 print_uint(PRINT_ANY, "sb", "sb %u",
4204 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4205 print_uint(PRINT_ANY, "pool", " pool %u",
4206 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
4207 print_uint(PRINT_ANY, "threshold", " threshold %u",
4208 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
4209 pr_out_port_handle_end(dl);
4210 }
4211
4212 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
4213 {
4214 struct dl *dl = data;
4215 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4216 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4217
4218 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4219 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4220 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4221 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
4222 return MNL_CB_ERROR;
4223 pr_out_sb_port_pool(dl, tb);
4224 return MNL_CB_OK;
4225 }
4226
4227 static int cmd_sb_port_pool_show(struct dl *dl)
4228 {
4229 struct nlmsghdr *nlh;
4230 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4231 int err;
4232
4233 if (dl_argc(dl) == 0)
4234 flags |= NLM_F_DUMP;
4235
4236 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
4237
4238 if (dl_argc(dl) > 0) {
4239 err = dl_argv_parse_put(nlh, dl,
4240 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
4241 DL_OPT_SB);
4242 if (err)
4243 return err;
4244 }
4245
4246 pr_out_section_start(dl, "port_pool");
4247 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
4248 pr_out_section_end(dl);
4249 return 0;
4250 }
4251
4252 static int cmd_sb_port_pool_set(struct dl *dl)
4253 {
4254 struct nlmsghdr *nlh;
4255 int err;
4256
4257 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
4258 NLM_F_REQUEST | NLM_F_ACK);
4259
4260 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
4261 DL_OPT_SB_TH, DL_OPT_SB);
4262 if (err)
4263 return err;
4264
4265 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4266 }
4267
4268 static int cmd_sb_port_pool(struct dl *dl)
4269 {
4270 if (dl_argv_match(dl, "help")) {
4271 cmd_sb_help();
4272 return 0;
4273 } else if (dl_argv_match(dl, "show") ||
4274 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4275 dl_arg_inc(dl);
4276 return cmd_sb_port_pool_show(dl);
4277 } else if (dl_argv_match(dl, "set")) {
4278 dl_arg_inc(dl);
4279 return cmd_sb_port_pool_set(dl);
4280 }
4281 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4282 return -ENOENT;
4283 }
4284
4285 static int cmd_sb_port(struct dl *dl)
4286 {
4287 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4288 cmd_sb_help();
4289 return 0;
4290 } else if (dl_argv_match(dl, "pool")) {
4291 dl_arg_inc(dl);
4292 return cmd_sb_port_pool(dl);
4293 }
4294 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4295 return -ENOENT;
4296 }
4297
4298 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
4299 {
4300 pr_out_port_handle_start_arr(dl, tb, true);
4301 check_indent_newline(dl);
4302 print_uint(PRINT_ANY, "sb", "sb %u",
4303 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4304 print_uint(PRINT_ANY, "tc", " tc %u",
4305 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
4306 print_string(PRINT_ANY, "type", " type %s",
4307 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
4308 print_uint(PRINT_ANY, "pool", " pool %u",
4309 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
4310 print_uint(PRINT_ANY, "threshold", " threshold %u",
4311 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
4312 pr_out_port_handle_end(dl);
4313 }
4314
4315 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
4316 {
4317 struct dl *dl = data;
4318 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4319 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4320
4321 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4322 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4323 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4324 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
4325 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
4326 return MNL_CB_ERROR;
4327 pr_out_sb_tc_bind(dl, tb);
4328 return MNL_CB_OK;
4329 }
4330
4331 static int cmd_sb_tc_bind_show(struct dl *dl)
4332 {
4333 struct nlmsghdr *nlh;
4334 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4335 int err;
4336
4337 if (dl_argc(dl) == 0)
4338 flags |= NLM_F_DUMP;
4339
4340 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
4341
4342 if (dl_argc(dl) > 0) {
4343 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
4344 DL_OPT_SB_TYPE, DL_OPT_SB);
4345 if (err)
4346 return err;
4347 }
4348
4349 pr_out_section_start(dl, "tc_bind");
4350 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
4351 pr_out_section_end(dl);
4352 return err;
4353 }
4354
4355 static int cmd_sb_tc_bind_set(struct dl *dl)
4356 {
4357 struct nlmsghdr *nlh;
4358 int err;
4359
4360 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
4361 NLM_F_REQUEST | NLM_F_ACK);
4362
4363 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
4364 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
4365 DL_OPT_SB);
4366 if (err)
4367 return err;
4368
4369 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4370 }
4371
4372 static int cmd_sb_tc_bind(struct dl *dl)
4373 {
4374 if (dl_argv_match(dl, "help")) {
4375 cmd_sb_help();
4376 return 0;
4377 } else if (dl_argv_match(dl, "show") ||
4378 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4379 dl_arg_inc(dl);
4380 return cmd_sb_tc_bind_show(dl);
4381 } else if (dl_argv_match(dl, "set")) {
4382 dl_arg_inc(dl);
4383 return cmd_sb_tc_bind_set(dl);
4384 }
4385 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4386 return -ENOENT;
4387 }
4388
4389 static int cmd_sb_tc(struct dl *dl)
4390 {
4391 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4392 cmd_sb_help();
4393 return 0;
4394 } else if (dl_argv_match(dl, "bind")) {
4395 dl_arg_inc(dl);
4396 return cmd_sb_tc_bind(dl);
4397 }
4398 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4399 return -ENOENT;
4400 }
4401
4402 struct occ_item {
4403 struct list_head list;
4404 uint32_t index;
4405 uint32_t cur;
4406 uint32_t max;
4407 uint32_t bound_pool_index;
4408 };
4409
4410 struct occ_port {
4411 struct list_head list;
4412 char *bus_name;
4413 char *dev_name;
4414 uint32_t port_index;
4415 uint32_t sb_index;
4416 struct list_head pool_list;
4417 struct list_head ing_tc_list;
4418 struct list_head eg_tc_list;
4419 };
4420
4421 struct occ_show {
4422 struct dl *dl;
4423 int err;
4424 struct list_head port_list;
4425 };
4426
4427 static struct occ_item *occ_item_alloc(void)
4428 {
4429 return calloc(1, sizeof(struct occ_item));
4430 }
4431
4432 static void occ_item_free(struct occ_item *occ_item)
4433 {
4434 free(occ_item);
4435 }
4436
4437 static struct occ_port *occ_port_alloc(uint32_t port_index)
4438 {
4439 struct occ_port *occ_port;
4440
4441 occ_port = calloc(1, sizeof(*occ_port));
4442 if (!occ_port)
4443 return NULL;
4444 occ_port->port_index = port_index;
4445 INIT_LIST_HEAD(&occ_port->pool_list);
4446 INIT_LIST_HEAD(&occ_port->ing_tc_list);
4447 INIT_LIST_HEAD(&occ_port->eg_tc_list);
4448 return occ_port;
4449 }
4450
4451 static void occ_port_free(struct occ_port *occ_port)
4452 {
4453 struct occ_item *occ_item, *tmp;
4454
4455 list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
4456 occ_item_free(occ_item);
4457 list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
4458 occ_item_free(occ_item);
4459 list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
4460 occ_item_free(occ_item);
4461 }
4462
4463 static struct occ_show *occ_show_alloc(struct dl *dl)
4464 {
4465 struct occ_show *occ_show;
4466
4467 occ_show = calloc(1, sizeof(*occ_show));
4468 if (!occ_show)
4469 return NULL;
4470 occ_show->dl = dl;
4471 INIT_LIST_HEAD(&occ_show->port_list);
4472 return occ_show;
4473 }
4474
4475 static void occ_show_free(struct occ_show *occ_show)
4476 {
4477 struct occ_port *occ_port, *tmp;
4478
4479 list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
4480 occ_port_free(occ_port);
4481 }
4482
4483 static struct occ_port *occ_port_get(struct occ_show *occ_show,
4484 struct nlattr **tb)
4485 {
4486 struct occ_port *occ_port;
4487 uint32_t port_index;
4488
4489 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
4490
4491 list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
4492 if (occ_port->port_index == port_index)
4493 return occ_port;
4494 }
4495 occ_port = occ_port_alloc(port_index);
4496 if (!occ_port)
4497 return NULL;
4498 list_add_tail(&occ_port->list, &occ_show->port_list);
4499 return occ_port;
4500 }
4501
4502 static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
4503 bool bound_pool)
4504 {
4505 struct occ_item *occ_item;
4506 int i = 1;
4507
4508 pr_out_sp(7, " %s:", label);
4509 list_for_each_entry(occ_item, list, list) {
4510 if ((i - 1) % 4 == 0 && i != 1)
4511 pr_out_sp(7, " ");
4512 if (bound_pool)
4513 pr_out_sp(7, "%2u(%u):", occ_item->index,
4514 occ_item->bound_pool_index);
4515 else
4516 pr_out_sp(7, "%2u:", occ_item->index);
4517 pr_out_sp(21, "%10u/%u", occ_item->cur, occ_item->max);
4518 if (i++ % 4 == 0)
4519 pr_out("\n");
4520 }
4521 if ((i - 1) % 4 != 0)
4522 pr_out("\n");
4523 }
4524
4525 static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
4526 struct list_head *list,
4527 bool bound_pool)
4528 {
4529 struct occ_item *occ_item;
4530 char buf[32];
4531
4532 open_json_object(label);
4533 list_for_each_entry(occ_item, list, list) {
4534 sprintf(buf, "%u", occ_item->index);
4535 open_json_object(buf);
4536 if (bound_pool)
4537 print_uint(PRINT_JSON, "bound_pool", NULL,
4538 occ_item->bound_pool_index);
4539 print_uint(PRINT_JSON, "current", NULL, occ_item->cur);
4540 print_uint(PRINT_JSON, "max", NULL, occ_item->max);
4541 close_json_object();
4542 }
4543 close_json_object();
4544 }
4545
4546 static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
4547 {
4548 if (dl->json_output) {
4549 pr_out_json_occ_show_item_list(dl, "pool",
4550 &occ_port->pool_list, false);
4551 pr_out_json_occ_show_item_list(dl, "itc",
4552 &occ_port->ing_tc_list, true);
4553 pr_out_json_occ_show_item_list(dl, "etc",
4554 &occ_port->eg_tc_list, true);
4555 } else {
4556 pr_out("\n");
4557 pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
4558 pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
4559 pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
4560 }
4561 }
4562
4563 static void pr_out_occ_show(struct occ_show *occ_show)
4564 {
4565 struct dl *dl = occ_show->dl;
4566 struct dl_opts *opts = &dl->opts;
4567 struct occ_port *occ_port;
4568
4569 list_for_each_entry(occ_port, &occ_show->port_list, list) {
4570 __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
4571 occ_port->port_index, true, false);
4572 pr_out_occ_show_port(dl, occ_port);
4573 pr_out_port_handle_end(dl);
4574 }
4575 }
4576
4577 static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
4578 struct nlattr **tb)
4579 {
4580 struct occ_port *occ_port;
4581 struct occ_item *occ_item;
4582
4583 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
4584 return;
4585
4586 occ_port = occ_port_get(occ_show, tb);
4587 if (!occ_port) {
4588 occ_show->err = -ENOMEM;
4589 return;
4590 }
4591
4592 occ_item = occ_item_alloc();
4593 if (!occ_item) {
4594 occ_show->err = -ENOMEM;
4595 return;
4596 }
4597 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
4598 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
4599 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
4600 list_add_tail(&occ_item->list, &occ_port->pool_list);
4601 }
4602
4603 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
4604 {
4605 struct occ_show *occ_show = data;
4606 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4607 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4608
4609 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4610 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4611 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4612 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
4613 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
4614 return MNL_CB_ERROR;
4615 cmd_sb_occ_port_pool_process(occ_show, tb);
4616 return MNL_CB_OK;
4617 }
4618
4619 static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
4620 struct nlattr **tb)
4621 {
4622 struct occ_port *occ_port;
4623 struct occ_item *occ_item;
4624 uint8_t pool_type;
4625
4626 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
4627 return;
4628
4629 occ_port = occ_port_get(occ_show, tb);
4630 if (!occ_port) {
4631 occ_show->err = -ENOMEM;
4632 return;
4633 }
4634
4635 occ_item = occ_item_alloc();
4636 if (!occ_item) {
4637 occ_show->err = -ENOMEM;
4638 return;
4639 }
4640 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
4641 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
4642 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
4643 occ_item->bound_pool_index =
4644 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
4645 pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
4646 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
4647 list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
4648 else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
4649 list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
4650 else
4651 occ_item_free(occ_item);
4652 }
4653
4654 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
4655 {
4656 struct occ_show *occ_show = data;
4657 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4658 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4659
4660 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4661 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4662 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
4663 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
4664 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
4665 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
4666 return MNL_CB_ERROR;
4667 cmd_sb_occ_tc_pool_process(occ_show, tb);
4668 return MNL_CB_OK;
4669 }
4670
4671 static int cmd_sb_occ_show(struct dl *dl)
4672 {
4673 struct nlmsghdr *nlh;
4674 struct occ_show *occ_show;
4675 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
4676 int err;
4677
4678 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
4679 if (err)
4680 return err;
4681
4682 occ_show = occ_show_alloc(dl);
4683 if (!occ_show)
4684 return -ENOMEM;
4685
4686 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
4687
4688 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
4689 cmd_sb_occ_port_pool_process_cb, occ_show);
4690 if (err)
4691 goto out;
4692
4693 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
4694
4695 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
4696 cmd_sb_occ_tc_pool_process_cb, occ_show);
4697 if (err)
4698 goto out;
4699
4700 pr_out_section_start(dl, "occupancy");
4701 pr_out_occ_show(occ_show);
4702 pr_out_section_end(dl);
4703
4704 out:
4705 occ_show_free(occ_show);
4706 return err;
4707 }
4708
4709 static int cmd_sb_occ_snapshot(struct dl *dl)
4710 {
4711 struct nlmsghdr *nlh;
4712 int err;
4713
4714 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
4715 NLM_F_REQUEST | NLM_F_ACK);
4716
4717 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4718 if (err)
4719 return err;
4720
4721 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4722 }
4723
4724 static int cmd_sb_occ_clearmax(struct dl *dl)
4725 {
4726 struct nlmsghdr *nlh;
4727 int err;
4728
4729 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
4730 NLM_F_REQUEST | NLM_F_ACK);
4731
4732 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4733 if (err)
4734 return err;
4735
4736 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4737 }
4738
4739 static int cmd_sb_occ(struct dl *dl)
4740 {
4741 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4742 cmd_sb_help();
4743 return 0;
4744 } else if (dl_argv_match(dl, "show") ||
4745 dl_argv_match(dl, "list")) {
4746 dl_arg_inc(dl);
4747 return cmd_sb_occ_show(dl);
4748 } else if (dl_argv_match(dl, "snapshot")) {
4749 dl_arg_inc(dl);
4750 return cmd_sb_occ_snapshot(dl);
4751 } else if (dl_argv_match(dl, "clearmax")) {
4752 dl_arg_inc(dl);
4753 return cmd_sb_occ_clearmax(dl);
4754 }
4755 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4756 return -ENOENT;
4757 }
4758
4759 static int cmd_sb(struct dl *dl)
4760 {
4761 if (dl_argv_match(dl, "help")) {
4762 cmd_sb_help();
4763 return 0;
4764 } else if (dl_argv_match(dl, "show") ||
4765 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4766 dl_arg_inc(dl);
4767 return cmd_sb_show(dl);
4768 } else if (dl_argv_match(dl, "pool")) {
4769 dl_arg_inc(dl);
4770 return cmd_sb_pool(dl);
4771 } else if (dl_argv_match(dl, "port")) {
4772 dl_arg_inc(dl);
4773 return cmd_sb_port(dl);
4774 } else if (dl_argv_match(dl, "tc")) {
4775 dl_arg_inc(dl);
4776 return cmd_sb_tc(dl);
4777 } else if (dl_argv_match(dl, "occupancy")) {
4778 dl_arg_inc(dl);
4779 return cmd_sb_occ(dl);
4780 }
4781 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4782 return -ENOENT;
4783 }
4784
4785 static const char *cmd_name(uint8_t cmd)
4786 {
4787 switch (cmd) {
4788 case DEVLINK_CMD_UNSPEC: return "unspec";
4789 case DEVLINK_CMD_GET: return "get";
4790 case DEVLINK_CMD_SET: return "set";
4791 case DEVLINK_CMD_NEW: return "new";
4792 case DEVLINK_CMD_DEL: return "del";
4793 case DEVLINK_CMD_PORT_GET: return "get";
4794 case DEVLINK_CMD_PORT_SET: return "set";
4795 case DEVLINK_CMD_PORT_NEW: return "new";
4796 case DEVLINK_CMD_PORT_DEL: return "del";
4797 case DEVLINK_CMD_PARAM_GET: return "get";
4798 case DEVLINK_CMD_PARAM_SET: return "set";
4799 case DEVLINK_CMD_PARAM_NEW: return "new";
4800 case DEVLINK_CMD_PARAM_DEL: return "del";
4801 case DEVLINK_CMD_REGION_GET: return "get";
4802 case DEVLINK_CMD_REGION_SET: return "set";
4803 case DEVLINK_CMD_REGION_NEW: return "new";
4804 case DEVLINK_CMD_REGION_DEL: return "del";
4805 case DEVLINK_CMD_FLASH_UPDATE: return "begin";
4806 case DEVLINK_CMD_FLASH_UPDATE_END: return "end";
4807 case DEVLINK_CMD_FLASH_UPDATE_STATUS: return "status";
4808 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER: return "status";
4809 case DEVLINK_CMD_TRAP_GET: return "get";
4810 case DEVLINK_CMD_TRAP_SET: return "set";
4811 case DEVLINK_CMD_TRAP_NEW: return "new";
4812 case DEVLINK_CMD_TRAP_DEL: return "del";
4813 case DEVLINK_CMD_TRAP_GROUP_GET: return "get";
4814 case DEVLINK_CMD_TRAP_GROUP_SET: return "set";
4815 case DEVLINK_CMD_TRAP_GROUP_NEW: return "new";
4816 case DEVLINK_CMD_TRAP_GROUP_DEL: return "del";
4817 case DEVLINK_CMD_TRAP_POLICER_GET: return "get";
4818 case DEVLINK_CMD_TRAP_POLICER_SET: return "set";
4819 case DEVLINK_CMD_TRAP_POLICER_NEW: return "new";
4820 case DEVLINK_CMD_TRAP_POLICER_DEL: return "del";
4821 default: return "<unknown cmd>";
4822 }
4823 }
4824
4825 static const char *cmd_obj(uint8_t cmd)
4826 {
4827 switch (cmd) {
4828 case DEVLINK_CMD_UNSPEC: return "unspec";
4829 case DEVLINK_CMD_GET:
4830 case DEVLINK_CMD_SET:
4831 case DEVLINK_CMD_NEW:
4832 case DEVLINK_CMD_DEL:
4833 return "dev";
4834 case DEVLINK_CMD_PORT_GET:
4835 case DEVLINK_CMD_PORT_SET:
4836 case DEVLINK_CMD_PORT_NEW:
4837 case DEVLINK_CMD_PORT_DEL:
4838 return "port";
4839 case DEVLINK_CMD_PARAM_GET:
4840 case DEVLINK_CMD_PARAM_SET:
4841 case DEVLINK_CMD_PARAM_NEW:
4842 case DEVLINK_CMD_PARAM_DEL:
4843 return "param";
4844 case DEVLINK_CMD_REGION_GET:
4845 case DEVLINK_CMD_REGION_SET:
4846 case DEVLINK_CMD_REGION_NEW:
4847 case DEVLINK_CMD_REGION_DEL:
4848 return "region";
4849 case DEVLINK_CMD_FLASH_UPDATE:
4850 case DEVLINK_CMD_FLASH_UPDATE_END:
4851 case DEVLINK_CMD_FLASH_UPDATE_STATUS:
4852 return "flash";
4853 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
4854 return "health";
4855 case DEVLINK_CMD_TRAP_GET:
4856 case DEVLINK_CMD_TRAP_SET:
4857 case DEVLINK_CMD_TRAP_NEW:
4858 case DEVLINK_CMD_TRAP_DEL:
4859 return "trap";
4860 case DEVLINK_CMD_TRAP_GROUP_GET:
4861 case DEVLINK_CMD_TRAP_GROUP_SET:
4862 case DEVLINK_CMD_TRAP_GROUP_NEW:
4863 case DEVLINK_CMD_TRAP_GROUP_DEL:
4864 return "trap-group";
4865 case DEVLINK_CMD_TRAP_POLICER_GET:
4866 case DEVLINK_CMD_TRAP_POLICER_SET:
4867 case DEVLINK_CMD_TRAP_POLICER_NEW:
4868 case DEVLINK_CMD_TRAP_POLICER_DEL:
4869 return "trap-policer";
4870 default: return "<unknown obj>";
4871 }
4872 }
4873
4874 static void pr_out_mon_header(uint8_t cmd)
4875 {
4876 if (!is_json_context()) {
4877 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
4878 } else {
4879 open_json_object(NULL);
4880 print_string(PRINT_JSON, "command", NULL, cmd_name(cmd));
4881 open_json_object(cmd_obj(cmd));
4882 }
4883 }
4884
4885 static void pr_out_mon_footer(void)
4886 {
4887 if (is_json_context()) {
4888 close_json_object();
4889 close_json_object();
4890 }
4891 }
4892
4893 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
4894 {
4895 const char *obj = cmd_obj(cmd);
4896 unsigned int index = 0;
4897 const char *cur_obj;
4898
4899 if (dl_no_arg(dl))
4900 return true;
4901 while ((cur_obj = dl_argv_index(dl, index++))) {
4902 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
4903 return true;
4904 }
4905 return false;
4906 }
4907
4908 static void pr_out_flash_update(struct dl *dl, struct nlattr **tb)
4909 {
4910 __pr_out_handle_start(dl, tb, true, false);
4911
4912 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]) {
4913 check_indent_newline(dl);
4914 print_string(PRINT_ANY, "msg", "msg %s",
4915 mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]));
4916 }
4917 if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]) {
4918 check_indent_newline(dl);
4919 print_string(PRINT_ANY, "component", "component %s",
4920 mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]));
4921 }
4922
4923 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
4924 pr_out_u64(dl, "done",
4925 mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]));
4926
4927 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
4928 pr_out_u64(dl, "total",
4929 mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]));
4930
4931 pr_out_handle_end(dl);
4932 }
4933
4934 static void pr_out_region(struct dl *dl, struct nlattr **tb);
4935 static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
4936 bool show_device, bool show_port);
4937 static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array);
4938 static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array);
4939 static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array);
4940
4941 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
4942 {
4943 struct dl *dl = data;
4944 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4945 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4946 uint8_t cmd = genl->cmd;
4947
4948 if (!cmd_filter_check(dl, cmd))
4949 return MNL_CB_OK;
4950
4951 switch (cmd) {
4952 case DEVLINK_CMD_GET: /* fall through */
4953 case DEVLINK_CMD_SET: /* fall through */
4954 case DEVLINK_CMD_NEW: /* fall through */
4955 case DEVLINK_CMD_DEL:
4956 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4957 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
4958 return MNL_CB_ERROR;
4959 pr_out_mon_header(genl->cmd);
4960 dl->stats = true;
4961 pr_out_dev(dl, tb);
4962 pr_out_mon_footer();
4963 break;
4964 case DEVLINK_CMD_PORT_GET: /* fall through */
4965 case DEVLINK_CMD_PORT_SET: /* fall through */
4966 case DEVLINK_CMD_PORT_NEW: /* fall through */
4967 case DEVLINK_CMD_PORT_DEL:
4968 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4969 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4970 !tb[DEVLINK_ATTR_PORT_INDEX])
4971 return MNL_CB_ERROR;
4972 pr_out_mon_header(genl->cmd);
4973 pr_out_port(dl, tb);
4974 pr_out_mon_footer();
4975 break;
4976 case DEVLINK_CMD_PARAM_GET: /* fall through */
4977 case DEVLINK_CMD_PARAM_SET: /* fall through */
4978 case DEVLINK_CMD_PARAM_NEW: /* fall through */
4979 case DEVLINK_CMD_PARAM_DEL:
4980 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4981 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4982 !tb[DEVLINK_ATTR_PARAM])
4983 return MNL_CB_ERROR;
4984 pr_out_mon_header(genl->cmd);
4985 pr_out_param(dl, tb, false);
4986 pr_out_mon_footer();
4987 break;
4988 case DEVLINK_CMD_REGION_GET: /* fall through */
4989 case DEVLINK_CMD_REGION_SET: /* fall through */
4990 case DEVLINK_CMD_REGION_NEW: /* fall through */
4991 case DEVLINK_CMD_REGION_DEL:
4992 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4993 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4994 !tb[DEVLINK_ATTR_REGION_NAME])
4995 return MNL_CB_ERROR;
4996 pr_out_mon_header(genl->cmd);
4997 pr_out_region(dl, tb);
4998 pr_out_mon_footer();
4999 break;
5000 case DEVLINK_CMD_FLASH_UPDATE: /* fall through */
5001 case DEVLINK_CMD_FLASH_UPDATE_END: /* fall through */
5002 case DEVLINK_CMD_FLASH_UPDATE_STATUS:
5003 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5004 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
5005 return MNL_CB_ERROR;
5006 pr_out_mon_header(genl->cmd);
5007 pr_out_flash_update(dl, tb);
5008 pr_out_mon_footer();
5009 break;
5010 case DEVLINK_CMD_HEALTH_REPORTER_RECOVER:
5011 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5012 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5013 !tb[DEVLINK_ATTR_HEALTH_REPORTER])
5014 return MNL_CB_ERROR;
5015 pr_out_mon_header(genl->cmd);
5016 pr_out_health(dl, tb, true, true);
5017 pr_out_mon_footer();
5018 break;
5019 case DEVLINK_CMD_TRAP_GET: /* fall through */
5020 case DEVLINK_CMD_TRAP_SET: /* fall through */
5021 case DEVLINK_CMD_TRAP_NEW: /* fall through */
5022 case DEVLINK_CMD_TRAP_DEL:
5023 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5024 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5025 !tb[DEVLINK_ATTR_TRAP_NAME] ||
5026 !tb[DEVLINK_ATTR_TRAP_TYPE] ||
5027 !tb[DEVLINK_ATTR_TRAP_ACTION] ||
5028 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
5029 !tb[DEVLINK_ATTR_TRAP_METADATA] ||
5030 !tb[DEVLINK_ATTR_STATS])
5031 return MNL_CB_ERROR;
5032 pr_out_mon_header(genl->cmd);
5033 pr_out_trap(dl, tb, false);
5034 pr_out_mon_footer();
5035 break;
5036 case DEVLINK_CMD_TRAP_GROUP_GET: /* fall through */
5037 case DEVLINK_CMD_TRAP_GROUP_SET: /* fall through */
5038 case DEVLINK_CMD_TRAP_GROUP_NEW: /* fall through */
5039 case DEVLINK_CMD_TRAP_GROUP_DEL:
5040 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5041 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5042 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
5043 !tb[DEVLINK_ATTR_STATS])
5044 return MNL_CB_ERROR;
5045 pr_out_mon_header(genl->cmd);
5046 pr_out_trap_group(dl, tb, false);
5047 pr_out_mon_footer();
5048 break;
5049 case DEVLINK_CMD_TRAP_POLICER_GET: /* fall through */
5050 case DEVLINK_CMD_TRAP_POLICER_SET: /* fall through */
5051 case DEVLINK_CMD_TRAP_POLICER_NEW: /* fall through */
5052 case DEVLINK_CMD_TRAP_POLICER_DEL: /* fall through */
5053 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5054 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5055 !tb[DEVLINK_ATTR_TRAP_POLICER_ID] ||
5056 !tb[DEVLINK_ATTR_TRAP_POLICER_RATE] ||
5057 !tb[DEVLINK_ATTR_TRAP_POLICER_BURST])
5058 return MNL_CB_ERROR;
5059 pr_out_mon_header(genl->cmd);
5060 pr_out_trap_policer(dl, tb, false);
5061 break;
5062 }
5063 fflush(stdout);
5064 return MNL_CB_OK;
5065 }
5066
5067 static int cmd_mon_show(struct dl *dl)
5068 {
5069 int err;
5070 unsigned int index = 0;
5071 const char *cur_obj;
5072
5073 while ((cur_obj = dl_argv_index(dl, index++))) {
5074 if (strcmp(cur_obj, "all") != 0 &&
5075 strcmp(cur_obj, "dev") != 0 &&
5076 strcmp(cur_obj, "port") != 0 &&
5077 strcmp(cur_obj, "health") != 0 &&
5078 strcmp(cur_obj, "trap") != 0 &&
5079 strcmp(cur_obj, "trap-group") != 0 &&
5080 strcmp(cur_obj, "trap-policer") != 0) {
5081 pr_err("Unknown object \"%s\"\n", cur_obj);
5082 return -EINVAL;
5083 }
5084 }
5085 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
5086 if (err)
5087 return err;
5088 open_json_object(NULL);
5089 open_json_array(PRINT_JSON, "mon");
5090 err = _mnlg_socket_recv_run_intr(dl->nlg, cmd_mon_show_cb, dl);
5091 close_json_array(PRINT_JSON, NULL);
5092 close_json_object();
5093 if (err)
5094 return err;
5095 return 0;
5096 }
5097
5098 static void cmd_mon_help(void)
5099 {
5100 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
5101 "where OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
5102 }
5103
5104 static int cmd_mon(struct dl *dl)
5105 {
5106 if (dl_argv_match(dl, "help")) {
5107 cmd_mon_help();
5108 return 0;
5109 }
5110 return cmd_mon_show(dl);
5111 }
5112
5113 struct dpipe_field {
5114 char *name;
5115 unsigned int id;
5116 unsigned int bitwidth;
5117 enum devlink_dpipe_field_mapping_type mapping_type;
5118 };
5119
5120 struct dpipe_header {
5121 struct list_head list;
5122 char *name;
5123 unsigned int id;
5124 struct dpipe_field *fields;
5125 unsigned int fields_count;
5126 };
5127
5128 struct dpipe_table {
5129 struct list_head list;
5130 char *name;
5131 unsigned int resource_id;
5132 bool resource_valid;
5133 };
5134
5135 struct dpipe_tables {
5136 struct list_head table_list;
5137 };
5138
5139 struct resource {
5140 char *name;
5141 uint64_t size;
5142 uint64_t size_new;
5143 uint64_t size_min;
5144 uint64_t size_max;
5145 uint64_t size_gran;
5146 enum devlink_resource_unit unit;
5147 bool size_valid;
5148 uint64_t size_occ;
5149 bool occ_valid;
5150 uint64_t id;
5151 struct list_head list;
5152 struct list_head resource_list;
5153 struct resource *parent;
5154 };
5155
5156 struct resources {
5157 struct list_head resource_list;
5158 };
5159
5160 struct resource_ctx {
5161 struct dl *dl;
5162 int err;
5163 struct resources *resources;
5164 struct dpipe_tables *tables;
5165 bool print_resources;
5166 bool pending_change;
5167 };
5168
5169 static struct resource *resource_alloc(void)
5170 {
5171 struct resource *resource;
5172
5173 resource = calloc(1, sizeof(struct resource));
5174 if (!resource)
5175 return NULL;
5176 INIT_LIST_HEAD(&resource->resource_list);
5177 return resource;
5178 }
5179
5180 static void resource_free(struct resource *resource)
5181 {
5182 struct resource *child_resource, *tmp;
5183
5184 list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
5185 list) {
5186 free(child_resource->name);
5187 resource_free(child_resource);
5188 }
5189 free(resource);
5190 }
5191
5192 static struct resources *resources_alloc(void)
5193 {
5194 struct resources *resources;
5195
5196 resources = calloc(1, sizeof(struct resources));
5197 if (!resources)
5198 return NULL;
5199 INIT_LIST_HEAD(&resources->resource_list);
5200 return resources;
5201 }
5202
5203 static void resources_free(struct resources *resources)
5204 {
5205 struct resource *resource, *tmp;
5206
5207 list_for_each_entry_safe(resource, tmp, &resources->resource_list, list)
5208 resource_free(resource);
5209 }
5210
5211 static int resource_ctx_init(struct resource_ctx *ctx, struct dl *dl)
5212 {
5213 ctx->resources = resources_alloc();
5214 if (!ctx->resources)
5215 return -ENOMEM;
5216 ctx->dl = dl;
5217 return 0;
5218 }
5219
5220 static void resource_ctx_fini(struct resource_ctx *ctx)
5221 {
5222 resources_free(ctx->resources);
5223 }
5224
5225 struct dpipe_ctx {
5226 struct dl *dl;
5227 int err;
5228 struct list_head global_headers;
5229 struct list_head local_headers;
5230 struct dpipe_tables *tables;
5231 struct resources *resources;
5232 bool print_headers;
5233 bool print_tables;
5234 };
5235
5236 static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
5237 {
5238 struct dpipe_header *header;
5239
5240 header = calloc(1, sizeof(struct dpipe_header));
5241 if (!header)
5242 return NULL;
5243 header->fields = calloc(fields_count, sizeof(struct dpipe_field));
5244 if (!header->fields)
5245 goto err_fields_alloc;
5246 header->fields_count = fields_count;
5247 return header;
5248
5249 err_fields_alloc:
5250 free(header);
5251 return NULL;
5252 }
5253
5254 static void dpipe_header_free(struct dpipe_header *header)
5255 {
5256 free(header->fields);
5257 free(header);
5258 }
5259
5260 static void dpipe_header_clear(struct dpipe_header *header)
5261 {
5262 struct dpipe_field *field;
5263 int i;
5264
5265 for (i = 0; i < header->fields_count; i++) {
5266 field = &header->fields[i];
5267 free(field->name);
5268 }
5269 free(header->name);
5270 }
5271
5272 static void dpipe_header_add(struct dpipe_ctx *ctx,
5273 struct dpipe_header *header, bool global)
5274 {
5275 if (global)
5276 list_add(&header->list, &ctx->global_headers);
5277 else
5278 list_add(&header->list, &ctx->local_headers);
5279 }
5280
5281 static void dpipe_header_del(struct dpipe_header *header)
5282 {
5283 list_del(&header->list);
5284 }
5285
5286 static struct dpipe_table *dpipe_table_alloc(void)
5287 {
5288 return calloc(1, sizeof(struct dpipe_table));
5289 }
5290
5291 static void dpipe_table_free(struct dpipe_table *table)
5292 {
5293 free(table);
5294 }
5295
5296 static struct dpipe_tables *dpipe_tables_alloc(void)
5297 {
5298 struct dpipe_tables *tables;
5299
5300 tables = calloc(1, sizeof(struct dpipe_tables));
5301 if (!tables)
5302 return NULL;
5303 INIT_LIST_HEAD(&tables->table_list);
5304 return tables;
5305 }
5306
5307 static void dpipe_tables_free(struct dpipe_tables *tables)
5308 {
5309 struct dpipe_table *table, *tmp;
5310
5311 list_for_each_entry_safe(table, tmp, &tables->table_list, list)
5312 dpipe_table_free(table);
5313 free(tables);
5314 }
5315
5316 static int dpipe_ctx_init(struct dpipe_ctx *ctx, struct dl *dl)
5317 {
5318 ctx->tables = dpipe_tables_alloc();
5319 if (!ctx->tables)
5320 return -ENOMEM;
5321
5322 ctx->dl = dl;
5323 INIT_LIST_HEAD(&ctx->global_headers);
5324 INIT_LIST_HEAD(&ctx->local_headers);
5325 return 0;
5326 }
5327
5328 static void dpipe_ctx_fini(struct dpipe_ctx *ctx)
5329 {
5330 struct dpipe_header *header, *tmp;
5331
5332 list_for_each_entry_safe(header, tmp, &ctx->global_headers,
5333 list) {
5334 dpipe_header_del(header);
5335 dpipe_header_clear(header);
5336 dpipe_header_free(header);
5337 }
5338 list_for_each_entry_safe(header, tmp, &ctx->local_headers,
5339 list) {
5340 dpipe_header_del(header);
5341 dpipe_header_clear(header);
5342 dpipe_header_free(header);
5343 }
5344 dpipe_tables_free(ctx->tables);
5345 }
5346
5347 static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
5348 uint32_t header_id, bool global)
5349 {
5350 struct list_head *header_list;
5351 struct dpipe_header *header;
5352
5353 if (global)
5354 header_list = &ctx->global_headers;
5355 else
5356 header_list = &ctx->local_headers;
5357 list_for_each_entry(header, header_list, list) {
5358 if (header->id != header_id)
5359 continue;
5360 return header->name;
5361 }
5362 return NULL;
5363 }
5364
5365 static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
5366 uint32_t header_id,
5367 uint32_t field_id, bool global)
5368 {
5369 struct list_head *header_list;
5370 struct dpipe_header *header;
5371
5372 if (global)
5373 header_list = &ctx->global_headers;
5374 else
5375 header_list = &ctx->local_headers;
5376 list_for_each_entry(header, header_list, list) {
5377 if (header->id != header_id)
5378 continue;
5379 return header->fields[field_id].name;
5380 }
5381 return NULL;
5382 }
5383
5384 static const char *
5385 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
5386 {
5387 switch (mapping_type) {
5388 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
5389 return NULL;
5390 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
5391 return "ifindex";
5392 default:
5393 return "<unknown>";
5394 }
5395 }
5396
5397 static const char *
5398 dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
5399 uint32_t field_id, bool global)
5400 {
5401 enum devlink_dpipe_field_mapping_type mapping_type;
5402 struct list_head *header_list;
5403 struct dpipe_header *header;
5404
5405 if (global)
5406 header_list = &ctx->global_headers;
5407 else
5408 header_list = &ctx->local_headers;
5409 list_for_each_entry(header, header_list, list) {
5410 if (header->id != header_id)
5411 continue;
5412 mapping_type = header->fields[field_id].mapping_type;
5413 return dpipe_field_mapping_e2s(mapping_type);
5414 }
5415 return NULL;
5416 }
5417
5418 static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
5419 struct dpipe_field *fields,
5420 unsigned int field_count)
5421 {
5422 struct dpipe_field *field;
5423 int i;
5424
5425 for (i = 0; i < field_count; i++) {
5426 field = &fields[i];
5427 pr_out_entry_start(ctx->dl);
5428 check_indent_newline(ctx->dl);
5429 print_string(PRINT_ANY, "name", "name %s", field->name);
5430 if (ctx->dl->verbose)
5431 print_uint(PRINT_ANY, "id", " id %u", field->id);
5432 print_uint(PRINT_ANY, "bitwidth", " bitwidth %u", field->bitwidth);
5433 if (field->mapping_type) {
5434 print_string(PRINT_ANY, "mapping_type", " mapping_type %s",
5435 dpipe_field_mapping_e2s(field->mapping_type));
5436 }
5437 pr_out_entry_end(ctx->dl);
5438 }
5439 }
5440
5441 static void
5442 pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
5443 struct dpipe_header *header, bool global)
5444 {
5445 pr_out_handle_start_arr(ctx->dl, tb);
5446 check_indent_newline(ctx->dl);
5447 print_string(PRINT_ANY, "name", "name %s", header->name);
5448 if (ctx->dl->verbose) {
5449 print_uint(PRINT_ANY, "id", " id %u", header->id);
5450 print_bool(PRINT_ANY, "global", " global %s", global);
5451 }
5452 pr_out_array_start(ctx->dl, "field");
5453 pr_out_dpipe_fields(ctx, header->fields,
5454 header->fields_count);
5455 pr_out_array_end(ctx->dl);
5456 pr_out_handle_end(ctx->dl);
5457 }
5458
5459 static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
5460 struct nlattr **tb)
5461 {
5462 struct dpipe_header *header;
5463
5464 list_for_each_entry(header, &ctx->local_headers, list)
5465 pr_out_dpipe_header(ctx, tb, header, false);
5466
5467 list_for_each_entry(header, &ctx->global_headers, list)
5468 pr_out_dpipe_header(ctx, tb, header, true);
5469 }
5470
5471 static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
5472 {
5473 struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
5474 const char *name;
5475 int err;
5476
5477 err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
5478 if (err != MNL_CB_OK)
5479 return -EINVAL;
5480 if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
5481 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
5482 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
5483 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
5484 return -EINVAL;
5485
5486 name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
5487 field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5488 field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
5489 field->name = strdup(name);
5490 if (!field->name)
5491 return -ENOMEM;
5492 field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
5493 return 0;
5494 }
5495
5496 static int dpipe_header_fields_get(struct nlattr *nla_fields,
5497 struct dpipe_field *fields)
5498 {
5499 struct nlattr *nla_field;
5500 int count = 0;
5501 int err;
5502
5503 mnl_attr_for_each_nested(nla_field, nla_fields) {
5504 err = dpipe_header_field_get(nla_field, &fields[count]);
5505 if (err)
5506 return err;
5507 count++;
5508 }
5509 return 0;
5510 }
5511
5512 static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
5513 {
5514 struct nlattr *nla_field;
5515 unsigned int count = 0;
5516
5517 mnl_attr_for_each_nested(nla_field, nla_fields)
5518 count++;
5519 return count;
5520 }
5521
5522 static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
5523 {
5524 struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
5525 struct dpipe_header *header;
5526 unsigned int fields_count;
5527 const char *header_name;
5528 bool global;
5529 int err;
5530
5531 err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
5532 if (err != MNL_CB_OK)
5533 return -EINVAL;
5534
5535 if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
5536 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5537 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
5538 return -EINVAL;
5539
5540 fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
5541 header = dpipe_header_alloc(fields_count);
5542 if (!header)
5543 return -ENOMEM;
5544
5545 header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
5546 header->name = strdup(header_name);
5547 header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5548 header->fields_count = fields_count;
5549 global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5550
5551 err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
5552 header->fields);
5553 if (err)
5554 goto err_field_get;
5555 dpipe_header_add(ctx, header, global);
5556 return 0;
5557
5558 err_field_get:
5559 dpipe_header_free(header);
5560 return err;
5561 }
5562
5563 static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
5564 {
5565 struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
5566 struct nlattr *nla_header;
5567 int err;
5568
5569 mnl_attr_for_each_nested(nla_header, nla_headers) {
5570 err = dpipe_header_get(ctx, nla_header);
5571 if (err)
5572 return err;
5573 }
5574 return 0;
5575 }
5576
5577 static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
5578 {
5579 struct dpipe_ctx *ctx = data;
5580 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5581 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5582 int err;
5583
5584 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5585 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5586 !tb[DEVLINK_ATTR_DPIPE_HEADERS])
5587 return MNL_CB_ERROR;
5588 err = dpipe_headers_get(ctx, tb);
5589 if (err) {
5590 ctx->err = err;
5591 return MNL_CB_ERROR;
5592 }
5593
5594 if (ctx->print_headers)
5595 pr_out_dpipe_headers(ctx, tb);
5596 return MNL_CB_OK;
5597 }
5598
5599 static int cmd_dpipe_headers_show(struct dl *dl)
5600 {
5601 struct nlmsghdr *nlh;
5602 struct dpipe_ctx ctx = {};
5603 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5604 int err;
5605
5606 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
5607
5608 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
5609 if (err)
5610 return err;
5611
5612 err = dpipe_ctx_init(&ctx, dl);
5613 if (err)
5614 return err;
5615
5616 ctx.print_headers = true;
5617
5618 pr_out_section_start(dl, "header");
5619 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
5620 if (err)
5621 pr_err("error get headers %s\n", strerror(ctx.err));
5622 pr_out_section_end(dl);
5623
5624 dpipe_ctx_fini(&ctx);
5625 return err;
5626 }
5627
5628 static void cmd_dpipe_help(void)
5629 {
5630 pr_err("Usage: devlink dpipe table show DEV [ name TABLE_NAME ]\n");
5631 pr_err(" devlink dpipe table set DEV name TABLE_NAME\n");
5632 pr_err(" [ counters_enabled { true | false } ]\n");
5633 pr_err(" devlink dpipe table dump DEV name TABLE_NAME\n");
5634 pr_err(" devlink dpipe header show DEV\n");
5635 }
5636
5637 static int cmd_dpipe_header(struct dl *dl)
5638 {
5639 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5640 cmd_dpipe_help();
5641 return 0;
5642 } else if (dl_argv_match(dl, "show")) {
5643 dl_arg_inc(dl);
5644 return cmd_dpipe_headers_show(dl);
5645 }
5646 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5647 return -ENOENT;
5648 }
5649
5650 static const char
5651 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
5652 {
5653 switch (action_type) {
5654 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
5655 return "field_modify";
5656 default:
5657 return "<unknown>";
5658 }
5659 }
5660
5661 struct dpipe_op_info {
5662 uint32_t header_id;
5663 uint32_t field_id;
5664 bool header_global;
5665 };
5666
5667 struct dpipe_action {
5668 struct dpipe_op_info info;
5669 uint32_t type;
5670 };
5671
5672 static void pr_out_dpipe_action(struct dpipe_action *action,
5673 struct dpipe_ctx *ctx)
5674 {
5675 struct dpipe_op_info *op_info = &action->info;
5676 const char *mapping;
5677
5678 check_indent_newline(ctx->dl);
5679 print_string(PRINT_ANY, "type", "type %s",
5680 dpipe_action_type_e2s(action->type));
5681 print_string(PRINT_ANY, "header", " header %s",
5682 dpipe_header_id2s(ctx, op_info->header_id,
5683 op_info->header_global));
5684 print_string(PRINT_ANY, "field", " field %s",
5685 dpipe_field_id2s(ctx, op_info->header_id,
5686 op_info->field_id,
5687 op_info->header_global));
5688 mapping = dpipe_mapping_get(ctx, op_info->header_id,
5689 op_info->field_id,
5690 op_info->header_global);
5691 if (mapping)
5692 print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
5693 }
5694
5695 static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
5696 {
5697 struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
5698 int err;
5699
5700 err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
5701 if (err != MNL_CB_OK)
5702 return -EINVAL;
5703
5704 if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
5705 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
5706 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5707 !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
5708 return -EINVAL;
5709 }
5710
5711 action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
5712 action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5713 action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5714 action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5715
5716 return 0;
5717 }
5718
5719 static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
5720 struct nlattr *nla_actions)
5721 {
5722 struct nlattr *nla_action;
5723 struct dpipe_action action;
5724
5725 mnl_attr_for_each_nested(nla_action, nla_actions) {
5726 pr_out_entry_start(ctx->dl);
5727 if (dpipe_action_parse(&action, nla_action))
5728 goto err_action_parse;
5729 pr_out_dpipe_action(&action, ctx);
5730 pr_out_entry_end(ctx->dl);
5731 }
5732 return 0;
5733
5734 err_action_parse:
5735 pr_out_entry_end(ctx->dl);
5736 return -EINVAL;
5737 }
5738
5739 static const char *
5740 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
5741 {
5742 switch (match_type) {
5743 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
5744 return "field_exact";
5745 default:
5746 return "<unknown>";
5747 }
5748 }
5749
5750 struct dpipe_match {
5751 struct dpipe_op_info info;
5752 uint32_t type;
5753 };
5754
5755 static void pr_out_dpipe_match(struct dpipe_match *match,
5756 struct dpipe_ctx *ctx)
5757 {
5758 struct dpipe_op_info *op_info = &match->info;
5759 const char *mapping;
5760
5761 check_indent_newline(ctx->dl);
5762 print_string(PRINT_ANY, "type", "type %s",
5763 dpipe_match_type_e2s(match->type));
5764 print_string(PRINT_ANY, "header", " header %s",
5765 dpipe_header_id2s(ctx, op_info->header_id,
5766 op_info->header_global));
5767 print_string(PRINT_ANY, "field", " field %s",
5768 dpipe_field_id2s(ctx, op_info->header_id,
5769 op_info->field_id,
5770 op_info->header_global));
5771 mapping = dpipe_mapping_get(ctx, op_info->header_id,
5772 op_info->field_id,
5773 op_info->header_global);
5774 if (mapping)
5775 print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
5776 }
5777
5778 static int dpipe_match_parse(struct dpipe_match *match,
5779 struct nlattr *nl)
5780
5781 {
5782 struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
5783 int err;
5784
5785 err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
5786 if (err != MNL_CB_OK)
5787 return -EINVAL;
5788
5789 if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
5790 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
5791 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5792 !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
5793 return -EINVAL;
5794 }
5795
5796 match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
5797 match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5798 match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5799 match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5800
5801 return 0;
5802 }
5803
5804 static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
5805 struct nlattr *nla_matches)
5806 {
5807 struct nlattr *nla_match;
5808 struct dpipe_match match;
5809
5810 mnl_attr_for_each_nested(nla_match, nla_matches) {
5811 pr_out_entry_start(ctx->dl);
5812 if (dpipe_match_parse(&match, nla_match))
5813 goto err_match_parse;
5814 pr_out_dpipe_match(&match, ctx);
5815 pr_out_entry_end(ctx->dl);
5816 }
5817 return 0;
5818
5819 err_match_parse:
5820 pr_out_entry_end(ctx->dl);
5821 return -EINVAL;
5822 }
5823
5824 static struct resource *
5825 resource_find(struct resources *resources, struct resource *resource,
5826 uint64_t resource_id)
5827 {
5828 struct list_head *list_head;
5829
5830 if (!resource)
5831 list_head = &resources->resource_list;
5832 else
5833 list_head = &resource->resource_list;
5834
5835 list_for_each_entry(resource, list_head, list) {
5836 struct resource *child_resource;
5837
5838 if (resource->id == resource_id)
5839 return resource;
5840
5841 child_resource = resource_find(resources, resource,
5842 resource_id);
5843 if (child_resource)
5844 return child_resource;
5845 }
5846 return NULL;
5847 }
5848
5849 static void
5850 resource_path_print(struct dl *dl, struct resources *resources,
5851 uint64_t resource_id)
5852 {
5853 struct resource *resource, *parent_resource;
5854 const char del[] = "/";
5855 int path_len = 0;
5856 char *path;
5857
5858 resource = resource_find(resources, NULL, resource_id);
5859 if (!resource)
5860 return;
5861
5862 for (parent_resource = resource; parent_resource;
5863 parent_resource = parent_resource->parent)
5864 path_len += strlen(parent_resource->name) + 1;
5865
5866 path_len++;
5867 path = calloc(1, path_len);
5868 if (!path)
5869 return;
5870
5871 path += path_len - 1;
5872 for (parent_resource = resource; parent_resource;
5873 parent_resource = parent_resource->parent) {
5874 path -= strlen(parent_resource->name);
5875 memcpy(path, parent_resource->name,
5876 strlen(parent_resource->name));
5877 path -= strlen(del);
5878 memcpy(path, del, strlen(del));
5879 }
5880 check_indent_newline(dl);
5881 print_string(PRINT_ANY, "resource_path", "resource_path %s", path);
5882 free(path);
5883 }
5884
5885 static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
5886 {
5887 struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
5888 struct dpipe_table *table;
5889 uint32_t resource_units;
5890 bool counters_enabled;
5891 bool resource_valid;
5892 uint32_t size;
5893 int err;
5894
5895 err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
5896 if (err != MNL_CB_OK)
5897 return -EINVAL;
5898
5899 if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
5900 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
5901 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
5902 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
5903 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
5904 return -EINVAL;
5905 }
5906
5907 table = dpipe_table_alloc();
5908 if (!table)
5909 return -ENOMEM;
5910
5911 table->name = strdup(mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]));
5912 size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
5913 counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
5914
5915 resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
5916 ctx->resources;
5917 if (resource_valid) {
5918 table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
5919 table->resource_valid = true;
5920 }
5921
5922 list_add_tail(&table->list, &ctx->tables->table_list);
5923 if (!ctx->print_tables)
5924 return 0;
5925
5926 check_indent_newline(ctx->dl);
5927 print_string(PRINT_ANY, "name", "name %s", table->name);
5928 print_uint(PRINT_ANY, "size", " size %u", size);
5929 print_bool(PRINT_ANY, "counters_enabled", " counters_enabled %s", counters_enabled);
5930
5931 if (resource_valid) {
5932 resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
5933 resource_path_print(ctx->dl, ctx->resources,
5934 table->resource_id);
5935 print_uint(PRINT_ANY, "resource_units", " resource_units %u",
5936 resource_units);
5937 }
5938
5939 pr_out_array_start(ctx->dl, "match");
5940 if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
5941 goto err_matches_show;
5942 pr_out_array_end(ctx->dl);
5943
5944 pr_out_array_start(ctx->dl, "action");
5945 if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
5946 goto err_actions_show;
5947 pr_out_array_end(ctx->dl);
5948
5949 return 0;
5950
5951 err_actions_show:
5952 err_matches_show:
5953 pr_out_array_end(ctx->dl);
5954 return -EINVAL;
5955 }
5956
5957 static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
5958 {
5959 struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
5960 struct nlattr *nla_table;
5961
5962 mnl_attr_for_each_nested(nla_table, nla_tables) {
5963 if (ctx->print_tables)
5964 pr_out_handle_start_arr(ctx->dl, tb);
5965 if (dpipe_table_show(ctx, nla_table))
5966 goto err_table_show;
5967 if (ctx->print_tables)
5968 pr_out_handle_end(ctx->dl);
5969 }
5970 return 0;
5971
5972 err_table_show:
5973 if (ctx->print_tables)
5974 pr_out_handle_end(ctx->dl);
5975 return -EINVAL;
5976 }
5977
5978 static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
5979 {
5980 struct dpipe_ctx *ctx = data;
5981 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5982 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5983
5984 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5985 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5986 !tb[DEVLINK_ATTR_DPIPE_TABLES])
5987 return MNL_CB_ERROR;
5988
5989 if (dpipe_tables_show(ctx, tb))
5990 return MNL_CB_ERROR;
5991 return MNL_CB_OK;
5992 }
5993
5994 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data);
5995
5996 static int cmd_dpipe_table_show(struct dl *dl)
5997 {
5998 struct nlmsghdr *nlh;
5999 struct dpipe_ctx dpipe_ctx = {};
6000 struct resource_ctx resource_ctx = {};
6001 uint16_t flags = NLM_F_REQUEST;
6002 int err;
6003
6004 err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
6005 if (err)
6006 return err;
6007
6008 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
6009
6010 err = dpipe_ctx_init(&dpipe_ctx, dl);
6011 if (err)
6012 return err;
6013
6014 dpipe_ctx.print_tables = true;
6015
6016 dl_opts_put(nlh, dl);
6017 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb,
6018 &dpipe_ctx);
6019 if (err) {
6020 pr_err("error get headers %s\n", strerror(dpipe_ctx.err));
6021 goto err_headers_get;
6022 }
6023
6024 err = resource_ctx_init(&resource_ctx, dl);
6025 if (err)
6026 goto err_resource_ctx_init;
6027
6028 resource_ctx.print_resources = false;
6029 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags);
6030 dl_opts_put(nlh, dl);
6031 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
6032 &resource_ctx);
6033 if (!err)
6034 dpipe_ctx.resources = resource_ctx.resources;
6035
6036 flags = NLM_F_REQUEST | NLM_F_ACK;
6037 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
6038 dl_opts_put(nlh, dl);
6039
6040 pr_out_section_start(dl, "table");
6041 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx);
6042 pr_out_section_end(dl);
6043
6044 resource_ctx_fini(&resource_ctx);
6045 dpipe_ctx_fini(&dpipe_ctx);
6046 return 0;
6047
6048 err_resource_ctx_init:
6049 err_headers_get:
6050 dpipe_ctx_fini(&dpipe_ctx);
6051 return err;
6052 }
6053
6054 static int cmd_dpipe_table_set(struct dl *dl)
6055 {
6056 struct nlmsghdr *nlh;
6057 int err;
6058
6059 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
6060 NLM_F_REQUEST | NLM_F_ACK);
6061
6062 err = dl_argv_parse_put(nlh, dl,
6063 DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
6064 DL_OPT_DPIPE_TABLE_COUNTERS, 0);
6065 if (err)
6066 return err;
6067
6068 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6069 }
6070
6071 enum dpipe_value_type {
6072 DPIPE_VALUE_TYPE_VALUE,
6073 DPIPE_VALUE_TYPE_MASK,
6074 };
6075
6076 static const char *
6077 dpipe_value_type_e2s(enum dpipe_value_type type)
6078 {
6079 switch (type) {
6080 case DPIPE_VALUE_TYPE_VALUE:
6081 return "value";
6082 case DPIPE_VALUE_TYPE_MASK:
6083 return "value_mask";
6084 default:
6085 return "<unknown>";
6086 }
6087 }
6088
6089 struct dpipe_field_printer {
6090 unsigned int field_id;
6091 void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
6092 };
6093
6094 struct dpipe_header_printer {
6095 struct dpipe_field_printer *printers;
6096 unsigned int printers_count;
6097 unsigned int header_id;
6098 };
6099
6100 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
6101 enum dpipe_value_type type,
6102 void *value)
6103 {
6104 struct in_addr ip_addr;
6105
6106 ip_addr.s_addr = htonl(*(uint32_t *)value);
6107 check_indent_newline(ctx->dl);
6108 print_string_name_value(dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
6109 }
6110
6111 static void
6112 dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
6113 enum dpipe_value_type type,
6114 void *value)
6115 {
6116 check_indent_newline(ctx->dl);
6117 print_string_name_value(dpipe_value_type_e2s(type),
6118 ether_ntoa((struct ether_addr *)value));
6119 }
6120
6121 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
6122 enum dpipe_value_type type,
6123 void *value)
6124 {
6125 char str[INET6_ADDRSTRLEN];
6126
6127 inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
6128 check_indent_newline(ctx->dl);
6129 print_string_name_value(dpipe_value_type_e2s(type), str);
6130 }
6131
6132 static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
6133 {
6134 .printer = dpipe_field_printer_ipv4_addr,
6135 .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
6136 }
6137 };
6138
6139 static struct dpipe_header_printer dpipe_header_printer_ipv4 = {
6140 .printers = dpipe_field_printers_ipv4,
6141 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
6142 .header_id = DEVLINK_DPIPE_HEADER_IPV4,
6143 };
6144
6145 static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
6146 {
6147 .printer = dpipe_field_printer_ethernet_addr,
6148 .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
6149 },
6150 };
6151
6152 static struct dpipe_header_printer dpipe_header_printer_ethernet = {
6153 .printers = dpipe_field_printers_ethernet,
6154 .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
6155 .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
6156 };
6157
6158 static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
6159 {
6160 .printer = dpipe_field_printer_ipv6_addr,
6161 .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
6162 }
6163 };
6164
6165 static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
6166 .printers = dpipe_field_printers_ipv6,
6167 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
6168 .header_id = DEVLINK_DPIPE_HEADER_IPV6,
6169 };
6170
6171 static struct dpipe_header_printer *dpipe_header_printers[] = {
6172 &dpipe_header_printer_ipv4,
6173 &dpipe_header_printer_ethernet,
6174 &dpipe_header_printer_ipv6,
6175 };
6176
6177 static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
6178 struct dpipe_op_info *info,
6179 enum dpipe_value_type type,
6180 void *value)
6181 {
6182 unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
6183 struct dpipe_header_printer *header_printer;
6184 struct dpipe_field_printer *field_printer;
6185 unsigned int field_printers_count;
6186 int j;
6187 int i;
6188
6189 for (i = 0; i < header_printers_count; i++) {
6190 header_printer = dpipe_header_printers[i];
6191 if (header_printer->header_id != info->header_id)
6192 continue;
6193 field_printers_count = header_printer->printers_count;
6194 for (j = 0; j < field_printers_count; j++) {
6195 field_printer = &header_printer->printers[j];
6196 if (field_printer->field_id != info->field_id)
6197 continue;
6198 field_printer->printer(ctx, type, value);
6199 return 0;
6200 }
6201 }
6202
6203 return -EINVAL;
6204 }
6205
6206 static void __pr_out_entry_value(struct dpipe_ctx *ctx,
6207 void *value,
6208 unsigned int value_len,
6209 struct dpipe_op_info *info,
6210 enum dpipe_value_type type)
6211 {
6212 if (info->header_global &&
6213 !dpipe_print_prot_header(ctx, info, type, value))
6214 return;
6215
6216 if (value_len == sizeof(uint32_t)) {
6217 uint32_t *value_32 = value;
6218
6219 check_indent_newline(ctx->dl);
6220 print_uint_name_value(dpipe_value_type_e2s(type), *value_32);
6221 }
6222 }
6223
6224 static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
6225 struct nlattr **nla_match_value,
6226 struct dpipe_op_info *info)
6227 {
6228 void *value, *value_mask;
6229 uint32_t value_mapping;
6230 uint16_t value_len;
6231 bool mask, mapping;
6232
6233 mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
6234 mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
6235
6236 value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
6237 value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
6238
6239 if (mapping) {
6240 value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
6241 check_indent_newline(ctx->dl);
6242 print_uint(PRINT_ANY, "mapping_value", "mapping_value %u", value_mapping);
6243 }
6244
6245 if (mask) {
6246 value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
6247 __pr_out_entry_value(ctx, value_mask, value_len, info,
6248 DPIPE_VALUE_TYPE_MASK);
6249 }
6250
6251 __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
6252 }
6253
6254 static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
6255 struct nlattr *nl)
6256 {
6257 struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
6258 struct dpipe_match match;
6259 int err;
6260
6261 err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
6262 if (err != MNL_CB_OK)
6263 return -EINVAL;
6264
6265 if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
6266 !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
6267 return -EINVAL;
6268 }
6269
6270 pr_out_entry_start(ctx->dl);
6271 if (dpipe_match_parse(&match,
6272 nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
6273 goto err_match_parse;
6274 pr_out_dpipe_match(&match, ctx);
6275 pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
6276 pr_out_entry_end(ctx->dl);
6277
6278 return 0;
6279
6280 err_match_parse:
6281 pr_out_entry_end(ctx->dl);
6282 return -EINVAL;
6283 }
6284
6285 static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
6286 struct nlattr *nl)
6287 {
6288 struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
6289 struct dpipe_action action;
6290 int err;
6291
6292 err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
6293 if (err != MNL_CB_OK)
6294 return -EINVAL;
6295
6296 if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
6297 !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
6298 return -EINVAL;
6299 }
6300
6301 pr_out_entry_start(ctx->dl);
6302 if (dpipe_action_parse(&action,
6303 nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
6304 goto err_action_parse;
6305 pr_out_dpipe_action(&action, ctx);
6306 pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
6307 pr_out_entry_end(ctx->dl);
6308
6309 return 0;
6310
6311 err_action_parse:
6312 pr_out_entry_end(ctx->dl);
6313 return -EINVAL;
6314 }
6315
6316 static int
6317 dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
6318 struct nlattr *nla_action_values)
6319 {
6320 struct nlattr *nla_action_value;
6321
6322 mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
6323 if (dpipe_entry_action_value_show(ctx, nla_action_value))
6324 return -EINVAL;
6325 }
6326 return 0;
6327 }
6328
6329 static int
6330 dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
6331 struct nlattr *nla_match_values)
6332 {
6333 struct nlattr *nla_match_value;
6334
6335 mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
6336 if (dpipe_entry_match_value_show(ctx, nla_match_value))
6337 return -EINVAL;
6338 }
6339 return 0;
6340 }
6341
6342 static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
6343 {
6344 struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
6345 uint32_t entry_index;
6346 uint64_t counter;
6347 int err;
6348
6349 err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
6350 if (err != MNL_CB_OK)
6351 return -EINVAL;
6352
6353 if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
6354 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
6355 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
6356 return -EINVAL;
6357 }
6358
6359 check_indent_newline(ctx->dl);
6360 entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
6361 print_uint(PRINT_ANY, "index", "index %u", entry_index);
6362
6363 if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
6364 counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
6365 print_uint(PRINT_ANY, "counter", " counter %u", counter);
6366 }
6367
6368 pr_out_array_start(ctx->dl, "match_value");
6369 if (dpipe_tables_match_values_show(ctx,
6370 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
6371 goto err_match_values_show;
6372 pr_out_array_end(ctx->dl);
6373
6374 pr_out_array_start(ctx->dl, "action_value");
6375 if (dpipe_tables_action_values_show(ctx,
6376 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
6377 goto err_action_values_show;
6378 pr_out_array_end(ctx->dl);
6379 return 0;
6380
6381 err_action_values_show:
6382 err_match_values_show:
6383 pr_out_array_end(ctx->dl);
6384 return -EINVAL;
6385 }
6386
6387 static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
6388 {
6389 struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
6390 struct nlattr *nla_entry;
6391
6392 mnl_attr_for_each_nested(nla_entry, nla_entries) {
6393 pr_out_handle_start_arr(ctx->dl, tb);
6394 if (dpipe_entry_show(ctx, nla_entry))
6395 goto err_entry_show;
6396 pr_out_handle_end(ctx->dl);
6397 }
6398 return 0;
6399
6400 err_entry_show:
6401 pr_out_handle_end(ctx->dl);
6402 return -EINVAL;
6403 }
6404
6405 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
6406 {
6407 struct dpipe_ctx *ctx = data;
6408 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6409 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6410
6411 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6412 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6413 !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
6414 return MNL_CB_ERROR;
6415
6416 if (dpipe_table_entries_show(ctx, tb))
6417 return MNL_CB_ERROR;
6418 return MNL_CB_OK;
6419 }
6420
6421 static int cmd_dpipe_table_dump(struct dl *dl)
6422 {
6423 struct nlmsghdr *nlh;
6424 struct dpipe_ctx ctx = {};
6425 uint16_t flags = NLM_F_REQUEST;
6426 int err;
6427
6428 err = dpipe_ctx_init(&ctx, dl);
6429 if (err)
6430 return err;
6431
6432 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
6433 if (err)
6434 goto out;
6435
6436 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
6437 dl_opts_put(nlh, dl);
6438 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
6439 if (err) {
6440 pr_err("error get headers %s\n", strerror(ctx.err));
6441 goto out;
6442 }
6443
6444 flags = NLM_F_REQUEST | NLM_F_ACK;
6445 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
6446 dl_opts_put(nlh, dl);
6447
6448 pr_out_section_start(dl, "table_entry");
6449 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx);
6450 pr_out_section_end(dl);
6451 out:
6452 dpipe_ctx_fini(&ctx);
6453 return err;
6454 }
6455
6456 static int cmd_dpipe_table(struct dl *dl)
6457 {
6458 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6459 cmd_dpipe_help();
6460 return 0;
6461 } else if (dl_argv_match(dl, "show")) {
6462 dl_arg_inc(dl);
6463 return cmd_dpipe_table_show(dl);
6464 } else if (dl_argv_match(dl, "set")) {
6465 dl_arg_inc(dl);
6466 return cmd_dpipe_table_set(dl);
6467 } else if (dl_argv_match(dl, "dump")) {
6468 dl_arg_inc(dl);
6469 return cmd_dpipe_table_dump(dl);
6470 }
6471 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6472 return -ENOENT;
6473 }
6474
6475 static int cmd_dpipe(struct dl *dl)
6476 {
6477 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6478 cmd_dpipe_help();
6479 return 0;
6480 } else if (dl_argv_match(dl, "header")) {
6481 dl_arg_inc(dl);
6482 return cmd_dpipe_header(dl);
6483 } else if (dl_argv_match(dl, "table")) {
6484 dl_arg_inc(dl);
6485 return cmd_dpipe_table(dl);
6486 }
6487 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6488 return -ENOENT;
6489 }
6490
6491 static int
6492 resource_parse(struct resource_ctx *ctx, struct resource *resource,
6493 struct nlattr **nla_resource)
6494 {
6495 if (!nla_resource[DEVLINK_ATTR_RESOURCE_NAME] ||
6496 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE] ||
6497 !nla_resource[DEVLINK_ATTR_RESOURCE_ID] ||
6498 !nla_resource[DEVLINK_ATTR_RESOURCE_UNIT] ||
6499 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN] ||
6500 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX] ||
6501 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]) {
6502 return -EINVAL;
6503 }
6504
6505 resource->name = strdup(mnl_attr_get_str(nla_resource[DEVLINK_ATTR_RESOURCE_NAME]));
6506 resource->size = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE]);
6507 resource->id = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_ID]);
6508 resource->unit = mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_UNIT]);
6509 resource->size_min = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN]);
6510 resource->size_max = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX]);
6511 resource->size_gran = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]);
6512
6513 if (nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW])
6514 resource->size_new = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW]);
6515 else
6516 resource->size_new = resource->size;
6517
6518 if (nla_resource[DEVLINK_ATTR_RESOURCE_OCC]) {
6519 resource->size_occ = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_OCC]);
6520 resource->occ_valid = true;
6521 }
6522
6523 if (resource->size_new != resource->size)
6524 ctx->pending_change = true;
6525
6526 return 0;
6527 }
6528
6529 static int
6530 resource_get(struct resource_ctx *ctx, struct resource *resource,
6531 struct resource *parent_resource, struct nlattr *nl)
6532 {
6533 struct nlattr *nla_resource[DEVLINK_ATTR_MAX + 1] = {};
6534 struct nlattr *nla_child_resource;
6535 struct nlattr *nla_resources;
6536 bool top = false;
6537 int err;
6538
6539 if (!resource) {
6540 nla_resources = nl;
6541 top = true;
6542 goto out;
6543 }
6544
6545 err = mnl_attr_parse_nested(nl, attr_cb, nla_resource);
6546 if (err != MNL_CB_OK)
6547 return -EINVAL;
6548
6549 err = resource_parse(ctx, resource, nla_resource);
6550 if (err)
6551 return err;
6552
6553 resource->parent = parent_resource;
6554 if (!nla_resource[DEVLINK_ATTR_RESOURCE_LIST])
6555 return 0;
6556
6557 resource->size_valid = !!mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_VALID]);
6558 nla_resources = nla_resource[DEVLINK_ATTR_RESOURCE_LIST];
6559 out:
6560 mnl_attr_for_each_nested(nla_child_resource, nla_resources) {
6561 struct resource *child_resource;
6562 struct list_head *list;
6563
6564 child_resource = resource_alloc();
6565 if (!child_resource)
6566 return -ENOMEM;
6567
6568 if (top)
6569 list = &ctx->resources->resource_list;
6570 else
6571 list = &resource->resource_list;
6572
6573 list_add_tail(&child_resource->list, list);
6574 err = resource_get(ctx, child_resource, resource,
6575 nla_child_resource);
6576 if (err)
6577 return err;
6578 }
6579
6580 return 0;
6581 }
6582
6583 static const char *resource_unit_str_get(enum devlink_resource_unit unit)
6584 {
6585 switch (unit) {
6586 case DEVLINK_RESOURCE_UNIT_ENTRY: return "entry";
6587 default: return "<unknown unit>";
6588 }
6589 }
6590
6591 static void resource_show(struct resource *resource,
6592 struct resource_ctx *ctx)
6593 {
6594 struct resource *child_resource;
6595 struct dpipe_table *table;
6596 struct dl *dl = ctx->dl;
6597 bool array = false;
6598
6599 check_indent_newline(dl);
6600 print_string(PRINT_ANY, "name", "name %s", resource->name);
6601 if (dl->verbose)
6602 resource_path_print(dl, ctx->resources, resource->id);
6603 pr_out_u64(dl, "size", resource->size);
6604 if (resource->size != resource->size_new)
6605 pr_out_u64(dl, "size_new", resource->size_new);
6606 if (resource->occ_valid)
6607 print_uint(PRINT_ANY, "occ", " occ %u", resource->size_occ);
6608 print_string(PRINT_ANY, "unit", " unit %s",
6609 resource_unit_str_get(resource->unit));
6610
6611 if (resource->size_min != resource->size_max) {
6612 print_uint(PRINT_ANY, "size_min", " size_min %u",
6613 resource->size_min);
6614 pr_out_u64(dl, "size_max", resource->size_max);
6615 print_uint(PRINT_ANY, "size_gran", " size_gran %u",
6616 resource->size_gran);
6617 }
6618
6619 list_for_each_entry(table, &ctx->tables->table_list, list)
6620 if (table->resource_id == resource->id &&
6621 table->resource_valid)
6622 array = true;
6623
6624 if (array)
6625 pr_out_array_start(dl, "dpipe_tables");
6626 else
6627 print_string(PRINT_ANY, "dpipe_tables", " dpipe_tables none",
6628 "none");
6629
6630 list_for_each_entry(table, &ctx->tables->table_list, list) {
6631 if (table->resource_id != resource->id ||
6632 !table->resource_valid)
6633 continue;
6634 pr_out_entry_start(dl);
6635 check_indent_newline(dl);
6636 print_string(PRINT_ANY, "table_name", "table_name %s",
6637 table->name);
6638 pr_out_entry_end(dl);
6639 }
6640 if (array)
6641 pr_out_array_end(dl);
6642
6643 if (list_empty(&resource->resource_list))
6644 return;
6645
6646 if (ctx->pending_change) {
6647 check_indent_newline(dl);
6648 print_string(PRINT_ANY, "size_valid", "size_valid %s",
6649 resource->size_valid ? "true" : "false");
6650 }
6651 pr_out_array_start(dl, "resources");
6652 list_for_each_entry(child_resource, &resource->resource_list, list) {
6653 pr_out_entry_start(dl);
6654 resource_show(child_resource, ctx);
6655 pr_out_entry_end(dl);
6656 }
6657 pr_out_array_end(dl);
6658 }
6659
6660 static void
6661 resources_show(struct resource_ctx *ctx, struct nlattr **tb)
6662 {
6663 struct resources *resources = ctx->resources;
6664 struct resource *resource;
6665
6666 list_for_each_entry(resource, &resources->resource_list, list) {
6667 pr_out_handle_start_arr(ctx->dl, tb);
6668 resource_show(resource, ctx);
6669 pr_out_handle_end(ctx->dl);
6670 }
6671 }
6672
6673 static int resources_get(struct resource_ctx *ctx, struct nlattr **tb)
6674 {
6675 return resource_get(ctx, NULL, NULL, tb[DEVLINK_ATTR_RESOURCE_LIST]);
6676 }
6677
6678 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data)
6679 {
6680 struct resource_ctx *ctx = data;
6681 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6682 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6683 int err;
6684
6685 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6686 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6687 !tb[DEVLINK_ATTR_RESOURCE_LIST])
6688 return MNL_CB_ERROR;
6689
6690 err = resources_get(ctx, tb);
6691 if (err) {
6692 ctx->err = err;
6693 return MNL_CB_ERROR;
6694 }
6695
6696 if (ctx->print_resources)
6697 resources_show(ctx, tb);
6698
6699 return MNL_CB_OK;
6700 }
6701
6702 static int cmd_resource_show(struct dl *dl)
6703 {
6704 struct nlmsghdr *nlh;
6705 struct dpipe_ctx dpipe_ctx = {};
6706 struct resource_ctx resource_ctx = {};
6707 int err;
6708
6709 err = dl_argv_parse(dl, DL_OPT_HANDLE, 0);
6710 if (err)
6711 return err;
6712
6713 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET,
6714 NLM_F_REQUEST);
6715 dl_opts_put(nlh, dl);
6716
6717 err = dpipe_ctx_init(&dpipe_ctx, dl);
6718 if (err)
6719 return err;
6720
6721 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb,
6722 &dpipe_ctx);
6723 if (err) {
6724 pr_err("error get tables %s\n", strerror(dpipe_ctx.err));
6725 goto out;
6726 }
6727
6728 err = resource_ctx_init(&resource_ctx, dl);
6729 if (err)
6730 goto out;
6731
6732 resource_ctx.print_resources = true;
6733 resource_ctx.tables = dpipe_ctx.tables;
6734 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6735 NLM_F_REQUEST | NLM_F_ACK);
6736 dl_opts_put(nlh, dl);
6737 pr_out_section_start(dl, "resources");
6738 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
6739 &resource_ctx);
6740 pr_out_section_end(dl);
6741 resource_ctx_fini(&resource_ctx);
6742 out:
6743 dpipe_ctx_fini(&dpipe_ctx);
6744 return err;
6745 }
6746
6747 static void cmd_resource_help(void)
6748 {
6749 pr_err("Usage: devlink resource show DEV\n"
6750 " devlink resource set DEV path PATH size SIZE\n");
6751 }
6752
6753 static struct resource *
6754 resource_find_by_name(struct list_head *list, char *name)
6755 {
6756 struct resource *resource;
6757
6758 list_for_each_entry(resource, list, list) {
6759 if (!strcmp(resource->name, name))
6760 return resource;
6761 }
6762 return NULL;
6763 }
6764
6765 static int
6766 resource_path_parse(struct resource_ctx *ctx, const char *resource_path,
6767 uint32_t *p_resource_id, bool *p_resource_valid)
6768 {
6769 struct resource *resource;
6770 uint32_t resource_id = 0;
6771 char *resource_path_dup;
6772 struct list_head *list;
6773 const char del[] = "/";
6774 char *resource_name;
6775
6776 resource_path_dup = strdup(resource_path);
6777 list = &ctx->resources->resource_list;
6778 resource_name = strtok(resource_path_dup, del);
6779 while (resource_name != NULL) {
6780 resource = resource_find_by_name(list, resource_name);
6781 if (!resource)
6782 goto err_resource_lookup;
6783
6784 list = &resource->resource_list;
6785 resource_name = strtok(NULL, del);
6786 resource_id = resource->id;
6787 }
6788 free(resource_path_dup);
6789 *p_resource_valid = true;
6790 *p_resource_id = resource_id;
6791 return 0;
6792
6793 err_resource_lookup:
6794 free(resource_path_dup);
6795 return -EINVAL;
6796 }
6797
6798 static int cmd_resource_set(struct dl *dl)
6799 {
6800 struct nlmsghdr *nlh;
6801 struct resource_ctx ctx = {};
6802 int err;
6803
6804 err = resource_ctx_init(&ctx, dl);
6805 if (err)
6806 return err;
6807
6808 ctx.print_resources = false;
6809 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_RESOURCE_PATH |
6810 DL_OPT_RESOURCE_SIZE, 0);
6811 if (err)
6812 goto out;
6813
6814 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6815 NLM_F_REQUEST);
6816 dl_opts_put(nlh, dl);
6817 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, &ctx);
6818 if (err) {
6819 pr_err("error getting resources %s\n", strerror(ctx.err));
6820 goto out;
6821 }
6822
6823 err = resource_path_parse(&ctx, dl->opts.resource_path,
6824 &dl->opts.resource_id,
6825 &dl->opts.resource_id_valid);
6826 if (err) {
6827 pr_err("error parsing resource path %s\n", strerror(-err));
6828 goto out;
6829 }
6830
6831 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_SET,
6832 NLM_F_REQUEST | NLM_F_ACK);
6833
6834 dl_opts_put(nlh, dl);
6835 err = _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6836 out:
6837 resource_ctx_fini(&ctx);
6838 return err;
6839 }
6840
6841 static int cmd_resource(struct dl *dl)
6842 {
6843 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6844 cmd_resource_help();
6845 return 0;
6846 } else if (dl_argv_match(dl, "show")) {
6847 dl_arg_inc(dl);
6848 return cmd_resource_show(dl);
6849 } else if (dl_argv_match(dl, "set")) {
6850 dl_arg_inc(dl);
6851 return cmd_resource_set(dl);
6852 }
6853 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6854 return -ENOENT;
6855 }
6856
6857 static void pr_out_region_handle_start(struct dl *dl, struct nlattr **tb)
6858 {
6859 const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
6860 const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
6861 const char *region_name = mnl_attr_get_str(tb[DEVLINK_ATTR_REGION_NAME]);
6862 char buf[256];
6863
6864 sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name);
6865 if (dl->json_output)
6866 open_json_object(buf);
6867 else
6868 pr_out("%s:", buf);
6869 }
6870
6871 static void pr_out_region_handle_end(struct dl *dl)
6872 {
6873 if (dl->json_output)
6874 close_json_object();
6875 else
6876 pr_out("\n");
6877 }
6878
6879 static void pr_out_region_snapshots_start(struct dl *dl, bool array)
6880 {
6881 __pr_out_indent_newline(dl);
6882 if (dl->json_output)
6883 open_json_array(PRINT_JSON, "snapshot");
6884 else
6885 pr_out("snapshot %s", array ? "[" : "");
6886 }
6887
6888 static void pr_out_region_snapshots_end(struct dl *dl, bool array)
6889 {
6890 if (dl->json_output)
6891 close_json_array(PRINT_JSON, NULL);
6892 else if (array)
6893 pr_out("]");
6894 }
6895
6896 static void pr_out_region_snapshots_id(struct dl *dl, struct nlattr **tb, int index)
6897 {
6898 uint32_t snapshot_id;
6899
6900 if (!tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6901 return;
6902
6903 snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
6904
6905 if (dl->json_output)
6906 print_uint(PRINT_JSON, NULL, NULL, snapshot_id);
6907 else
6908 pr_out("%s%u", index ? " " : "", snapshot_id);
6909 }
6910
6911 static void pr_out_snapshots(struct dl *dl, struct nlattr **tb)
6912 {
6913 struct nlattr *tb_snapshot[DEVLINK_ATTR_MAX + 1] = {};
6914 struct nlattr *nla_sanpshot;
6915 int err, index = 0;
6916
6917 pr_out_region_snapshots_start(dl, true);
6918 mnl_attr_for_each_nested(nla_sanpshot, tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) {
6919 err = mnl_attr_parse_nested(nla_sanpshot, attr_cb, tb_snapshot);
6920 if (err != MNL_CB_OK)
6921 return;
6922 pr_out_region_snapshots_id(dl, tb_snapshot, index++);
6923 }
6924 pr_out_region_snapshots_end(dl, true);
6925 }
6926
6927 static void pr_out_snapshot(struct dl *dl, struct nlattr **tb)
6928 {
6929 pr_out_region_snapshots_start(dl, false);
6930 pr_out_region_snapshots_id(dl, tb, 0);
6931 pr_out_region_snapshots_end(dl, false);
6932 }
6933
6934 static void pr_out_region(struct dl *dl, struct nlattr **tb)
6935 {
6936 pr_out_region_handle_start(dl, tb);
6937
6938 if (tb[DEVLINK_ATTR_REGION_SIZE])
6939 pr_out_u64(dl, "size",
6940 mnl_attr_get_u64(tb[DEVLINK_ATTR_REGION_SIZE]));
6941
6942 if (tb[DEVLINK_ATTR_REGION_SNAPSHOTS])
6943 pr_out_snapshots(dl, tb);
6944
6945 if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6946 pr_out_snapshot(dl, tb);
6947
6948 pr_out_region_handle_end(dl);
6949 }
6950
6951 static int cmd_region_show_cb(const struct nlmsghdr *nlh, void *data)
6952 {
6953 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6954 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6955 struct dl *dl = data;
6956
6957 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6958 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6959 !tb[DEVLINK_ATTR_REGION_NAME] || !tb[DEVLINK_ATTR_REGION_SIZE])
6960 return MNL_CB_ERROR;
6961
6962 pr_out_region(dl, tb);
6963
6964 return MNL_CB_OK;
6965 }
6966
6967 static int cmd_region_show(struct dl *dl)
6968 {
6969 struct nlmsghdr *nlh;
6970 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6971 int err;
6972
6973 if (dl_argc(dl) == 0)
6974 flags |= NLM_F_DUMP;
6975
6976 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_GET, flags);
6977
6978 if (dl_argc(dl) > 0) {
6979 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0);
6980 if (err)
6981 return err;
6982 }
6983
6984 pr_out_section_start(dl, "regions");
6985 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_show_cb, dl);
6986 pr_out_section_end(dl);
6987 return err;
6988 }
6989
6990 static int cmd_region_snapshot_del(struct dl *dl)
6991 {
6992 struct nlmsghdr *nlh;
6993 int err;
6994
6995 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_DEL,
6996 NLM_F_REQUEST | NLM_F_ACK);
6997
6998 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6999 DL_OPT_REGION_SNAPSHOT_ID, 0);
7000 if (err)
7001 return err;
7002
7003 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7004 }
7005
7006 static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data)
7007 {
7008 struct nlattr *nla_entry, *nla_chunk_data, *nla_chunk_addr;
7009 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7010 struct nlattr *tb_field[DEVLINK_ATTR_MAX + 1] = {};
7011 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7012 struct dl *dl = data;
7013 int err;
7014
7015 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7016 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7017 !tb[DEVLINK_ATTR_REGION_CHUNKS])
7018 return MNL_CB_ERROR;
7019
7020 mnl_attr_for_each_nested(nla_entry, tb[DEVLINK_ATTR_REGION_CHUNKS]) {
7021 err = mnl_attr_parse_nested(nla_entry, attr_cb, tb_field);
7022 if (err != MNL_CB_OK)
7023 return MNL_CB_ERROR;
7024
7025 nla_chunk_data = tb_field[DEVLINK_ATTR_REGION_CHUNK_DATA];
7026 if (!nla_chunk_data)
7027 continue;
7028
7029 nla_chunk_addr = tb_field[DEVLINK_ATTR_REGION_CHUNK_ADDR];
7030 if (!nla_chunk_addr)
7031 continue;
7032
7033 pr_out_region_chunk(dl, mnl_attr_get_payload(nla_chunk_data),
7034 mnl_attr_get_payload_len(nla_chunk_data),
7035 mnl_attr_get_u64(nla_chunk_addr));
7036 }
7037 return MNL_CB_OK;
7038 }
7039
7040 static int cmd_region_dump(struct dl *dl)
7041 {
7042 struct nlmsghdr *nlh;
7043 int err;
7044
7045 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
7046 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
7047
7048 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
7049 DL_OPT_REGION_SNAPSHOT_ID, 0);
7050 if (err)
7051 return err;
7052
7053 pr_out_section_start(dl, "dump");
7054 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
7055 pr_out_section_end(dl);
7056 if (!dl->json_output)
7057 pr_out("\n");
7058 return err;
7059 }
7060
7061 static int cmd_region_read(struct dl *dl)
7062 {
7063 struct nlmsghdr *nlh;
7064 int err;
7065
7066 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
7067 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
7068
7069 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
7070 DL_OPT_REGION_ADDRESS | DL_OPT_REGION_LENGTH |
7071 DL_OPT_REGION_SNAPSHOT_ID, 0);
7072 if (err)
7073 return err;
7074
7075 pr_out_section_start(dl, "read");
7076 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
7077 pr_out_section_end(dl);
7078 if (!dl->json_output)
7079 pr_out("\n");
7080 return err;
7081 }
7082
7083 static int cmd_region_snapshot_new_cb(const struct nlmsghdr *nlh, void *data)
7084 {
7085 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7086 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7087 struct dl *dl = data;
7088
7089 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7090 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7091 !tb[DEVLINK_ATTR_REGION_NAME] ||
7092 !tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
7093 return MNL_CB_ERROR;
7094
7095 pr_out_region(dl, tb);
7096
7097 return MNL_CB_OK;
7098 }
7099
7100 static int cmd_region_snapshot_new(struct dl *dl)
7101 {
7102 struct nlmsghdr *nlh;
7103 int err;
7104
7105 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_NEW,
7106 NLM_F_REQUEST | NLM_F_ACK);
7107
7108 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION,
7109 DL_OPT_REGION_SNAPSHOT_ID);
7110 if (err)
7111 return err;
7112
7113 pr_out_section_start(dl, "regions");
7114 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_snapshot_new_cb, dl);
7115 pr_out_section_end(dl);
7116 return err;
7117 }
7118
7119 static void cmd_region_help(void)
7120 {
7121 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
7122 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
7123 pr_err(" devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
7124 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
7125 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
7126 }
7127
7128 static int cmd_region(struct dl *dl)
7129 {
7130 if (dl_no_arg(dl)) {
7131 return cmd_region_show(dl);
7132 } else if (dl_argv_match(dl, "help")) {
7133 cmd_region_help();
7134 return 0;
7135 } else if (dl_argv_match(dl, "show")) {
7136 dl_arg_inc(dl);
7137 return cmd_region_show(dl);
7138 } else if (dl_argv_match(dl, "del")) {
7139 dl_arg_inc(dl);
7140 return cmd_region_snapshot_del(dl);
7141 } else if (dl_argv_match(dl, "dump")) {
7142 dl_arg_inc(dl);
7143 return cmd_region_dump(dl);
7144 } else if (dl_argv_match(dl, "read")) {
7145 dl_arg_inc(dl);
7146 return cmd_region_read(dl);
7147 } else if (dl_argv_match(dl, "new")) {
7148 dl_arg_inc(dl);
7149 return cmd_region_snapshot_new(dl);
7150 }
7151 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7152 return -ENOENT;
7153 }
7154
7155 static int cmd_health_set_params(struct dl *dl)
7156 {
7157 struct nlmsghdr *nlh;
7158 int err;
7159
7160 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET,
7161 NLM_F_REQUEST | NLM_F_ACK);
7162 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP | DL_OPT_HEALTH_REPORTER_NAME,
7163 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD |
7164 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER |
7165 DL_OPT_HEALTH_REPORTER_AUTO_DUMP);
7166 if (err)
7167 return err;
7168
7169 dl_opts_put(nlh, dl);
7170 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7171 }
7172
7173 static int cmd_health_dump_clear(struct dl *dl)
7174 {
7175 struct nlmsghdr *nlh;
7176 int err;
7177
7178 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
7179 NLM_F_REQUEST | NLM_F_ACK);
7180
7181 err = dl_argv_parse_put(nlh, dl,
7182 DL_OPT_HANDLE | DL_OPT_HANDLEP |
7183 DL_OPT_HEALTH_REPORTER_NAME, 0);
7184 if (err)
7185 return err;
7186
7187 dl_opts_put(nlh, dl);
7188 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7189 }
7190
7191 static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
7192 {
7193 uint8_t *data;
7194 uint32_t len;
7195
7196 check_indent_newline(dl);
7197 switch (type) {
7198 case MNL_TYPE_FLAG:
7199 print_bool(PRINT_ANY, NULL, "%s", mnl_attr_get_u8(nl_data));
7200 break;
7201 case MNL_TYPE_U8:
7202 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u8(nl_data));
7203 break;
7204 case MNL_TYPE_U16:
7205 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u16(nl_data));
7206 break;
7207 case MNL_TYPE_U32:
7208 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u32(nl_data));
7209 break;
7210 case MNL_TYPE_U64:
7211 print_u64(PRINT_ANY, NULL, "%"PRIu64, mnl_attr_get_u64(nl_data));
7212 break;
7213 case MNL_TYPE_NUL_STRING:
7214 print_string(PRINT_ANY, NULL, "%s", mnl_attr_get_str(nl_data));
7215 break;
7216 case MNL_TYPE_BINARY:
7217 len = mnl_attr_get_payload_len(nl_data);
7218 data = mnl_attr_get_payload(nl_data);
7219 pr_out_binary_value(dl, data, len);
7220 break;
7221 default:
7222 return -EINVAL;
7223 }
7224 return MNL_CB_OK;
7225 }
7226
7227 static void pr_out_fmsg_name(struct dl *dl, char **name)
7228 {
7229 if (!*name)
7230 return;
7231
7232 pr_out_name(dl, *name);
7233 free(*name);
7234 *name = NULL;
7235 }
7236
7237 struct nest_entry {
7238 int attr_type;
7239 struct list_head list;
7240 };
7241
7242 struct fmsg_cb_data {
7243 char *name;
7244 struct dl *dl;
7245 uint8_t value_type;
7246 struct list_head entry_list;
7247 };
7248
7249 static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
7250 uint8_t *attr_value, bool insert)
7251 {
7252 struct nest_entry *entry;
7253
7254 if (insert) {
7255 entry = malloc(sizeof(struct nest_entry));
7256 if (!entry)
7257 return -ENOMEM;
7258
7259 entry->attr_type = *attr_value;
7260 list_add(&entry->list, &fmsg_data->entry_list);
7261 } else {
7262 if (list_empty(&fmsg_data->entry_list))
7263 return MNL_CB_ERROR;
7264 entry = list_first_entry(&fmsg_data->entry_list,
7265 struct nest_entry, list);
7266 *attr_value = entry->attr_type;
7267 list_del(&entry->list);
7268 free(entry);
7269 }
7270 return MNL_CB_OK;
7271 }
7272
7273 static void pr_out_fmsg_group_start(struct dl *dl, char **name)
7274 {
7275 __pr_out_newline();
7276 pr_out_fmsg_name(dl, name);
7277 __pr_out_newline();
7278 __pr_out_indent_inc();
7279 }
7280
7281 static void pr_out_fmsg_group_end(struct dl *dl)
7282 {
7283 __pr_out_newline();
7284 __pr_out_indent_dec();
7285 }
7286
7287 static void pr_out_fmsg_start_object(struct dl *dl, char **name)
7288 {
7289 if (dl->json_output) {
7290 pr_out_fmsg_name(dl, name);
7291 open_json_object(NULL);
7292 } else {
7293 pr_out_fmsg_group_start(dl, name);
7294 }
7295 }
7296
7297 static void pr_out_fmsg_end_object(struct dl *dl)
7298 {
7299 if (dl->json_output)
7300 close_json_object();
7301 else
7302 pr_out_fmsg_group_end(dl);
7303 }
7304
7305 static void pr_out_fmsg_start_array(struct dl *dl, char **name)
7306 {
7307 if (dl->json_output) {
7308 pr_out_fmsg_name(dl, name);
7309 open_json_array(PRINT_JSON, NULL);
7310 } else {
7311 pr_out_fmsg_group_start(dl, name);
7312 }
7313 }
7314
7315 static void pr_out_fmsg_end_array(struct dl *dl)
7316 {
7317 if (dl->json_output)
7318 close_json_array(PRINT_JSON, NULL);
7319 else
7320 pr_out_fmsg_group_end(dl);
7321 }
7322
7323 static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value,
7324 bool start)
7325 {
7326 struct dl *dl = fmsg_data->dl;
7327 uint8_t value = nest_value;
7328 int err;
7329
7330 err = cmd_fmsg_nest_queue(fmsg_data, &value, start);
7331 if (err != MNL_CB_OK)
7332 return err;
7333
7334 switch (value) {
7335 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
7336 if (start)
7337 pr_out_fmsg_start_object(dl, &fmsg_data->name);
7338 else
7339 pr_out_fmsg_end_object(dl);
7340 break;
7341 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
7342 break;
7343 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
7344 if (start)
7345 pr_out_fmsg_start_array(dl, &fmsg_data->name);
7346 else
7347 pr_out_fmsg_end_array(dl);
7348 break;
7349 default:
7350 return -EINVAL;
7351 }
7352 return MNL_CB_OK;
7353 }
7354
7355 static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data)
7356 {
7357 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7358 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7359 struct fmsg_cb_data *fmsg_data = data;
7360 struct dl *dl = fmsg_data->dl;
7361 struct nlattr *nla_object;
7362 int attr_type;
7363 int err;
7364
7365 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7366 if (!tb[DEVLINK_ATTR_FMSG])
7367 return MNL_CB_ERROR;
7368
7369 mnl_attr_for_each_nested(nla_object, tb[DEVLINK_ATTR_FMSG]) {
7370 attr_type = mnl_attr_get_type(nla_object);
7371 switch (attr_type) {
7372 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
7373 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
7374 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
7375 err = cmd_fmsg_nest(fmsg_data, attr_type, true);
7376 if (err != MNL_CB_OK)
7377 return err;
7378 break;
7379 case DEVLINK_ATTR_FMSG_NEST_END:
7380 err = cmd_fmsg_nest(fmsg_data, attr_type, false);
7381 if (err != MNL_CB_OK)
7382 return err;
7383 break;
7384 case DEVLINK_ATTR_FMSG_OBJ_NAME:
7385 free(fmsg_data->name);
7386 fmsg_data->name = strdup(mnl_attr_get_str(nla_object));
7387 if (!fmsg_data->name)
7388 return -ENOMEM;
7389 break;
7390 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE:
7391 fmsg_data->value_type = mnl_attr_get_u8(nla_object);
7392 break;
7393 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
7394 pr_out_fmsg_name(dl, &fmsg_data->name);
7395 err = fmsg_value_show(dl, fmsg_data->value_type,
7396 nla_object);
7397 if (err != MNL_CB_OK)
7398 return err;
7399 break;
7400 default:
7401 return -EINVAL;
7402 }
7403 }
7404 return MNL_CB_OK;
7405 }
7406
7407 static void cmd_fmsg_init(struct dl *dl, struct fmsg_cb_data *data)
7408 {
7409 /* FMSG is dynamic: opening of an object or array causes a
7410 * newline. JSON starts with an { or [, but plain text should
7411 * not start with a new line. Ensure this by setting
7412 * g_new_line_count to 1: avoiding newline before the first
7413 * print.
7414 */
7415 g_new_line_count = 1;
7416 data->name = NULL;
7417 data->dl = dl;
7418 INIT_LIST_HEAD(&data->entry_list);
7419 }
7420
7421 static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
7422 {
7423 struct fmsg_cb_data data;
7424 struct nlmsghdr *nlh;
7425 int err;
7426
7427 nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
7428
7429 err = dl_argv_parse_put(nlh, dl,
7430 DL_OPT_HANDLE | DL_OPT_HANDLEP |
7431 DL_OPT_HEALTH_REPORTER_NAME, 0);
7432 if (err)
7433 return err;
7434
7435 cmd_fmsg_init(dl, &data);
7436 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data);
7437 free(data.name);
7438 return err;
7439 }
7440
7441 static int cmd_health_dump_show(struct dl *dl)
7442 {
7443 return cmd_health_object_common(dl,
7444 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
7445 NLM_F_DUMP);
7446 }
7447
7448 static int cmd_health_diagnose(struct dl *dl)
7449 {
7450 return cmd_health_object_common(dl,
7451 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
7452 0);
7453 }
7454
7455 static int cmd_health_test(struct dl *dl)
7456 {
7457 return cmd_health_object_common(dl,
7458 DEVLINK_CMD_HEALTH_REPORTER_TEST,
7459 0);
7460 }
7461
7462 static int cmd_health_recover(struct dl *dl)
7463 {
7464 struct nlmsghdr *nlh;
7465 int err;
7466
7467 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
7468 NLM_F_REQUEST | NLM_F_ACK);
7469
7470 err = dl_argv_parse_put(nlh, dl,
7471 DL_OPT_HANDLE | DL_OPT_HANDLEP |
7472 DL_OPT_HEALTH_REPORTER_NAME, 0);
7473 if (err)
7474 return err;
7475
7476 dl_opts_put(nlh, dl);
7477 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7478 }
7479
7480 enum devlink_health_reporter_state {
7481 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
7482 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
7483 };
7484
7485 static const char *health_state_name(uint8_t state)
7486 {
7487 switch (state) {
7488 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY:
7489 return HEALTH_REPORTER_STATE_HEALTHY_STR;
7490 case DEVLINK_HEALTH_REPORTER_STATE_ERROR:
7491 return HEALTH_REPORTER_STATE_ERROR_STR;
7492 default:
7493 return "<unknown state>";
7494 }
7495 }
7496
7497 static void pr_out_dump_reporter_format_logtime(struct dl *dl, const struct nlattr *attr)
7498 {
7499 char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7500 char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7501 uint64_t time_ms = mnl_attr_get_u64(attr);
7502 struct sysinfo s_info;
7503 struct tm *info;
7504 time_t now, sec;
7505 int err;
7506
7507 time(&now);
7508 info = localtime(&now);
7509 err = sysinfo(&s_info);
7510 if (err)
7511 goto out;
7512 /* Subtract uptime in sec from now yields the time of system
7513 * uptime. To this, add time_ms which is the amount of
7514 * milliseconds elapsed between uptime and the dump taken.
7515 */
7516 sec = now - s_info.uptime + time_ms / 1000;
7517 info = localtime(&sec);
7518 out:
7519 strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
7520 strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
7521 check_indent_newline(dl);
7522 print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
7523 print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
7524 }
7525
7526 static void pr_out_dump_report_timestamp(struct dl *dl, const struct nlattr *attr)
7527 {
7528 char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7529 char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7530 time_t tv_sec;
7531 struct tm *tm;
7532 uint64_t ts;
7533
7534 ts = mnl_attr_get_u64(attr);
7535 tv_sec = ts / 1000000000;
7536 tm = localtime(&tv_sec);
7537
7538 strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", tm);
7539 strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", tm);
7540
7541 check_indent_newline(dl);
7542 print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
7543 print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
7544 }
7545
7546 static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
7547 bool print_device, bool print_port)
7548 {
7549 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7550 enum devlink_health_reporter_state state;
7551 int err;
7552
7553 err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER],
7554 attr_cb, tb);
7555 if (err != MNL_CB_OK)
7556 return;
7557
7558 if (!tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME] ||
7559 !tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] ||
7560 !tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] ||
7561 !tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE])
7562 return;
7563
7564 if (!print_device && !print_port)
7565 return;
7566 if (print_port) {
7567 if (!print_device && !tb_health[DEVLINK_ATTR_PORT_INDEX])
7568 return;
7569 else if (tb_health[DEVLINK_ATTR_PORT_INDEX])
7570 pr_out_port_handle_start_arr(dl, tb_health, false);
7571 }
7572 if (print_device) {
7573 if (!print_port && tb_health[DEVLINK_ATTR_PORT_INDEX])
7574 return;
7575 else if (!tb_health[DEVLINK_ATTR_PORT_INDEX])
7576 pr_out_handle_start_arr(dl, tb_health);
7577 }
7578
7579 check_indent_newline(dl);
7580 print_string(PRINT_ANY, "reporter", "reporter %s",
7581 mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
7582 if (!dl->json_output) {
7583 __pr_out_newline();
7584 __pr_out_indent_inc();
7585 }
7586 state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]);
7587 check_indent_newline(dl);
7588 print_string(PRINT_ANY, "state", "state %s", health_state_name(state));
7589 pr_out_u64(dl, "error",
7590 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT]));
7591 pr_out_u64(dl, "recover",
7592 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT]));
7593 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS])
7594 pr_out_dump_report_timestamp(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]);
7595 else if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS])
7596 pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]);
7597 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
7598 pr_out_u64(dl, "grace_period",
7599 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]));
7600 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
7601 print_bool(PRINT_ANY, "auto_recover", " auto_recover %s",
7602 mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]));
7603 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
7604 print_bool(PRINT_ANY, "auto_dump", " auto_dump %s",
7605 mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]));
7606
7607 __pr_out_indent_dec();
7608 pr_out_handle_end(dl);
7609 }
7610
7611 struct health_ctx {
7612 struct dl *dl;
7613 bool show_device;
7614 bool show_port;
7615 };
7616
7617 static int cmd_health_show_cb(const struct nlmsghdr *nlh, void *data)
7618 {
7619 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7620 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7621 struct health_ctx *ctx = data;
7622 struct dl *dl = ctx->dl;
7623
7624 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7625 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7626 !tb[DEVLINK_ATTR_HEALTH_REPORTER])
7627 return MNL_CB_ERROR;
7628
7629 pr_out_health(dl, tb, ctx->show_device, ctx->show_port);
7630
7631 return MNL_CB_OK;
7632 }
7633
7634 static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port)
7635 {
7636 struct nlmsghdr *nlh;
7637 struct health_ctx ctx = { dl, show_device, show_port };
7638 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7639 int err;
7640
7641 if (dl_argc(dl) == 0)
7642 flags |= NLM_F_DUMP;
7643 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET,
7644 flags);
7645
7646 if (dl_argc(dl) > 0) {
7647 ctx.show_port = true;
7648 err = dl_argv_parse_put(nlh, dl,
7649 DL_OPT_HANDLE | DL_OPT_HANDLEP |
7650 DL_OPT_HEALTH_REPORTER_NAME, 0);
7651 if (err)
7652 return err;
7653 }
7654 pr_out_section_start(dl, "health");
7655
7656 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_health_show_cb, &ctx);
7657 pr_out_section_end(dl);
7658 return err;
7659 }
7660
7661 static void cmd_health_help(void)
7662 {
7663 pr_err("Usage: devlink health show [ { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME ]\n");
7664 pr_err(" devlink health recover { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7665 pr_err(" devlink health diagnose { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7666 pr_err(" devlink health test { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7667 pr_err(" devlink health dump show { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7668 pr_err(" devlink health dump clear { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7669 pr_err(" devlink health set { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7670 pr_err(" [ grace_period MSEC ]\n");
7671 pr_err(" [ auto_recover { true | false } ]\n");
7672 pr_err(" [ auto_dump { true | false } ]\n");
7673 }
7674
7675 static int cmd_health(struct dl *dl)
7676 {
7677 if (dl_argv_match(dl, "help")) {
7678 cmd_health_help();
7679 return 0;
7680 } else if (dl_argv_match(dl, "show") ||
7681 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7682 dl_arg_inc(dl);
7683 return __cmd_health_show(dl, true, true);
7684 } else if (dl_argv_match(dl, "recover")) {
7685 dl_arg_inc(dl);
7686 return cmd_health_recover(dl);
7687 } else if (dl_argv_match(dl, "diagnose")) {
7688 dl_arg_inc(dl);
7689 return cmd_health_diagnose(dl);
7690 } else if (dl_argv_match(dl, "test")) {
7691 dl_arg_inc(dl);
7692 return cmd_health_test(dl);
7693 } else if (dl_argv_match(dl, "dump")) {
7694 dl_arg_inc(dl);
7695 if (dl_argv_match(dl, "show")) {
7696 dl_arg_inc(dl);
7697 return cmd_health_dump_show(dl);
7698 } else if (dl_argv_match(dl, "clear")) {
7699 dl_arg_inc(dl);
7700 return cmd_health_dump_clear(dl);
7701 }
7702 } else if (dl_argv_match(dl, "set")) {
7703 dl_arg_inc(dl);
7704 return cmd_health_set_params(dl);
7705 }
7706 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7707 return -ENOENT;
7708 }
7709
7710 static const char *trap_type_name(uint8_t type)
7711 {
7712 switch (type) {
7713 case DEVLINK_TRAP_TYPE_DROP:
7714 return "drop";
7715 case DEVLINK_TRAP_TYPE_EXCEPTION:
7716 return "exception";
7717 case DEVLINK_TRAP_TYPE_CONTROL:
7718 return "control";
7719 default:
7720 return "<unknown type>";
7721 }
7722 }
7723
7724 static const char *trap_action_name(uint8_t action)
7725 {
7726 switch (action) {
7727 case DEVLINK_TRAP_ACTION_DROP:
7728 return "drop";
7729 case DEVLINK_TRAP_ACTION_TRAP:
7730 return "trap";
7731 case DEVLINK_TRAP_ACTION_MIRROR:
7732 return "mirror";
7733 default:
7734 return "<unknown action>";
7735 }
7736 }
7737
7738 static const char *trap_metadata_name(const struct nlattr *attr)
7739 {
7740 switch (attr->nla_type) {
7741 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT:
7742 return "input_port";
7743 case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE:
7744 return "flow_action_cookie";
7745 default:
7746 return "<unknown metadata type>";
7747 }
7748 }
7749 static void pr_out_trap_metadata(struct dl *dl, struct nlattr *attr)
7750 {
7751 struct nlattr *attr_metadata;
7752
7753 pr_out_array_start(dl, "metadata");
7754 mnl_attr_for_each_nested(attr_metadata, attr) {
7755 check_indent_newline(dl);
7756 print_string(PRINT_ANY, NULL, "%s",
7757 trap_metadata_name(attr_metadata));
7758 }
7759 pr_out_array_end(dl);
7760 }
7761
7762 static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array)
7763 {
7764 uint8_t action = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_ACTION]);
7765 uint8_t type = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_TYPE]);
7766
7767 if (array)
7768 pr_out_handle_start_arr(dl, tb);
7769 else
7770 __pr_out_handle_start(dl, tb, true, false);
7771
7772 check_indent_newline(dl);
7773 print_string(PRINT_ANY, "name", "name %s",
7774 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_NAME]));
7775 print_string(PRINT_ANY, "type", " type %s", trap_type_name(type));
7776 print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
7777 print_string(PRINT_ANY, "action", " action %s", trap_action_name(action));
7778 print_string(PRINT_ANY, "group", " group %s",
7779 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
7780 if (dl->verbose)
7781 pr_out_trap_metadata(dl, tb[DEVLINK_ATTR_TRAP_METADATA]);
7782 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7783 pr_out_handle_end(dl);
7784 }
7785
7786 static int cmd_trap_show_cb(const struct nlmsghdr *nlh, void *data)
7787 {
7788 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7789 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7790 struct dl *dl = data;
7791
7792 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7793 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7794 !tb[DEVLINK_ATTR_TRAP_NAME] || !tb[DEVLINK_ATTR_TRAP_TYPE] ||
7795 !tb[DEVLINK_ATTR_TRAP_ACTION] ||
7796 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
7797 !tb[DEVLINK_ATTR_TRAP_METADATA] || !tb[DEVLINK_ATTR_STATS])
7798 return MNL_CB_ERROR;
7799
7800 pr_out_trap(dl, tb, true);
7801
7802 return MNL_CB_OK;
7803 }
7804
7805 static void cmd_trap_help(void)
7806 {
7807 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop | mirror } ]\n");
7808 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
7809 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop | mirror } ]\n");
7810 pr_err(" [ policer POLICER ] [ nopolicer ]\n");
7811 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
7812 pr_err(" devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
7813 pr_err(" devlink trap policer show DEV policer POLICER\n");
7814 }
7815
7816 static int cmd_trap_show(struct dl *dl)
7817 {
7818 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7819 struct nlmsghdr *nlh;
7820 int err;
7821
7822 if (dl_argc(dl) == 0)
7823 flags |= NLM_F_DUMP;
7824
7825 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GET, flags);
7826
7827 if (dl_argc(dl) > 0) {
7828 err = dl_argv_parse_put(nlh, dl,
7829 DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0);
7830 if (err)
7831 return err;
7832 }
7833
7834 pr_out_section_start(dl, "trap");
7835 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_show_cb, dl);
7836 pr_out_section_end(dl);
7837
7838 return err;
7839 }
7840
7841 static int cmd_trap_set(struct dl *dl)
7842 {
7843 struct nlmsghdr *nlh;
7844 int err;
7845
7846 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_SET,
7847 NLM_F_REQUEST | NLM_F_ACK);
7848
7849 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME,
7850 DL_OPT_TRAP_ACTION);
7851 if (err)
7852 return err;
7853
7854 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7855 }
7856
7857 static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array)
7858 {
7859 if (array)
7860 pr_out_handle_start_arr(dl, tb);
7861 else
7862 __pr_out_handle_start(dl, tb, true, false);
7863
7864 check_indent_newline(dl);
7865 print_string(PRINT_ANY, "name", "name %s",
7866 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
7867 print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
7868 if (tb[DEVLINK_ATTR_TRAP_POLICER_ID])
7869 print_uint(PRINT_ANY, "policer", " policer %u",
7870 mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
7871 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7872 pr_out_handle_end(dl);
7873 }
7874
7875 static int cmd_trap_group_show_cb(const struct nlmsghdr *nlh, void *data)
7876 {
7877 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7878 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7879 struct dl *dl = data;
7880
7881 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7882 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7883 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] || !tb[DEVLINK_ATTR_STATS])
7884 return MNL_CB_ERROR;
7885
7886 pr_out_trap_group(dl, tb, true);
7887
7888 return MNL_CB_OK;
7889 }
7890
7891 static int cmd_trap_group_show(struct dl *dl)
7892 {
7893 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7894 struct nlmsghdr *nlh;
7895 int err;
7896
7897 if (dl_argc(dl) == 0)
7898 flags |= NLM_F_DUMP;
7899
7900 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags);
7901
7902 if (dl_argc(dl) > 0) {
7903 err = dl_argv_parse_put(nlh, dl,
7904 DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
7905 0);
7906 if (err)
7907 return err;
7908 }
7909
7910 pr_out_section_start(dl, "trap_group");
7911 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_group_show_cb, dl);
7912 pr_out_section_end(dl);
7913
7914 return err;
7915 }
7916
7917 static int cmd_trap_group_set(struct dl *dl)
7918 {
7919 struct nlmsghdr *nlh;
7920 int err;
7921
7922 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET,
7923 NLM_F_REQUEST | NLM_F_ACK);
7924
7925 err = dl_argv_parse_put(nlh, dl,
7926 DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
7927 DL_OPT_TRAP_ACTION | DL_OPT_TRAP_POLICER_ID);
7928 if (err)
7929 return err;
7930
7931 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7932 }
7933
7934 static int cmd_trap_group(struct dl *dl)
7935 {
7936 if (dl_argv_match(dl, "help")) {
7937 cmd_trap_help();
7938 return 0;
7939 } else if (dl_argv_match(dl, "show") ||
7940 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7941 dl_arg_inc(dl);
7942 return cmd_trap_group_show(dl);
7943 } else if (dl_argv_match(dl, "set")) {
7944 dl_arg_inc(dl);
7945 return cmd_trap_group_set(dl);
7946 }
7947 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7948 return -ENOENT;
7949 }
7950
7951 static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array)
7952 {
7953 if (array)
7954 pr_out_handle_start_arr(dl, tb);
7955 else
7956 __pr_out_handle_start(dl, tb, true, false);
7957
7958 check_indent_newline(dl);
7959 print_uint(PRINT_ANY, "policer", "policer %u",
7960 mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
7961 print_u64(PRINT_ANY, "rate", " rate %llu",
7962 mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_RATE]));
7963 print_u64(PRINT_ANY, "burst", " burst %llu",
7964 mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_BURST]));
7965 if (tb[DEVLINK_ATTR_STATS])
7966 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7967 pr_out_handle_end(dl);
7968 }
7969
7970 static int cmd_trap_policer_show_cb(const struct nlmsghdr *nlh, void *data)
7971 {
7972 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7973 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7974 struct dl *dl = data;
7975
7976 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7977 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7978 !tb[DEVLINK_ATTR_TRAP_POLICER_ID] ||
7979 !tb[DEVLINK_ATTR_TRAP_POLICER_RATE] ||
7980 !tb[DEVLINK_ATTR_TRAP_POLICER_BURST])
7981 return MNL_CB_ERROR;
7982
7983 pr_out_trap_policer(dl, tb, true);
7984
7985 return MNL_CB_OK;
7986 }
7987
7988 static int cmd_trap_policer_show(struct dl *dl)
7989 {
7990 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7991 struct nlmsghdr *nlh;
7992 int err;
7993
7994 if (dl_argc(dl) == 0)
7995 flags |= NLM_F_DUMP;
7996
7997 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_GET, flags);
7998
7999 if (dl_argc(dl) > 0) {
8000 err = dl_argv_parse_put(nlh, dl,
8001 DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
8002 0);
8003 if (err)
8004 return err;
8005 }
8006
8007 pr_out_section_start(dl, "trap_policer");
8008 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_policer_show_cb, dl);
8009 pr_out_section_end(dl);
8010
8011 return err;
8012 }
8013
8014 static int cmd_trap_policer_set(struct dl *dl)
8015 {
8016 struct nlmsghdr *nlh;
8017 int err;
8018
8019 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_SET,
8020 NLM_F_REQUEST | NLM_F_ACK);
8021
8022 err = dl_argv_parse_put(nlh, dl,
8023 DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
8024 DL_OPT_TRAP_POLICER_RATE |
8025 DL_OPT_TRAP_POLICER_BURST);
8026 if (err)
8027 return err;
8028
8029 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
8030 }
8031
8032 static int cmd_trap_policer(struct dl *dl)
8033 {
8034 if (dl_argv_match(dl, "help")) {
8035 cmd_trap_help();
8036 return 0;
8037 } else if (dl_argv_match(dl, "show") ||
8038 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8039 dl_arg_inc(dl);
8040 return cmd_trap_policer_show(dl);
8041 } else if (dl_argv_match(dl, "set")) {
8042 dl_arg_inc(dl);
8043 return cmd_trap_policer_set(dl);
8044 }
8045 pr_err("Command \"%s\" not found\n", dl_argv(dl));
8046 return -ENOENT;
8047 }
8048
8049 static int cmd_trap(struct dl *dl)
8050 {
8051 if (dl_argv_match(dl, "help")) {
8052 cmd_trap_help();
8053 return 0;
8054 } else if (dl_argv_match(dl, "show") ||
8055 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
8056 dl_arg_inc(dl);
8057 return cmd_trap_show(dl);
8058 } else if (dl_argv_match(dl, "set")) {
8059 dl_arg_inc(dl);
8060 return cmd_trap_set(dl);
8061 } else if (dl_argv_match(dl, "group")) {
8062 dl_arg_inc(dl);
8063 return cmd_trap_group(dl);
8064 } else if (dl_argv_match(dl, "policer")) {
8065 dl_arg_inc(dl);
8066 return cmd_trap_policer(dl);
8067 }
8068 pr_err("Command \"%s\" not found\n", dl_argv(dl));
8069 return -ENOENT;
8070 }
8071
8072 static void help(void)
8073 {
8074 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
8075 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
8076 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
8077 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
8078 }
8079
8080 static int dl_cmd(struct dl *dl, int argc, char **argv)
8081 {
8082 dl->argc = argc;
8083 dl->argv = argv;
8084
8085 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
8086 help();
8087 return 0;
8088 } else if (dl_argv_match(dl, "dev")) {
8089 dl_arg_inc(dl);
8090 return cmd_dev(dl);
8091 } else if (dl_argv_match(dl, "port")) {
8092 dl_arg_inc(dl);
8093 return cmd_port(dl);
8094 } else if (dl_argv_match(dl, "sb")) {
8095 dl_arg_inc(dl);
8096 return cmd_sb(dl);
8097 } else if (dl_argv_match(dl, "monitor")) {
8098 dl_arg_inc(dl);
8099 return cmd_mon(dl);
8100 } else if (dl_argv_match(dl, "dpipe")) {
8101 dl_arg_inc(dl);
8102 return cmd_dpipe(dl);
8103 } else if (dl_argv_match(dl, "resource")) {
8104 dl_arg_inc(dl);
8105 return cmd_resource(dl);
8106 } else if (dl_argv_match(dl, "region")) {
8107 dl_arg_inc(dl);
8108 return cmd_region(dl);
8109 } else if (dl_argv_match(dl, "health")) {
8110 dl_arg_inc(dl);
8111 return cmd_health(dl);
8112 } else if (dl_argv_match(dl, "trap")) {
8113 dl_arg_inc(dl);
8114 return cmd_trap(dl);
8115 }
8116 pr_err("Object \"%s\" not found\n", dl_argv(dl));
8117 return -ENOENT;
8118 }
8119
8120 static int dl_init(struct dl *dl)
8121 {
8122 int err;
8123
8124 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
8125 if (!dl->nlg) {
8126 pr_err("Failed to connect to devlink Netlink\n");
8127 return -errno;
8128 }
8129
8130 err = ifname_map_init(dl);
8131 if (err) {
8132 pr_err("Failed to create index map\n");
8133 goto err_ifname_map_create;
8134 }
8135 new_json_obj_plain(dl->json_output);
8136 return 0;
8137
8138 err_ifname_map_create:
8139 mnlg_socket_close(dl->nlg);
8140 return err;
8141 }
8142
8143 static void dl_fini(struct dl *dl)
8144 {
8145 delete_json_obj_plain();
8146 ifname_map_fini(dl);
8147 mnlg_socket_close(dl->nlg);
8148 }
8149
8150 static struct dl *dl_alloc(void)
8151 {
8152 struct dl *dl;
8153
8154 dl = calloc(1, sizeof(*dl));
8155 if (!dl)
8156 return NULL;
8157 return dl;
8158 }
8159
8160 static void dl_free(struct dl *dl)
8161 {
8162 free(dl);
8163 }
8164
8165 static int dl_batch_cmd(int argc, char *argv[], void *data)
8166 {
8167 struct dl *dl = data;
8168
8169 return dl_cmd(dl, argc, argv);
8170 }
8171
8172 static int dl_batch(struct dl *dl, const char *name, bool force)
8173 {
8174 return do_batch(name, force, dl_batch_cmd, dl);
8175 }
8176
8177 int main(int argc, char **argv)
8178 {
8179 static const struct option long_options[] = {
8180 { "Version", no_argument, NULL, 'V' },
8181 { "force", no_argument, NULL, 'f' },
8182 { "batch", required_argument, NULL, 'b' },
8183 { "no-nice-names", no_argument, NULL, 'n' },
8184 { "json", no_argument, NULL, 'j' },
8185 { "pretty", no_argument, NULL, 'p' },
8186 { "verbose", no_argument, NULL, 'v' },
8187 { "statistics", no_argument, NULL, 's' },
8188 { "Netns", required_argument, NULL, 'N' },
8189 { NULL, 0, NULL, 0 }
8190 };
8191 const char *batch_file = NULL;
8192 bool force = false;
8193 struct dl *dl;
8194 int opt;
8195 int err;
8196 int ret;
8197
8198 dl = dl_alloc();
8199 if (!dl) {
8200 pr_err("Failed to allocate memory for devlink\n");
8201 return EXIT_FAILURE;
8202 }
8203
8204 while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:",
8205 long_options, NULL)) >= 0) {
8206
8207 switch (opt) {
8208 case 'V':
8209 printf("devlink utility, iproute2-%s\n", version);
8210 ret = EXIT_SUCCESS;
8211 goto dl_free;
8212 case 'f':
8213 force = true;
8214 break;
8215 case 'b':
8216 batch_file = optarg;
8217 break;
8218 case 'n':
8219 dl->no_nice_names = true;
8220 break;
8221 case 'j':
8222 dl->json_output = true;
8223 break;
8224 case 'p':
8225 pretty = true;
8226 break;
8227 case 'v':
8228 dl->verbose = true;
8229 break;
8230 case 's':
8231 dl->stats = true;
8232 break;
8233 case 'N':
8234 if (netns_switch(optarg)) {
8235 ret = EXIT_FAILURE;
8236 goto dl_free;
8237 }
8238 break;
8239 default:
8240 pr_err("Unknown option.\n");
8241 help();
8242 ret = EXIT_FAILURE;
8243 goto dl_free;
8244 }
8245 }
8246
8247 argc -= optind;
8248 argv += optind;
8249
8250 err = dl_init(dl);
8251 if (err) {
8252 ret = EXIT_FAILURE;
8253 goto dl_free;
8254 }
8255
8256 if (batch_file)
8257 err = dl_batch(dl, batch_file, force);
8258 else
8259 err = dl_cmd(dl, argc, argv);
8260
8261 if (err) {
8262 ret = EXIT_FAILURE;
8263 goto dl_fini;
8264 }
8265
8266 ret = EXIT_SUCCESS;
8267
8268 dl_fini:
8269 dl_fini(dl);
8270 dl_free:
8271 dl_free(dl);
8272
8273 return ret;
8274 }