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