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