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