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