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