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