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