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