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