]> git.proxmox.com Git - mirror_iproute2.git/blame - devlink/devlink.c
iproute2: ip maddress: Check multiaddr length
[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
JP
4656 }
4657 return MNL_CB_OK;
4658}
4659
4660static int cmd_mon_show(struct dl *dl)
4661{
4662 int err;
4663 unsigned int index = 0;
4664 const char *cur_obj;
4665
4666 while ((cur_obj = dl_argv_index(dl, index++))) {
4667 if (strcmp(cur_obj, "all") != 0 &&
4668 strcmp(cur_obj, "dev") != 0 &&
ef12d6da 4669 strcmp(cur_obj, "port") != 0 &&
5023df6a 4670 strcmp(cur_obj, "health") != 0 &&
4ede9e9d 4671 strcmp(cur_obj, "trap") != 0 &&
a66af556
IS
4672 strcmp(cur_obj, "trap-group") != 0 &&
4673 strcmp(cur_obj, "trap-policer") != 0) {
a3c4b484
JP
4674 pr_err("Unknown object \"%s\"\n", cur_obj);
4675 return -EINVAL;
4676 }
4677 }
4678 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
4679 if (err)
4680 return err;
c4dfddcc
JP
4681 open_json_object(NULL);
4682 open_json_array(PRINT_JSON, "mon");
4683 err = _mnlg_socket_recv_run_intr(dl->nlg, cmd_mon_show_cb, dl);
4684 close_json_array(PRINT_JSON, NULL);
4685 close_json_object();
a3c4b484
JP
4686 if (err)
4687 return err;
4688 return 0;
4689}
4690
4691static void cmd_mon_help(void)
4692{
7a9466db 4693 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
a66af556 4694 "where OBJECT-LIST := { dev | port | health | trap | trap-group | trap-policer }\n");
a3c4b484
JP
4695}
4696
4697static int cmd_mon(struct dl *dl)
4698{
4699 if (dl_argv_match(dl, "help")) {
4700 cmd_mon_help();
4701 return 0;
a3c4b484 4702 }
e7330604 4703 return cmd_mon_show(dl);
a3c4b484
JP
4704}
4705
153c1a9b
AS
4706struct dpipe_field {
4707 char *name;
4708 unsigned int id;
4709 unsigned int bitwidth;
4710 enum devlink_dpipe_field_mapping_type mapping_type;
4711};
4712
4713struct dpipe_header {
4714 struct list_head list;
4715 char *name;
4716 unsigned int id;
4717 struct dpipe_field *fields;
4718 unsigned int fields_count;
4719};
4720
ead18027
AS
4721struct dpipe_table {
4722 struct list_head list;
4723 char *name;
4724 unsigned int resource_id;
4725 bool resource_valid;
4726};
4727
4728struct dpipe_tables {
4729 struct list_head table_list;
4730};
4731
8cd64409
AS
4732struct resource {
4733 char *name;
4734 uint64_t size;
4735 uint64_t size_new;
4736 uint64_t size_min;
4737 uint64_t size_max;
4738 uint64_t size_gran;
4739 enum devlink_resource_unit unit;
4740 bool size_valid;
4741 uint64_t size_occ;
4742 bool occ_valid;
4743 uint64_t id;
4744 struct list_head list;
4745 struct list_head resource_list;
4746 struct resource *parent;
4747};
4748
4749struct resources {
4750 struct list_head resource_list;
4751};
4752
4753struct resource_ctx {
4754 struct dl *dl;
4755 int err;
4756 struct resources *resources;
ead18027 4757 struct dpipe_tables *tables;
8cd64409
AS
4758 bool print_resources;
4759 bool pending_change;
4760};
4761
4762static struct resource *resource_alloc(void)
4763{
4764 struct resource *resource;
4765
4766 resource = calloc(1, sizeof(struct resource));
4767 if (!resource)
4768 return NULL;
4769 INIT_LIST_HEAD(&resource->resource_list);
4770 return resource;
4771}
4772
4773static void resource_free(struct resource *resource)
4774{
4775 struct resource *child_resource, *tmp;
4776
4777 list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
4778 list) {
4779 free(child_resource->name);
4780 resource_free(child_resource);
4781 }
4782 free(resource);
4783}
4784
4785static struct resources *resources_alloc(void)
4786{
4787 struct resources *resources;
4788
4789 resources = calloc(1, sizeof(struct resources));
4790 if (!resources)
4791 return NULL;
4792 INIT_LIST_HEAD(&resources->resource_list);
4793 return resources;
4794}
4795
4796static void resources_free(struct resources *resources)
4797{
4798 struct resource *resource, *tmp;
4799
4800 list_for_each_entry_safe(resource, tmp, &resources->resource_list, list)
4801 resource_free(resource);
4802}
4803
4804static int resource_ctx_init(struct resource_ctx *ctx, struct dl *dl)
4805{
4806 ctx->resources = resources_alloc();
4807 if (!ctx->resources)
4808 return -ENOMEM;
4809 ctx->dl = dl;
4810 return 0;
4811}
4812
4813static void resource_ctx_fini(struct resource_ctx *ctx)
4814{
4815 resources_free(ctx->resources);
4816}
4817
153c1a9b
AS
4818struct dpipe_ctx {
4819 struct dl *dl;
4820 int err;
4821 struct list_head global_headers;
4822 struct list_head local_headers;
ead18027
AS
4823 struct dpipe_tables *tables;
4824 struct resources *resources;
153c1a9b 4825 bool print_headers;
ead18027 4826 bool print_tables;
153c1a9b
AS
4827};
4828
4829static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
a3c4b484 4830{
153c1a9b
AS
4831 struct dpipe_header *header;
4832
4833 header = calloc(1, sizeof(struct dpipe_header));
4834 if (!header)
4835 return NULL;
4836 header->fields = calloc(fields_count, sizeof(struct dpipe_field));
4837 if (!header->fields)
4838 goto err_fields_alloc;
4839 header->fields_count = fields_count;
4840 return header;
4841
4842err_fields_alloc:
4843 free(header);
4844 return NULL;
a3c4b484
JP
4845}
4846
153c1a9b 4847static void dpipe_header_free(struct dpipe_header *header)
a3c4b484 4848{
153c1a9b
AS
4849 free(header->fields);
4850 free(header);
4851}
4852
4853static void dpipe_header_clear(struct dpipe_header *header)
4854{
4855 struct dpipe_field *field;
4856 int i;
4857
4858 for (i = 0; i < header->fields_count; i++) {
4859 field = &header->fields[i];
4860 free(field->name);
a3c4b484 4861 }
153c1a9b 4862 free(header->name);
a3c4b484
JP
4863}
4864
153c1a9b
AS
4865static void dpipe_header_add(struct dpipe_ctx *ctx,
4866 struct dpipe_header *header, bool global)
a3c4b484 4867{
153c1a9b
AS
4868 if (global)
4869 list_add(&header->list, &ctx->global_headers);
4870 else
4871 list_add(&header->list, &ctx->local_headers);
4872}
a3c4b484 4873
153c1a9b
AS
4874static void dpipe_header_del(struct dpipe_header *header)
4875{
4876 list_del(&header->list);
4877}
a3c4b484 4878
ead18027
AS
4879static struct dpipe_table *dpipe_table_alloc(void)
4880{
4881 return calloc(1, sizeof(struct dpipe_table));
4882}
4883
4884static void dpipe_table_free(struct dpipe_table *table)
4885{
4886 free(table);
4887}
4888
4889static struct dpipe_tables *dpipe_tables_alloc(void)
4890{
4891 struct dpipe_tables *tables;
4892
4893 tables = calloc(1, sizeof(struct dpipe_tables));
4894 if (!tables)
4895 return NULL;
4896 INIT_LIST_HEAD(&tables->table_list);
4897 return tables;
4898}
4899
4900static void dpipe_tables_free(struct dpipe_tables *tables)
4901{
4902 struct dpipe_table *table, *tmp;
4903
4904 list_for_each_entry_safe(table, tmp, &tables->table_list, list)
4905 dpipe_table_free(table);
4906 free(tables);
4907}
4908
06a2cda9 4909static int dpipe_ctx_init(struct dpipe_ctx *ctx, struct dl *dl)
153c1a9b 4910{
ead18027
AS
4911 ctx->tables = dpipe_tables_alloc();
4912 if (!ctx->tables)
4913 return -ENOMEM;
4914
153c1a9b
AS
4915 ctx->dl = dl;
4916 INIT_LIST_HEAD(&ctx->global_headers);
4917 INIT_LIST_HEAD(&ctx->local_headers);
06a2cda9 4918 return 0;
153c1a9b
AS
4919}
4920
06a2cda9 4921static void dpipe_ctx_fini(struct dpipe_ctx *ctx)
153c1a9b
AS
4922{
4923 struct dpipe_header *header, *tmp;
4924
4925 list_for_each_entry_safe(header, tmp, &ctx->global_headers,
4926 list) {
4927 dpipe_header_del(header);
4928 dpipe_header_clear(header);
4929 dpipe_header_free(header);
4930 }
4931 list_for_each_entry_safe(header, tmp, &ctx->local_headers,
4932 list) {
4933 dpipe_header_del(header);
4934 dpipe_header_clear(header);
4935 dpipe_header_free(header);
a3c4b484 4936 }
ead18027 4937 dpipe_tables_free(ctx->tables);
153c1a9b 4938}
a3c4b484 4939
153c1a9b
AS
4940static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
4941 uint32_t header_id, bool global)
4942{
4943 struct list_head *header_list;
4944 struct dpipe_header *header;
4945
4946 if (global)
4947 header_list = &ctx->global_headers;
4948 else
4949 header_list = &ctx->local_headers;
4950 list_for_each_entry(header, header_list, list) {
4951 if (header->id != header_id)
4952 continue;
4953 return header->name;
a3c4b484 4954 }
153c1a9b
AS
4955 return NULL;
4956}
4957
4958static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
4959 uint32_t header_id,
4960 uint32_t field_id, bool global)
4961{
4962 struct list_head *header_list;
4963 struct dpipe_header *header;
4964
4965 if (global)
4966 header_list = &ctx->global_headers;
4967 else
4968 header_list = &ctx->local_headers;
4969 list_for_each_entry(header, header_list, list) {
4970 if (header->id != header_id)
4971 continue;
4972 return header->fields[field_id].name;
e3d0f0c0 4973 }
153c1a9b
AS
4974 return NULL;
4975}
a3c4b484 4976
153c1a9b
AS
4977static const char *
4978dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
4979{
4980 switch (mapping_type) {
4981 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
4982 return NULL;
4983 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
4984 return "ifindex";
4985 default:
4986 return "<unknown>";
4987 }
a3c4b484
JP
4988}
4989
153c1a9b
AS
4990static const char *
4991dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
4992 uint32_t field_id, bool global)
a3c4b484 4993{
153c1a9b
AS
4994 enum devlink_dpipe_field_mapping_type mapping_type;
4995 struct list_head *header_list;
4996 struct dpipe_header *header;
4997
4998 if (global)
4999 header_list = &ctx->global_headers;
5000 else
5001 header_list = &ctx->local_headers;
5002 list_for_each_entry(header, header_list, list) {
5003 if (header->id != header_id)
5004 continue;
5005 mapping_type = header->fields[field_id].mapping_type;
5006 return dpipe_field_mapping_e2s(mapping_type);
5007 }
5008 return NULL;
a3c4b484
JP
5009}
5010
153c1a9b
AS
5011static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
5012 struct dpipe_field *fields,
5013 unsigned int field_count)
a3c4b484 5014{
153c1a9b
AS
5015 struct dpipe_field *field;
5016 int i;
a3c4b484 5017
153c1a9b
AS
5018 for (i = 0; i < field_count; i++) {
5019 field = &fields[i];
5020 pr_out_entry_start(ctx->dl);
3666eb0e
RD
5021 check_indent_newline(ctx->dl);
5022 print_string(PRINT_ANY, "name", "name %s", field->name);
153c1a9b 5023 if (ctx->dl->verbose)
ff360fe9
RD
5024 print_uint(PRINT_ANY, "id", " id %u", field->id);
5025 print_uint(PRINT_ANY, "bitwidth", " bitwidth %u", field->bitwidth);
3666eb0e
RD
5026 if (field->mapping_type) {
5027 print_string(PRINT_ANY, "mapping_type", " mapping_type %s",
5028 dpipe_field_mapping_e2s(field->mapping_type));
5029 }
153c1a9b
AS
5030 pr_out_entry_end(ctx->dl);
5031 }
a3c4b484
JP
5032}
5033
153c1a9b
AS
5034static void
5035pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
5036 struct dpipe_header *header, bool global)
a3c4b484 5037{
153c1a9b 5038 pr_out_handle_start_arr(ctx->dl, tb);
3666eb0e
RD
5039 check_indent_newline(ctx->dl);
5040 print_string(PRINT_ANY, "name", "name %s", header->name);
153c1a9b 5041 if (ctx->dl->verbose) {
ff360fe9 5042 print_uint(PRINT_ANY, "id", " id %u", header->id);
3666eb0e 5043 print_bool(PRINT_ANY, "global", " global %s", global);
153c1a9b
AS
5044 }
5045 pr_out_array_start(ctx->dl, "field");
5046 pr_out_dpipe_fields(ctx, header->fields,
5047 header->fields_count);
5048 pr_out_array_end(ctx->dl);
5049 pr_out_handle_end(ctx->dl);
a3c4b484
JP
5050}
5051
153c1a9b
AS
5052static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
5053 struct nlattr **tb)
a3c4b484 5054{
153c1a9b
AS
5055 struct dpipe_header *header;
5056
5057 list_for_each_entry(header, &ctx->local_headers, list)
5058 pr_out_dpipe_header(ctx, tb, header, false);
5059
5060 list_for_each_entry(header, &ctx->global_headers, list)
5061 pr_out_dpipe_header(ctx, tb, header, true);
5062}
5063
5064static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
5065{
5066 struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
5067 const char *name;
a3c4b484 5068 int err;
a3c4b484 5069
153c1a9b
AS
5070 err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
5071 if (err != MNL_CB_OK)
5072 return -EINVAL;
5073 if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
5074 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
5075 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
5076 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
5077 return -EINVAL;
5078
5079 name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
5080 field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5081 field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
5082 field->name = strdup(name);
5083 if (!field->name)
5084 return -ENOMEM;
5085 field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
5086 return 0;
5087}
5088
5089static int dpipe_header_fields_get(struct nlattr *nla_fields,
5090 struct dpipe_field *fields)
5091{
5092 struct nlattr *nla_field;
5093 int count = 0;
5094 int err;
5095
5096 mnl_attr_for_each_nested(nla_field, nla_fields) {
5097 err = dpipe_header_field_get(nla_field, &fields[count]);
5098 if (err)
5099 return err;
5100 count++;
43f35be4 5101 }
153c1a9b
AS
5102 return 0;
5103}
43f35be4 5104
153c1a9b
AS
5105static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
5106{
5107 struct nlattr *nla_field;
5108 unsigned int count = 0;
a3c4b484 5109
153c1a9b
AS
5110 mnl_attr_for_each_nested(nla_field, nla_fields)
5111 count++;
5112 return count;
5113}
5114
5115static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
5116{
5117 struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
5118 struct dpipe_header *header;
5119 unsigned int fields_count;
5120 const char *header_name;
5121 bool global;
5122 int err;
5123
5124 err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
5125 if (err != MNL_CB_OK)
5126 return -EINVAL;
5127
5128 if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
5129 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5130 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
5131 return -EINVAL;
5132
5133 fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
5134 header = dpipe_header_alloc(fields_count);
5135 if (!header)
5136 return -ENOMEM;
5137
5138 header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
5139 header->name = strdup(header_name);
5140 header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5141 header->fields_count = fields_count;
5142 global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5143
5144 err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
5145 header->fields);
5146 if (err)
5147 goto err_field_get;
5148 dpipe_header_add(ctx, header, global);
5149 return 0;
5150
5151err_field_get:
5152 dpipe_header_free(header);
5153 return err;
5154}
5155
5156static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
5157{
5158 struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
5159 struct nlattr *nla_header;
5160 int err;
5161
5162 mnl_attr_for_each_nested(nla_header, nla_headers) {
5163 err = dpipe_header_get(ctx, nla_header);
5164 if (err)
5165 return err;
5166 }
5167 return 0;
5168}
5169
5170static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
5171{
5172 struct dpipe_ctx *ctx = data;
5173 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5174 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5175 int err;
5176
5177 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5178 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5179 !tb[DEVLINK_ATTR_DPIPE_HEADERS])
5180 return MNL_CB_ERROR;
5181 err = dpipe_headers_get(ctx, tb);
5182 if (err) {
5183 ctx->err = err;
5184 return MNL_CB_ERROR;
5185 }
5186
5187 if (ctx->print_headers)
5188 pr_out_dpipe_headers(ctx, tb);
5189 return MNL_CB_OK;
5190}
5191
5192static int cmd_dpipe_headers_show(struct dl *dl)
5193{
5194 struct nlmsghdr *nlh;
06a2cda9 5195 struct dpipe_ctx ctx = {};
153c1a9b
AS
5196 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5197 int err;
5198
5199 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
5200
5201 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
5202 if (err)
5203 return err;
5204
06a2cda9
AS
5205 err = dpipe_ctx_init(&ctx, dl);
5206 if (err)
5207 return err;
153c1a9b 5208
06a2cda9 5209 ctx.print_headers = true;
153c1a9b
AS
5210
5211 pr_out_section_start(dl, "header");
06a2cda9 5212 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
153c1a9b 5213 if (err)
06a2cda9 5214 pr_err("error get headers %s\n", strerror(ctx.err));
153c1a9b
AS
5215 pr_out_section_end(dl);
5216
06a2cda9 5217 dpipe_ctx_fini(&ctx);
153c1a9b
AS
5218 return err;
5219}
5220
b2522187 5221static void cmd_dpipe_help(void)
153c1a9b 5222{
b2522187
JP
5223 pr_err("Usage: devlink dpipe table show DEV [ name TABLE_NAME ]\n");
5224 pr_err(" devlink dpipe table set DEV name TABLE_NAME\n");
5225 pr_err(" [ counters_enabled { true | false } ]\n");
5226 pr_err(" devlink dpipe table dump DEV name TABLE_NAME\n");
5227 pr_err(" devlink dpipe header show DEV\n");
153c1a9b
AS
5228}
5229
5230static int cmd_dpipe_header(struct dl *dl)
5231{
5232 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
b2522187 5233 cmd_dpipe_help();
153c1a9b
AS
5234 return 0;
5235 } else if (dl_argv_match(dl, "show")) {
5236 dl_arg_inc(dl);
5237 return cmd_dpipe_headers_show(dl);
5238 }
5239 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5240 return -ENOENT;
5241}
5242
5243static const char
5244*dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
5245{
5246 switch (action_type) {
5247 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
5248 return "field_modify";
5249 default:
5250 return "<unknown>";
5251 }
5252}
5253
92b2a5bb
AS
5254struct dpipe_op_info {
5255 uint32_t header_id;
5256 uint32_t field_id;
5257 bool header_global;
5258};
5259
5260struct dpipe_action {
5261 struct dpipe_op_info info;
5262 uint32_t type;
5263};
5264
5265static void pr_out_dpipe_action(struct dpipe_action *action,
5266 struct dpipe_ctx *ctx)
153c1a9b 5267{
92b2a5bb 5268 struct dpipe_op_info *op_info = &action->info;
153c1a9b
AS
5269 const char *mapping;
5270
3666eb0e
RD
5271 check_indent_newline(ctx->dl);
5272 print_string(PRINT_ANY, "type", "type %s",
5273 dpipe_action_type_e2s(action->type));
5274 print_string(PRINT_ANY, "header", " header %s",
5275 dpipe_header_id2s(ctx, op_info->header_id,
5276 op_info->header_global));
5277 print_string(PRINT_ANY, "field", " field %s",
5278 dpipe_field_id2s(ctx, op_info->header_id,
5279 op_info->field_id,
5280 op_info->header_global));
92b2a5bb
AS
5281 mapping = dpipe_mapping_get(ctx, op_info->header_id,
5282 op_info->field_id,
5283 op_info->header_global);
153c1a9b 5284 if (mapping)
3666eb0e 5285 print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
153c1a9b
AS
5286}
5287
92b2a5bb 5288static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
153c1a9b
AS
5289{
5290 struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
153c1a9b
AS
5291 int err;
5292
5293 err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
5294 if (err != MNL_CB_OK)
5295 return -EINVAL;
5296
5297 if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
5298 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
5299 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5300 !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
5301 return -EINVAL;
5302 }
5303
92b2a5bb
AS
5304 action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
5305 action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5306 action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5307 action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
153c1a9b 5308
153c1a9b
AS
5309 return 0;
5310}
5311
5312static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
5313 struct nlattr *nla_actions)
5314{
5315 struct nlattr *nla_action;
92b2a5bb 5316 struct dpipe_action action;
153c1a9b
AS
5317
5318 mnl_attr_for_each_nested(nla_action, nla_actions) {
5319 pr_out_entry_start(ctx->dl);
92b2a5bb
AS
5320 if (dpipe_action_parse(&action, nla_action))
5321 goto err_action_parse;
5322 pr_out_dpipe_action(&action, ctx);
153c1a9b
AS
5323 pr_out_entry_end(ctx->dl);
5324 }
5325 return 0;
5326
92b2a5bb 5327err_action_parse:
153c1a9b
AS
5328 pr_out_entry_end(ctx->dl);
5329 return -EINVAL;
5330}
5331
5332static const char *
5333dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
5334{
5335 switch (match_type) {
5336 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
5337 return "field_exact";
5338 default:
5339 return "<unknown>";
5340 }
5341}
5342
92b2a5bb
AS
5343struct dpipe_match {
5344 struct dpipe_op_info info;
5345 uint32_t type;
5346};
5347
5348static void pr_out_dpipe_match(struct dpipe_match *match,
5349 struct dpipe_ctx *ctx)
153c1a9b 5350{
92b2a5bb 5351 struct dpipe_op_info *op_info = &match->info;
153c1a9b
AS
5352 const char *mapping;
5353
3666eb0e
RD
5354 check_indent_newline(ctx->dl);
5355 print_string(PRINT_ANY, "type", "type %s",
5356 dpipe_match_type_e2s(match->type));
5357 print_string(PRINT_ANY, "header", " header %s",
5358 dpipe_header_id2s(ctx, op_info->header_id,
5359 op_info->header_global));
5360 print_string(PRINT_ANY, "field", " field %s",
5361 dpipe_field_id2s(ctx, op_info->header_id,
5362 op_info->field_id,
5363 op_info->header_global));
92b2a5bb
AS
5364 mapping = dpipe_mapping_get(ctx, op_info->header_id,
5365 op_info->field_id,
5366 op_info->header_global);
153c1a9b 5367 if (mapping)
3666eb0e 5368 print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
153c1a9b
AS
5369}
5370
92b2a5bb
AS
5371static int dpipe_match_parse(struct dpipe_match *match,
5372 struct nlattr *nl)
5373
153c1a9b
AS
5374{
5375 struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
153c1a9b
AS
5376 int err;
5377
5378 err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
5379 if (err != MNL_CB_OK)
5380 return -EINVAL;
5381
5382 if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
5383 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
5384 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5385 !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
5386 return -EINVAL;
5387 }
5388
92b2a5bb
AS
5389 match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
5390 match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5391 match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5392 match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
153c1a9b 5393
153c1a9b
AS
5394 return 0;
5395}
5396
5397static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
5398 struct nlattr *nla_matches)
5399{
5400 struct nlattr *nla_match;
92b2a5bb 5401 struct dpipe_match match;
153c1a9b
AS
5402
5403 mnl_attr_for_each_nested(nla_match, nla_matches) {
5404 pr_out_entry_start(ctx->dl);
92b2a5bb
AS
5405 if (dpipe_match_parse(&match, nla_match))
5406 goto err_match_parse;
5407 pr_out_dpipe_match(&match, ctx);
153c1a9b
AS
5408 pr_out_entry_end(ctx->dl);
5409 }
5410 return 0;
5411
92b2a5bb 5412err_match_parse:
153c1a9b
AS
5413 pr_out_entry_end(ctx->dl);
5414 return -EINVAL;
5415}
5416
8cd64409
AS
5417static struct resource *
5418resource_find(struct resources *resources, struct resource *resource,
5419 uint64_t resource_id)
5420{
5421 struct list_head *list_head;
5422
5423 if (!resource)
5424 list_head = &resources->resource_list;
5425 else
5426 list_head = &resource->resource_list;
5427
5428 list_for_each_entry(resource, list_head, list) {
5429 struct resource *child_resource;
5430
5431 if (resource->id == resource_id)
5432 return resource;
5433
5434 child_resource = resource_find(resources, resource,
5435 resource_id);
5436 if (child_resource)
5437 return child_resource;
5438 }
5439 return NULL;
5440}
5441
5442static void
5443resource_path_print(struct dl *dl, struct resources *resources,
5444 uint64_t resource_id)
5445{
5446 struct resource *resource, *parent_resource;
5447 const char del[] = "/";
5448 int path_len = 0;
5449 char *path;
5450
5451 resource = resource_find(resources, NULL, resource_id);
5452 if (!resource)
5453 return;
5454
5455 for (parent_resource = resource; parent_resource;
5456 parent_resource = parent_resource->parent)
5457 path_len += strlen(parent_resource->name) + 1;
5458
5459 path_len++;
5460 path = calloc(1, path_len);
5461 if (!path)
5462 return;
5463
5464 path += path_len - 1;
5465 for (parent_resource = resource; parent_resource;
5466 parent_resource = parent_resource->parent) {
5467 path -= strlen(parent_resource->name);
5468 memcpy(path, parent_resource->name,
5469 strlen(parent_resource->name));
5470 path -= strlen(del);
5471 memcpy(path, del, strlen(del));
5472 }
3666eb0e
RD
5473 check_indent_newline(dl);
5474 print_string(PRINT_ANY, "resource_path", "resource_path %s", path);
8cd64409
AS
5475 free(path);
5476}
5477
153c1a9b
AS
5478static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
5479{
5480 struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
ead18027
AS
5481 struct dpipe_table *table;
5482 uint32_t resource_units;
153c1a9b 5483 bool counters_enabled;
ead18027 5484 bool resource_valid;
153c1a9b
AS
5485 uint32_t size;
5486 int err;
5487
5488 err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
5489 if (err != MNL_CB_OK)
5490 return -EINVAL;
5491
5492 if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
5493 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
5494 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
5495 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
5496 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
5497 return -EINVAL;
5498 }
5499
ead18027
AS
5500 table = dpipe_table_alloc();
5501 if (!table)
5502 return -ENOMEM;
5503
5504 table->name = strdup(mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]));
153c1a9b
AS
5505 size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
5506 counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
5507
0e7e1819
JP
5508 resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
5509 ctx->resources;
ead18027
AS
5510 if (resource_valid) {
5511 table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
5512 table->resource_valid = true;
5513 }
5514
5515 list_add_tail(&table->list, &ctx->tables->table_list);
5516 if (!ctx->print_tables)
5517 return 0;
5518
3666eb0e
RD
5519 check_indent_newline(ctx->dl);
5520 print_string(PRINT_ANY, "name", "name %s", table->name);
ff360fe9 5521 print_uint(PRINT_ANY, "size", " size %u", size);
3666eb0e 5522 print_bool(PRINT_ANY, "counters_enabled", " counters_enabled %s", counters_enabled);
153c1a9b 5523
ead18027
AS
5524 if (resource_valid) {
5525 resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
5526 resource_path_print(ctx->dl, ctx->resources,
5527 table->resource_id);
ff360fe9
RD
5528 print_uint(PRINT_ANY, "resource_units", " resource_units %u",
5529 resource_units);
ead18027
AS
5530 }
5531
153c1a9b
AS
5532 pr_out_array_start(ctx->dl, "match");
5533 if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
5534 goto err_matches_show;
5535 pr_out_array_end(ctx->dl);
5536
5537 pr_out_array_start(ctx->dl, "action");
5538 if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
5539 goto err_actions_show;
5540 pr_out_array_end(ctx->dl);
5541
5542 return 0;
5543
5544err_actions_show:
5545err_matches_show:
5546 pr_out_array_end(ctx->dl);
5547 return -EINVAL;
5548}
5549
5550static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
5551{
5552 struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
5553 struct nlattr *nla_table;
5554
5555 mnl_attr_for_each_nested(nla_table, nla_tables) {
ead18027
AS
5556 if (ctx->print_tables)
5557 pr_out_handle_start_arr(ctx->dl, tb);
153c1a9b
AS
5558 if (dpipe_table_show(ctx, nla_table))
5559 goto err_table_show;
ead18027
AS
5560 if (ctx->print_tables)
5561 pr_out_handle_end(ctx->dl);
153c1a9b
AS
5562 }
5563 return 0;
5564
5565err_table_show:
ead18027
AS
5566 if (ctx->print_tables)
5567 pr_out_handle_end(ctx->dl);
153c1a9b
AS
5568 return -EINVAL;
5569}
5570
5571static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
5572{
5573 struct dpipe_ctx *ctx = data;
5574 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5575 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5576
5577 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5578 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5579 !tb[DEVLINK_ATTR_DPIPE_TABLES])
5580 return MNL_CB_ERROR;
5581
5582 if (dpipe_tables_show(ctx, tb))
5583 return MNL_CB_ERROR;
5584 return MNL_CB_OK;
5585}
5586
ead18027
AS
5587static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data);
5588
153c1a9b
AS
5589static int cmd_dpipe_table_show(struct dl *dl)
5590{
5591 struct nlmsghdr *nlh;
ead18027
AS
5592 struct dpipe_ctx dpipe_ctx = {};
5593 struct resource_ctx resource_ctx = {};
153c1a9b
AS
5594 uint16_t flags = NLM_F_REQUEST;
5595 int err;
5596
ead18027 5597 err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
06a2cda9
AS
5598 if (err)
5599 return err;
153c1a9b 5600
ead18027
AS
5601 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
5602
5603 err = dpipe_ctx_init(&dpipe_ctx, dl);
153c1a9b 5604 if (err)
ead18027
AS
5605 return err;
5606
5607 dpipe_ctx.print_tables = true;
153c1a9b 5608
153c1a9b 5609 dl_opts_put(nlh, dl);
ead18027
AS
5610 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb,
5611 &dpipe_ctx);
153c1a9b 5612 if (err) {
ead18027
AS
5613 pr_err("error get headers %s\n", strerror(dpipe_ctx.err));
5614 goto err_headers_get;
5615 }
5616
5617 err = resource_ctx_init(&resource_ctx, dl);
5618 if (err)
5619 goto err_resource_ctx_init;
5620
5621 resource_ctx.print_resources = false;
5622 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags);
5623 dl_opts_put(nlh, dl);
5624 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
5625 &resource_ctx);
0e7e1819
JP
5626 if (!err)
5627 dpipe_ctx.resources = resource_ctx.resources;
153c1a9b
AS
5628
5629 flags = NLM_F_REQUEST | NLM_F_ACK;
5630 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
5631 dl_opts_put(nlh, dl);
5632
5633 pr_out_section_start(dl, "table");
ead18027 5634 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx);
153c1a9b 5635 pr_out_section_end(dl);
ead18027
AS
5636
5637 resource_ctx_fini(&resource_ctx);
5638 dpipe_ctx_fini(&dpipe_ctx);
5639 return 0;
5640
ead18027
AS
5641err_resource_ctx_init:
5642err_headers_get:
5643 dpipe_ctx_fini(&dpipe_ctx);
153c1a9b
AS
5644 return err;
5645}
5646
5647static int cmd_dpipe_table_set(struct dl *dl)
5648{
5649 struct nlmsghdr *nlh;
5650 int err;
5651
5652 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
5653 NLM_F_REQUEST | NLM_F_ACK);
5654
5655 err = dl_argv_parse_put(nlh, dl,
5656 DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
5657 DL_OPT_DPIPE_TABLE_COUNTERS, 0);
5658 if (err)
5659 return err;
5660
5661 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
5662}
5663
31639589
AS
5664enum dpipe_value_type {
5665 DPIPE_VALUE_TYPE_VALUE,
5666 DPIPE_VALUE_TYPE_MASK,
5667};
5668
5669static const char *
5670dpipe_value_type_e2s(enum dpipe_value_type type)
5671{
5672 switch (type) {
5673 case DPIPE_VALUE_TYPE_VALUE:
5674 return "value";
5675 case DPIPE_VALUE_TYPE_MASK:
5676 return "value_mask";
5677 default:
5678 return "<unknown>";
5679 }
5680}
5681
5682struct dpipe_field_printer {
5683 unsigned int field_id;
5684 void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
5685};
5686
5687struct dpipe_header_printer {
5688 struct dpipe_field_printer *printers;
5689 unsigned int printers_count;
5690 unsigned int header_id;
5691};
5692
b2947f8b
AS
5693static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
5694 enum dpipe_value_type type,
5695 void *value)
5696{
5697 struct in_addr ip_addr;
5698
5699 ip_addr.s_addr = htonl(*(uint32_t *)value);
3666eb0e
RD
5700 check_indent_newline(ctx->dl);
5701 print_string_name_value(dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
b2947f8b
AS
5702}
5703
5704static void
5705dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
5706 enum dpipe_value_type type,
5707 void *value)
5708{
3666eb0e
RD
5709 check_indent_newline(ctx->dl);
5710 print_string_name_value(dpipe_value_type_e2s(type),
5711 ether_ntoa((struct ether_addr *)value));
b2947f8b
AS
5712}
5713
5714static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
5715 enum dpipe_value_type type,
5716 void *value)
5717{
5718 char str[INET6_ADDRSTRLEN];
5719
5720 inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
3666eb0e
RD
5721 check_indent_newline(ctx->dl);
5722 print_string_name_value(dpipe_value_type_e2s(type), str);
b2947f8b
AS
5723}
5724
5725static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
5726 {
5727 .printer = dpipe_field_printer_ipv4_addr,
5728 .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
5729 }
5730};
5731
5732static struct dpipe_header_printer dpipe_header_printer_ipv4 = {
5733 .printers = dpipe_field_printers_ipv4,
5734 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
5735 .header_id = DEVLINK_DPIPE_HEADER_IPV4,
5736};
5737
5738static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
5739 {
5740 .printer = dpipe_field_printer_ethernet_addr,
5741 .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
5742 },
5743};
5744
5745static struct dpipe_header_printer dpipe_header_printer_ethernet = {
5746 .printers = dpipe_field_printers_ethernet,
5747 .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
5748 .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
5749};
5750
5751static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
5752 {
5753 .printer = dpipe_field_printer_ipv6_addr,
5754 .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
5755 }
5756};
5757
5758static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
5759 .printers = dpipe_field_printers_ipv6,
5760 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
5761 .header_id = DEVLINK_DPIPE_HEADER_IPV6,
5762};
5763
5764static struct dpipe_header_printer *dpipe_header_printers[] = {
5765 &dpipe_header_printer_ipv4,
5766 &dpipe_header_printer_ethernet,
5767 &dpipe_header_printer_ipv6,
5768};
31639589
AS
5769
5770static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
5771 struct dpipe_op_info *info,
5772 enum dpipe_value_type type,
5773 void *value)
153c1a9b 5774{
31639589
AS
5775 unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
5776 struct dpipe_header_printer *header_printer;
5777 struct dpipe_field_printer *field_printer;
5778 unsigned int field_printers_count;
5779 int j;
5780 int i;
5781
5782 for (i = 0; i < header_printers_count; i++) {
5783 header_printer = dpipe_header_printers[i];
5784 if (header_printer->header_id != info->header_id)
5785 continue;
5786 field_printers_count = header_printer->printers_count;
5787 for (j = 0; j < field_printers_count; j++) {
5788 field_printer = &header_printer->printers[j];
5789 if (field_printer->field_id != info->field_id)
5790 continue;
5791 field_printer->printer(ctx, type, value);
5792 return 0;
5793 }
5794 }
5795
5796 return -EINVAL;
5797}
5798
5799static void __pr_out_entry_value(struct dpipe_ctx *ctx,
5800 void *value,
5801 unsigned int value_len,
5802 struct dpipe_op_info *info,
5803 enum dpipe_value_type type)
5804{
5805 if (info->header_global &&
5806 !dpipe_print_prot_header(ctx, info, type, value))
5807 return;
5808
5809 if (value_len == sizeof(uint32_t)) {
5810 uint32_t *value_32 = value;
5811
ff360fe9
RD
5812 check_indent_newline(ctx->dl);
5813 print_uint_name_value(dpipe_value_type_e2s(type), *value_32);
31639589
AS
5814 }
5815}
5816
5817static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
5818 struct nlattr **nla_match_value,
5819 struct dpipe_op_info *info)
5820{
5821 void *value, *value_mask;
5822 uint32_t value_mapping;
153c1a9b
AS
5823 uint16_t value_len;
5824 bool mask, mapping;
5825
5826 mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
5827 mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
5828
5829 value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
31639589 5830 value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
153c1a9b 5831
31639589
AS
5832 if (mapping) {
5833 value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
ff360fe9
RD
5834 check_indent_newline(ctx->dl);
5835 print_uint(PRINT_ANY, "mapping_value", "mapping_value %u", value_mapping);
31639589 5836 }
153c1a9b 5837
31639589
AS
5838 if (mask) {
5839 value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
5840 __pr_out_entry_value(ctx, value_mask, value_len, info,
5841 DPIPE_VALUE_TYPE_MASK);
153c1a9b
AS
5842 }
5843
31639589 5844 __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
153c1a9b
AS
5845}
5846
5847static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
5848 struct nlattr *nl)
5849{
5850 struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
92b2a5bb 5851 struct dpipe_match match;
153c1a9b
AS
5852 int err;
5853
5854 err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
5855 if (err != MNL_CB_OK)
5856 return -EINVAL;
5857
5858 if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
5859 !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
5860 return -EINVAL;
5861 }
5862
5863 pr_out_entry_start(ctx->dl);
92b2a5bb
AS
5864 if (dpipe_match_parse(&match,
5865 nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
5866 goto err_match_parse;
5867 pr_out_dpipe_match(&match, ctx);
31639589 5868 pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
153c1a9b
AS
5869 pr_out_entry_end(ctx->dl);
5870
5871 return 0;
5872
92b2a5bb 5873err_match_parse:
153c1a9b
AS
5874 pr_out_entry_end(ctx->dl);
5875 return -EINVAL;
5876}
5877
5878static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
5879 struct nlattr *nl)
5880{
5881 struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
92b2a5bb 5882 struct dpipe_action action;
153c1a9b
AS
5883 int err;
5884
5885 err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
5886 if (err != MNL_CB_OK)
5887 return -EINVAL;
5888
5889 if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
5890 !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
5891 return -EINVAL;
5892 }
5893
5894 pr_out_entry_start(ctx->dl);
92b2a5bb
AS
5895 if (dpipe_action_parse(&action,
5896 nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
5897 goto err_action_parse;
5898 pr_out_dpipe_action(&action, ctx);
31639589 5899 pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
153c1a9b
AS
5900 pr_out_entry_end(ctx->dl);
5901
5902 return 0;
5903
92b2a5bb 5904err_action_parse:
153c1a9b
AS
5905 pr_out_entry_end(ctx->dl);
5906 return -EINVAL;
5907}
5908
5909static int
5910dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
5911 struct nlattr *nla_action_values)
5912{
5913 struct nlattr *nla_action_value;
5914
5915 mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
5916 if (dpipe_entry_action_value_show(ctx, nla_action_value))
5917 return -EINVAL;
5918 }
5919 return 0;
5920}
5921
5922static int
5923dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
5924 struct nlattr *nla_match_values)
5925{
5926 struct nlattr *nla_match_value;
5927
5928 mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
5929 if (dpipe_entry_match_value_show(ctx, nla_match_value))
5930 return -EINVAL;
5931 }
5932 return 0;
5933}
5934
5935static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
5936{
5937 struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
5938 uint32_t entry_index;
5939 uint64_t counter;
5940 int err;
5941
5942 err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
5943 if (err != MNL_CB_OK)
5944 return -EINVAL;
5945
5946 if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
5947 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
5948 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
5949 return -EINVAL;
5950 }
5951
ff360fe9 5952 check_indent_newline(ctx->dl);
153c1a9b 5953 entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
ff360fe9 5954 print_uint(PRINT_ANY, "index", "index %u", entry_index);
153c1a9b
AS
5955
5956 if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
5957 counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
ff360fe9 5958 print_uint(PRINT_ANY, "counter", " counter %u", counter);
153c1a9b
AS
5959 }
5960
5961 pr_out_array_start(ctx->dl, "match_value");
5962 if (dpipe_tables_match_values_show(ctx,
5963 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
5964 goto err_match_values_show;
5965 pr_out_array_end(ctx->dl);
5966
5967 pr_out_array_start(ctx->dl, "action_value");
5968 if (dpipe_tables_action_values_show(ctx,
5969 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
5970 goto err_action_values_show;
5971 pr_out_array_end(ctx->dl);
5972 return 0;
5973
5974err_action_values_show:
5975err_match_values_show:
5976 pr_out_array_end(ctx->dl);
5977 return -EINVAL;
5978}
5979
5980static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
5981{
5982 struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
5983 struct nlattr *nla_entry;
5984
5985 mnl_attr_for_each_nested(nla_entry, nla_entries) {
5986 pr_out_handle_start_arr(ctx->dl, tb);
5987 if (dpipe_entry_show(ctx, nla_entry))
5988 goto err_entry_show;
5989 pr_out_handle_end(ctx->dl);
5990 }
5991 return 0;
5992
5993err_entry_show:
5994 pr_out_handle_end(ctx->dl);
5995 return -EINVAL;
5996}
5997
5998static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
5999{
6000 struct dpipe_ctx *ctx = data;
6001 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6002 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6003
6004 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6005 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6006 !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
6007 return MNL_CB_ERROR;
6008
6009 if (dpipe_table_entries_show(ctx, tb))
6010 return MNL_CB_ERROR;
6011 return MNL_CB_OK;
6012}
6013
6014static int cmd_dpipe_table_dump(struct dl *dl)
6015{
6016 struct nlmsghdr *nlh;
06a2cda9 6017 struct dpipe_ctx ctx = {};
153c1a9b
AS
6018 uint16_t flags = NLM_F_REQUEST;
6019 int err;
6020
06a2cda9
AS
6021 err = dpipe_ctx_init(&ctx, dl);
6022 if (err)
6023 return err;
153c1a9b
AS
6024
6025 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
6026 if (err)
6027 goto out;
6028
6029 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
6030 dl_opts_put(nlh, dl);
06a2cda9 6031 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
153c1a9b 6032 if (err) {
06a2cda9 6033 pr_err("error get headers %s\n", strerror(ctx.err));
153c1a9b
AS
6034 goto out;
6035 }
6036
6037 flags = NLM_F_REQUEST | NLM_F_ACK;
6038 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
6039 dl_opts_put(nlh, dl);
6040
6041 pr_out_section_start(dl, "table_entry");
06a2cda9 6042 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx);
153c1a9b
AS
6043 pr_out_section_end(dl);
6044out:
06a2cda9 6045 dpipe_ctx_fini(&ctx);
153c1a9b
AS
6046 return err;
6047}
6048
153c1a9b
AS
6049static int cmd_dpipe_table(struct dl *dl)
6050{
6051 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
b2522187 6052 cmd_dpipe_help();
153c1a9b
AS
6053 return 0;
6054 } else if (dl_argv_match(dl, "show")) {
6055 dl_arg_inc(dl);
6056 return cmd_dpipe_table_show(dl);
6057 } else if (dl_argv_match(dl, "set")) {
6058 dl_arg_inc(dl);
6059 return cmd_dpipe_table_set(dl);
6060 } else if (dl_argv_match(dl, "dump")) {
6061 dl_arg_inc(dl);
6062 return cmd_dpipe_table_dump(dl);
6063 }
6064 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6065 return -ENOENT;
6066}
6067
153c1a9b
AS
6068static int cmd_dpipe(struct dl *dl)
6069{
6070 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6071 cmd_dpipe_help();
6072 return 0;
6073 } else if (dl_argv_match(dl, "header")) {
6074 dl_arg_inc(dl);
6075 return cmd_dpipe_header(dl);
6076 } else if (dl_argv_match(dl, "table")) {
6077 dl_arg_inc(dl);
6078 return cmd_dpipe_table(dl);
6079 }
6080 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6081 return -ENOENT;
6082}
6083
8cd64409
AS
6084static int
6085resource_parse(struct resource_ctx *ctx, struct resource *resource,
6086 struct nlattr **nla_resource)
6087{
6088 if (!nla_resource[DEVLINK_ATTR_RESOURCE_NAME] ||
6089 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE] ||
6090 !nla_resource[DEVLINK_ATTR_RESOURCE_ID] ||
6091 !nla_resource[DEVLINK_ATTR_RESOURCE_UNIT] ||
6092 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN] ||
6093 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX] ||
6094 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]) {
6095 return -EINVAL;
6096 }
6097
6098 resource->name = strdup(mnl_attr_get_str(nla_resource[DEVLINK_ATTR_RESOURCE_NAME]));
6099 resource->size = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE]);
6100 resource->id = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_ID]);
6101 resource->unit = mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_UNIT]);
6102 resource->size_min = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN]);
6103 resource->size_max = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX]);
6104 resource->size_gran = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]);
6105
6106 if (nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW])
6107 resource->size_new = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW]);
6108 else
6109 resource->size_new = resource->size;
6110
6111 if (nla_resource[DEVLINK_ATTR_RESOURCE_OCC]) {
6112 resource->size_occ = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_OCC]);
6113 resource->occ_valid = true;
6114 }
6115
6116 if (resource->size_new != resource->size)
6117 ctx->pending_change = true;
6118
6119 return 0;
6120}
6121
6122static int
6123resource_get(struct resource_ctx *ctx, struct resource *resource,
6124 struct resource *parent_resource, struct nlattr *nl)
6125{
6126 struct nlattr *nla_resource[DEVLINK_ATTR_MAX + 1] = {};
6127 struct nlattr *nla_child_resource;
6128 struct nlattr *nla_resources;
6129 bool top = false;
6130 int err;
6131
6132 if (!resource) {
6133 nla_resources = nl;
6134 top = true;
6135 goto out;
6136 }
6137
6138 err = mnl_attr_parse_nested(nl, attr_cb, nla_resource);
6139 if (err != MNL_CB_OK)
6140 return -EINVAL;
6141
6142 err = resource_parse(ctx, resource, nla_resource);
6143 if (err)
6144 return err;
6145
6146 resource->parent = parent_resource;
6147 if (!nla_resource[DEVLINK_ATTR_RESOURCE_LIST])
6148 return 0;
6149
6150 resource->size_valid = !!mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_VALID]);
6151 nla_resources = nla_resource[DEVLINK_ATTR_RESOURCE_LIST];
6152out:
6153 mnl_attr_for_each_nested(nla_child_resource, nla_resources) {
6154 struct resource *child_resource;
6155 struct list_head *list;
6156
6157 child_resource = resource_alloc();
6158 if (!child_resource)
6159 return -ENOMEM;
6160
6161 if (top)
6162 list = &ctx->resources->resource_list;
6163 else
6164 list = &resource->resource_list;
6165
6166 list_add_tail(&child_resource->list, list);
6167 err = resource_get(ctx, child_resource, resource,
6168 nla_child_resource);
6169 if (err)
6170 return err;
6171 }
6172
6173 return 0;
6174}
6175
6176static const char *resource_unit_str_get(enum devlink_resource_unit unit)
6177{
6178 switch (unit) {
6179 case DEVLINK_RESOURCE_UNIT_ENTRY: return "entry";
6180 default: return "<unknown unit>";
6181 }
6182}
6183
6184static void resource_show(struct resource *resource,
6185 struct resource_ctx *ctx)
6186{
6187 struct resource *child_resource;
ead18027 6188 struct dpipe_table *table;
8cd64409 6189 struct dl *dl = ctx->dl;
ead18027 6190 bool array = false;
8cd64409 6191
3666eb0e
RD
6192 check_indent_newline(dl);
6193 print_string(PRINT_ANY, "name", "name %s", resource->name);
8cd64409
AS
6194 if (dl->verbose)
6195 resource_path_print(dl, ctx->resources, resource->id);
43eb8728 6196 pr_out_u64(dl, "size", resource->size);
8cd64409 6197 if (resource->size != resource->size_new)
43eb8728 6198 pr_out_u64(dl, "size_new", resource->size_new);
8cd64409 6199 if (resource->occ_valid)
ff360fe9 6200 print_uint(PRINT_ANY, "occ", " occ %u", resource->size_occ);
3666eb0e
RD
6201 print_string(PRINT_ANY, "unit", " unit %s",
6202 resource_unit_str_get(resource->unit));
8cd64409
AS
6203
6204 if (resource->size_min != resource->size_max) {
ff360fe9
RD
6205 print_uint(PRINT_ANY, "size_min", " size_min %u",
6206 resource->size_min);
43eb8728 6207 pr_out_u64(dl, "size_max", resource->size_max);
ff360fe9
RD
6208 print_uint(PRINT_ANY, "size_gran", " size_gran %u",
6209 resource->size_gran);
8cd64409
AS
6210 }
6211
ead18027
AS
6212 list_for_each_entry(table, &ctx->tables->table_list, list)
6213 if (table->resource_id == resource->id &&
6214 table->resource_valid)
6215 array = true;
6216
6217 if (array)
6218 pr_out_array_start(dl, "dpipe_tables");
6219 else
3666eb0e
RD
6220 print_string(PRINT_ANY, "dpipe_tables", " dpipe_tables none",
6221 "none");
ead18027
AS
6222
6223 list_for_each_entry(table, &ctx->tables->table_list, list) {
6224 if (table->resource_id != resource->id ||
6225 !table->resource_valid)
6226 continue;
6227 pr_out_entry_start(dl);
3666eb0e
RD
6228 check_indent_newline(dl);
6229 print_string(PRINT_ANY, "table_name", "table_name %s",
6230 table->name);
ead18027
AS
6231 pr_out_entry_end(dl);
6232 }
6233 if (array)
6234 pr_out_array_end(dl);
6235
8cd64409
AS
6236 if (list_empty(&resource->resource_list))
6237 return;
6238
3666eb0e
RD
6239 if (ctx->pending_change) {
6240 check_indent_newline(dl);
6241 print_string(PRINT_ANY, "size_valid", "size_valid %s",
6242 resource->size_valid ? "true" : "false");
6243 }
8cd64409
AS
6244 pr_out_array_start(dl, "resources");
6245 list_for_each_entry(child_resource, &resource->resource_list, list) {
6246 pr_out_entry_start(dl);
6247 resource_show(child_resource, ctx);
6248 pr_out_entry_end(dl);
6249 }
6250 pr_out_array_end(dl);
6251}
6252
6253static void
6254resources_show(struct resource_ctx *ctx, struct nlattr **tb)
6255{
6256 struct resources *resources = ctx->resources;
6257 struct resource *resource;
6258
6259 list_for_each_entry(resource, &resources->resource_list, list) {
6260 pr_out_handle_start_arr(ctx->dl, tb);
6261 resource_show(resource, ctx);
6262 pr_out_handle_end(ctx->dl);
6263 }
6264}
6265
6266static int resources_get(struct resource_ctx *ctx, struct nlattr **tb)
6267{
6268 return resource_get(ctx, NULL, NULL, tb[DEVLINK_ATTR_RESOURCE_LIST]);
6269}
6270
6271static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data)
6272{
6273 struct resource_ctx *ctx = data;
6274 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6275 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6276 int err;
6277
6278 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6279 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6280 !tb[DEVLINK_ATTR_RESOURCE_LIST])
6281 return MNL_CB_ERROR;
6282
6283 err = resources_get(ctx, tb);
6284 if (err) {
6285 ctx->err = err;
6286 return MNL_CB_ERROR;
6287 }
6288
6289 if (ctx->print_resources)
6290 resources_show(ctx, tb);
6291
6292 return MNL_CB_OK;
6293}
6294
6295static int cmd_resource_show(struct dl *dl)
6296{
6297 struct nlmsghdr *nlh;
ead18027
AS
6298 struct dpipe_ctx dpipe_ctx = {};
6299 struct resource_ctx resource_ctx = {};
8cd64409
AS
6300 int err;
6301
ead18027 6302 err = dl_argv_parse(dl, DL_OPT_HANDLE, 0);
8cd64409
AS
6303 if (err)
6304 return err;
6305
ead18027
AS
6306 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET,
6307 NLM_F_REQUEST);
6308 dl_opts_put(nlh, dl);
6309
6310 err = dpipe_ctx_init(&dpipe_ctx, dl);
8cd64409
AS
6311 if (err)
6312 return err;
6313
ead18027
AS
6314 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb,
6315 &dpipe_ctx);
6316 if (err) {
6317 pr_err("error get tables %s\n", strerror(dpipe_ctx.err));
6318 goto out;
6319 }
6320
6321 err = resource_ctx_init(&resource_ctx, dl);
6322 if (err)
6323 goto out;
6324
6325 resource_ctx.print_resources = true;
6326 resource_ctx.tables = dpipe_ctx.tables;
6327 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6328 NLM_F_REQUEST | NLM_F_ACK);
6329 dl_opts_put(nlh, dl);
8cd64409 6330 pr_out_section_start(dl, "resources");
ead18027
AS
6331 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
6332 &resource_ctx);
8cd64409 6333 pr_out_section_end(dl);
ead18027
AS
6334 resource_ctx_fini(&resource_ctx);
6335out:
6336 dpipe_ctx_fini(&dpipe_ctx);
8cd64409
AS
6337 return err;
6338}
6339
6340static void cmd_resource_help(void)
6341{
6342 pr_err("Usage: devlink resource show DEV\n"
6343 " devlink resource set DEV path PATH size SIZE\n");
6344}
6345
6346static struct resource *
6347resource_find_by_name(struct list_head *list, char *name)
6348{
6349 struct resource *resource;
6350
6351 list_for_each_entry(resource, list, list) {
6352 if (!strcmp(resource->name, name))
6353 return resource;
6354 }
6355 return NULL;
6356}
6357
6358static int
6359resource_path_parse(struct resource_ctx *ctx, const char *resource_path,
6360 uint32_t *p_resource_id, bool *p_resource_valid)
6361{
6362 struct resource *resource;
6363 uint32_t resource_id = 0;
6364 char *resource_path_dup;
6365 struct list_head *list;
6366 const char del[] = "/";
6367 char *resource_name;
6368
6369 resource_path_dup = strdup(resource_path);
6370 list = &ctx->resources->resource_list;
6371 resource_name = strtok(resource_path_dup, del);
6372 while (resource_name != NULL) {
6373 resource = resource_find_by_name(list, resource_name);
6374 if (!resource)
6375 goto err_resource_lookup;
6376
6377 list = &resource->resource_list;
6378 resource_name = strtok(NULL, del);
6379 resource_id = resource->id;
6380 }
6381 free(resource_path_dup);
6382 *p_resource_valid = true;
6383 *p_resource_id = resource_id;
6384 return 0;
6385
6386err_resource_lookup:
6387 free(resource_path_dup);
6388 return -EINVAL;
6389}
6390
6391static int cmd_resource_set(struct dl *dl)
6392{
6393 struct nlmsghdr *nlh;
6394 struct resource_ctx ctx = {};
6395 int err;
6396
6397 err = resource_ctx_init(&ctx, dl);
6398 if (err)
6399 return err;
6400
6401 ctx.print_resources = false;
6402 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_RESOURCE_PATH |
6403 DL_OPT_RESOURCE_SIZE, 0);
6404 if (err)
6405 goto out;
6406
6407 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6408 NLM_F_REQUEST);
6409 dl_opts_put(nlh, dl);
6410 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, &ctx);
6411 if (err) {
6412 pr_err("error getting resources %s\n", strerror(ctx.err));
6413 goto out;
6414 }
6415
6416 err = resource_path_parse(&ctx, dl->opts.resource_path,
6417 &dl->opts.resource_id,
6418 &dl->opts.resource_id_valid);
6419 if (err) {
b1ffc1f4 6420 pr_err("error parsing resource path %s\n", strerror(-err));
8cd64409
AS
6421 goto out;
6422 }
6423
6424 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_SET,
6425 NLM_F_REQUEST | NLM_F_ACK);
6426
6427 dl_opts_put(nlh, dl);
6428 err = _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6429out:
6430 resource_ctx_fini(&ctx);
6431 return err;
6432}
6433
6434static int cmd_resource(struct dl *dl)
6435{
6436 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6437 cmd_resource_help();
6438 return 0;
6439 } else if (dl_argv_match(dl, "show")) {
6440 dl_arg_inc(dl);
6441 return cmd_resource_show(dl);
6442 } else if (dl_argv_match(dl, "set")) {
6443 dl_arg_inc(dl);
6444 return cmd_resource_set(dl);
6445 }
6446 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6447 return -ENOENT;
6448}
6449
8b4fbf0b
AV
6450static void pr_out_region_handle_start(struct dl *dl, struct nlattr **tb)
6451{
6452 const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
6453 const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
6454 const char *region_name = mnl_attr_get_str(tb[DEVLINK_ATTR_REGION_NAME]);
6455 char buf[256];
6456
6457 sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name);
b20555e4
RD
6458 if (dl->json_output)
6459 open_json_object(buf);
6460 else
8b4fbf0b 6461 pr_out("%s:", buf);
8b4fbf0b
AV
6462}
6463
6464static void pr_out_region_handle_end(struct dl *dl)
6465{
6466 if (dl->json_output)
b20555e4 6467 close_json_object();
8b4fbf0b
AV
6468 else
6469 pr_out("\n");
6470}
6471
6472static void pr_out_region_snapshots_start(struct dl *dl, bool array)
6473{
56b725a4 6474 __pr_out_indent_newline(dl);
b20555e4
RD
6475 if (dl->json_output)
6476 open_json_array(PRINT_JSON, "snapshot");
6477 else
56b725a4 6478 pr_out("snapshot %s", array ? "[" : "");
8b4fbf0b
AV
6479}
6480
6481static void pr_out_region_snapshots_end(struct dl *dl, bool array)
6482{
6483 if (dl->json_output)
b20555e4 6484 close_json_array(PRINT_JSON, NULL);
8b4fbf0b
AV
6485 else if (array)
6486 pr_out("]");
6487}
6488
6489static void pr_out_region_snapshots_id(struct dl *dl, struct nlattr **tb, int index)
6490{
6491 uint32_t snapshot_id;
6492
6493 if (!tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6494 return;
6495
6496 snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
6497
6498 if (dl->json_output)
b20555e4 6499 print_uint(PRINT_JSON, NULL, NULL, snapshot_id);
8b4fbf0b
AV
6500 else
6501 pr_out("%s%u", index ? " " : "", snapshot_id);
6502}
6503
6504static void pr_out_snapshots(struct dl *dl, struct nlattr **tb)
6505{
6506 struct nlattr *tb_snapshot[DEVLINK_ATTR_MAX + 1] = {};
6507 struct nlattr *nla_sanpshot;
6508 int err, index = 0;
6509
6510 pr_out_region_snapshots_start(dl, true);
6511 mnl_attr_for_each_nested(nla_sanpshot, tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) {
6512 err = mnl_attr_parse_nested(nla_sanpshot, attr_cb, tb_snapshot);
6513 if (err != MNL_CB_OK)
6514 return;
6515 pr_out_region_snapshots_id(dl, tb_snapshot, index++);
6516 }
6517 pr_out_region_snapshots_end(dl, true);
6518}
6519
6520static void pr_out_snapshot(struct dl *dl, struct nlattr **tb)
6521{
6522 pr_out_region_snapshots_start(dl, false);
6523 pr_out_region_snapshots_id(dl, tb, 0);
6524 pr_out_region_snapshots_end(dl, false);
6525}
6526
6527static void pr_out_region(struct dl *dl, struct nlattr **tb)
6528{
6529 pr_out_region_handle_start(dl, tb);
6530
6531 if (tb[DEVLINK_ATTR_REGION_SIZE])
6532 pr_out_u64(dl, "size",
6533 mnl_attr_get_u64(tb[DEVLINK_ATTR_REGION_SIZE]));
6534
6535 if (tb[DEVLINK_ATTR_REGION_SNAPSHOTS])
6536 pr_out_snapshots(dl, tb);
6537
6538 if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6539 pr_out_snapshot(dl, tb);
6540
6541 pr_out_region_handle_end(dl);
6542}
6543
6544static int cmd_region_show_cb(const struct nlmsghdr *nlh, void *data)
6545{
6546 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6547 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6548 struct dl *dl = data;
6549
6550 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6551 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6552 !tb[DEVLINK_ATTR_REGION_NAME] || !tb[DEVLINK_ATTR_REGION_SIZE])
6553 return MNL_CB_ERROR;
6554
6555 pr_out_region(dl, tb);
6556
6557 return MNL_CB_OK;
6558}
6559
6560static int cmd_region_show(struct dl *dl)
6561{
6562 struct nlmsghdr *nlh;
6563 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6564 int err;
6565
6566 if (dl_argc(dl) == 0)
6567 flags |= NLM_F_DUMP;
6568
6569 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_GET, flags);
6570
6571 if (dl_argc(dl) > 0) {
6572 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0);
6573 if (err)
6574 return err;
6575 }
6576
6577 pr_out_section_start(dl, "regions");
6578 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_show_cb, dl);
6579 pr_out_section_end(dl);
6580 return err;
6581}
6582
6583static int cmd_region_snapshot_del(struct dl *dl)
6584{
6585 struct nlmsghdr *nlh;
6586 int err;
6587
6588 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_DEL,
6589 NLM_F_REQUEST | NLM_F_ACK);
6590
6591 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6592 DL_OPT_REGION_SNAPSHOT_ID, 0);
6593 if (err)
6594 return err;
6595
6596 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6597}
6598
6599static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data)
6600{
6601 struct nlattr *nla_entry, *nla_chunk_data, *nla_chunk_addr;
6602 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6603 struct nlattr *tb_field[DEVLINK_ATTR_MAX + 1] = {};
6604 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6605 struct dl *dl = data;
6606 int err;
6607
6608 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6609 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6610 !tb[DEVLINK_ATTR_REGION_CHUNKS])
6611 return MNL_CB_ERROR;
6612
6613 mnl_attr_for_each_nested(nla_entry, tb[DEVLINK_ATTR_REGION_CHUNKS]) {
6614 err = mnl_attr_parse_nested(nla_entry, attr_cb, tb_field);
6615 if (err != MNL_CB_OK)
6616 return MNL_CB_ERROR;
6617
6618 nla_chunk_data = tb_field[DEVLINK_ATTR_REGION_CHUNK_DATA];
6619 if (!nla_chunk_data)
6620 continue;
6621
6622 nla_chunk_addr = tb_field[DEVLINK_ATTR_REGION_CHUNK_ADDR];
6623 if (!nla_chunk_addr)
6624 continue;
6625
6626 pr_out_region_chunk(dl, mnl_attr_get_payload(nla_chunk_data),
6627 mnl_attr_get_payload_len(nla_chunk_data),
6628 mnl_attr_get_u64(nla_chunk_addr));
6629 }
6630 return MNL_CB_OK;
6631}
6632
6633static int cmd_region_dump(struct dl *dl)
6634{
6635 struct nlmsghdr *nlh;
6636 int err;
6637
6638 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
6639 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
6640
6641 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6642 DL_OPT_REGION_SNAPSHOT_ID, 0);
6643 if (err)
6644 return err;
6645
6646 pr_out_section_start(dl, "dump");
6647 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
6648 pr_out_section_end(dl);
6649 if (!dl->json_output)
6650 pr_out("\n");
6651 return err;
6652}
6653
6654static int cmd_region_read(struct dl *dl)
6655{
6656 struct nlmsghdr *nlh;
6657 int err;
6658
6659 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
6660 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
6661
6662 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6663 DL_OPT_REGION_ADDRESS | DL_OPT_REGION_LENGTH |
6664 DL_OPT_REGION_SNAPSHOT_ID, 0);
6665 if (err)
6666 return err;
6667
6668 pr_out_section_start(dl, "read");
6669 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
6670 pr_out_section_end(dl);
6671 if (!dl->json_output)
6672 pr_out("\n");
6673 return err;
6674}
6675
ec04b6fc
JK
6676static int cmd_region_snapshot_new_cb(const struct nlmsghdr *nlh, void *data)
6677{
6678 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6679 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6680 struct dl *dl = data;
6681
6682 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6683 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6684 !tb[DEVLINK_ATTR_REGION_NAME] ||
6685 !tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6686 return MNL_CB_ERROR;
6687
6688 pr_out_region(dl, tb);
6689
6690 return MNL_CB_OK;
6691}
6692
7ae84fed
JK
6693static int cmd_region_snapshot_new(struct dl *dl)
6694{
6695 struct nlmsghdr *nlh;
6696 int err;
6697
6698 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_NEW,
6699 NLM_F_REQUEST | NLM_F_ACK);
6700
ec04b6fc
JK
6701 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION,
6702 DL_OPT_REGION_SNAPSHOT_ID);
7ae84fed
JK
6703 if (err)
6704 return err;
6705
ec04b6fc
JK
6706 pr_out_section_start(dl, "regions");
6707 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_snapshot_new_cb, dl);
6708 pr_out_section_end(dl);
6709 return err;
7ae84fed
JK
6710}
6711
8b4fbf0b
AV
6712static void cmd_region_help(void)
6713{
6714 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
6715 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
7ae84fed 6716 pr_err(" devlink region new DEV/REGION snapshot SNAPSHOT_ID\n");
8b4fbf0b
AV
6717 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
6718 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
6719}
6720
6721static int cmd_region(struct dl *dl)
6722{
6723 if (dl_no_arg(dl)) {
6724 return cmd_region_show(dl);
6725 } else if (dl_argv_match(dl, "help")) {
6726 cmd_region_help();
6727 return 0;
6728 } else if (dl_argv_match(dl, "show")) {
6729 dl_arg_inc(dl);
6730 return cmd_region_show(dl);
6731 } else if (dl_argv_match(dl, "del")) {
6732 dl_arg_inc(dl);
6733 return cmd_region_snapshot_del(dl);
6734 } else if (dl_argv_match(dl, "dump")) {
6735 dl_arg_inc(dl);
6736 return cmd_region_dump(dl);
6737 } else if (dl_argv_match(dl, "read")) {
6738 dl_arg_inc(dl);
6739 return cmd_region_read(dl);
7ae84fed
JK
6740 } else if (dl_argv_match(dl, "new")) {
6741 dl_arg_inc(dl);
6742 return cmd_region_snapshot_new(dl);
8b4fbf0b
AV
6743 }
6744 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6745 return -ENOENT;
6746}
6747
b18d8919
AL
6748static int cmd_health_set_params(struct dl *dl)
6749{
6750 struct nlmsghdr *nlh;
6751 int err;
6752
6753 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET,
6754 NLM_F_REQUEST | NLM_F_ACK);
211c8d6c 6755 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP | DL_OPT_HEALTH_REPORTER_NAME,
b18d8919 6756 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD |
4aa0c9c9
EBE
6757 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER |
6758 DL_OPT_HEALTH_REPORTER_AUTO_DUMP);
b18d8919
AL
6759 if (err)
6760 return err;
6761
6762 dl_opts_put(nlh, dl);
6763 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6764}
6765
04b583d0
AL
6766static int cmd_health_dump_clear(struct dl *dl)
6767{
6768 struct nlmsghdr *nlh;
6769 int err;
6770
6771 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
6772 NLM_F_REQUEST | NLM_F_ACK);
6773
6774 err = dl_argv_parse_put(nlh, dl,
211c8d6c
VT
6775 DL_OPT_HANDLE | DL_OPT_HANDLEP |
6776 DL_OPT_HEALTH_REPORTER_NAME, 0);
04b583d0
AL
6777 if (err)
6778 return err;
6779
6780 dl_opts_put(nlh, dl);
6781 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6782}
6783
7b8baf83
AL
6784static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
6785{
6786 uint8_t *data;
6787 uint32_t len;
6788
3666eb0e 6789 check_indent_newline(dl);
7b8baf83
AL
6790 switch (type) {
6791 case MNL_TYPE_FLAG:
5a71671a 6792 print_bool(PRINT_ANY, NULL, "%s", mnl_attr_get_u8(nl_data));
7b8baf83
AL
6793 break;
6794 case MNL_TYPE_U8:
5a71671a 6795 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u8(nl_data));
7b8baf83
AL
6796 break;
6797 case MNL_TYPE_U16:
5a71671a 6798 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u16(nl_data));
7b8baf83
AL
6799 break;
6800 case MNL_TYPE_U32:
5a71671a 6801 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u32(nl_data));
7b8baf83
AL
6802 break;
6803 case MNL_TYPE_U64:
5a71671a 6804 print_u64(PRINT_ANY, NULL, "%"PRIu64, mnl_attr_get_u64(nl_data));
7b8baf83
AL
6805 break;
6806 case MNL_TYPE_NUL_STRING:
3666eb0e 6807 print_string(PRINT_ANY, NULL, "%s", mnl_attr_get_str(nl_data));
7b8baf83
AL
6808 break;
6809 case MNL_TYPE_BINARY:
6810 len = mnl_attr_get_payload_len(nl_data);
6811 data = mnl_attr_get_payload(nl_data);
6812 pr_out_binary_value(dl, data, len);
6813 break;
6814 default:
6815 return -EINVAL;
6816 }
6817 return MNL_CB_OK;
6818}
6819
af646bf9
AL
6820static void pr_out_fmsg_name(struct dl *dl, char **name)
6821{
6822 if (!*name)
6823 return;
6824
6825 pr_out_name(dl, *name);
6826 free(*name);
6827 *name = NULL;
6828}
6829
efd12cd2 6830struct nest_entry {
7b8baf83 6831 int attr_type;
efd12cd2 6832 struct list_head list;
7b8baf83
AL
6833};
6834
6835struct fmsg_cb_data {
af646bf9 6836 char *name;
7b8baf83
AL
6837 struct dl *dl;
6838 uint8_t value_type;
efd12cd2 6839 struct list_head entry_list;
7b8baf83
AL
6840};
6841
6842static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
6843 uint8_t *attr_value, bool insert)
6844{
efd12cd2 6845 struct nest_entry *entry;
7b8baf83
AL
6846
6847 if (insert) {
efd12cd2 6848 entry = malloc(sizeof(struct nest_entry));
7b8baf83
AL
6849 if (!entry)
6850 return -ENOMEM;
6851
6852 entry->attr_type = *attr_value;
efd12cd2 6853 list_add(&entry->list, &fmsg_data->entry_list);
7b8baf83 6854 } else {
efd12cd2 6855 if (list_empty(&fmsg_data->entry_list))
7b8baf83 6856 return MNL_CB_ERROR;
efd12cd2
JP
6857 entry = list_first_entry(&fmsg_data->entry_list,
6858 struct nest_entry, list);
7b8baf83 6859 *attr_value = entry->attr_type;
efd12cd2 6860 list_del(&entry->list);
7b8baf83
AL
6861 free(entry);
6862 }
6863 return MNL_CB_OK;
6864}
6865
af646bf9
AL
6866static void pr_out_fmsg_group_start(struct dl *dl, char **name)
6867{
6868 __pr_out_newline();
6869 pr_out_fmsg_name(dl, name);
6870 __pr_out_newline();
6871 __pr_out_indent_inc();
6872}
6873
6874static void pr_out_fmsg_group_end(struct dl *dl)
6875{
6876 __pr_out_newline();
6877 __pr_out_indent_dec();
6878}
6879
6880static void pr_out_fmsg_start_object(struct dl *dl, char **name)
6881{
6882 if (dl->json_output) {
6883 pr_out_fmsg_name(dl, name);
b20555e4 6884 open_json_object(NULL);
af646bf9
AL
6885 } else {
6886 pr_out_fmsg_group_start(dl, name);
6887 }
6888}
6889
6890static void pr_out_fmsg_end_object(struct dl *dl)
6891{
6892 if (dl->json_output)
b20555e4 6893 close_json_object();
af646bf9
AL
6894 else
6895 pr_out_fmsg_group_end(dl);
6896}
6897
6898static void pr_out_fmsg_start_array(struct dl *dl, char **name)
6899{
6900 if (dl->json_output) {
6901 pr_out_fmsg_name(dl, name);
b20555e4 6902 open_json_array(PRINT_JSON, NULL);
af646bf9
AL
6903 } else {
6904 pr_out_fmsg_group_start(dl, name);
6905 }
6906}
6907
6908static void pr_out_fmsg_end_array(struct dl *dl)
6909{
6910 if (dl->json_output)
b20555e4 6911 close_json_array(PRINT_JSON, NULL);
af646bf9
AL
6912 else
6913 pr_out_fmsg_group_end(dl);
6914}
6915
7b8baf83
AL
6916static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value,
6917 bool start)
6918{
6919 struct dl *dl = fmsg_data->dl;
6920 uint8_t value = nest_value;
6921 int err;
6922
6923 err = cmd_fmsg_nest_queue(fmsg_data, &value, start);
6924 if (err != MNL_CB_OK)
6925 return err;
6926
6927 switch (value) {
6928 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
6929 if (start)
af646bf9 6930 pr_out_fmsg_start_object(dl, &fmsg_data->name);
7b8baf83 6931 else
af646bf9 6932 pr_out_fmsg_end_object(dl);
7b8baf83
AL
6933 break;
6934 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
6935 break;
6936 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
af646bf9
AL
6937 if (start)
6938 pr_out_fmsg_start_array(dl, &fmsg_data->name);
6939 else
6940 pr_out_fmsg_end_array(dl);
7b8baf83
AL
6941 break;
6942 default:
6943 return -EINVAL;
6944 }
6945 return MNL_CB_OK;
6946}
6947
6948static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data)
6949{
6950 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6951 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6952 struct fmsg_cb_data *fmsg_data = data;
6953 struct dl *dl = fmsg_data->dl;
6954 struct nlattr *nla_object;
6955 int attr_type;
6956 int err;
6957
6958 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6959 if (!tb[DEVLINK_ATTR_FMSG])
6960 return MNL_CB_ERROR;
6961
6962 mnl_attr_for_each_nested(nla_object, tb[DEVLINK_ATTR_FMSG]) {
6963 attr_type = mnl_attr_get_type(nla_object);
6964 switch (attr_type) {
6965 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
6966 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
6967 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
6968 err = cmd_fmsg_nest(fmsg_data, attr_type, true);
6969 if (err != MNL_CB_OK)
6970 return err;
6971 break;
6972 case DEVLINK_ATTR_FMSG_NEST_END:
6973 err = cmd_fmsg_nest(fmsg_data, attr_type, false);
6974 if (err != MNL_CB_OK)
6975 return err;
6976 break;
6977 case DEVLINK_ATTR_FMSG_OBJ_NAME:
af646bf9
AL
6978 free(fmsg_data->name);
6979 fmsg_data->name = strdup(mnl_attr_get_str(nla_object));
6980 if (!fmsg_data->name)
6981 return -ENOMEM;
7b8baf83
AL
6982 break;
6983 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE:
6984 fmsg_data->value_type = mnl_attr_get_u8(nla_object);
6985 break;
6986 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
af646bf9 6987 pr_out_fmsg_name(dl, &fmsg_data->name);
7b8baf83
AL
6988 err = fmsg_value_show(dl, fmsg_data->value_type,
6989 nla_object);
6990 if (err != MNL_CB_OK)
6991 return err;
6992 break;
6993 default:
6994 return -EINVAL;
6995 }
6996 }
6997 return MNL_CB_OK;
6998}
6999
af646bf9
AL
7000static void cmd_fmsg_init(struct dl *dl, struct fmsg_cb_data *data)
7001{
7002 /* FMSG is dynamic: opening of an object or array causes a
7003 * newline. JSON starts with an { or [, but plain text should
7004 * not start with a new line. Ensure this by setting
7005 * g_new_line_count to 1: avoiding newline before the first
7006 * print.
7007 */
7008 g_new_line_count = 1;
7009 data->name = NULL;
7010 data->dl = dl;
7011 INIT_LIST_HEAD(&data->entry_list);
7012}
7013
b4d97ef5 7014static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
7b8baf83
AL
7015{
7016 struct fmsg_cb_data data;
7017 struct nlmsghdr *nlh;
7018 int err;
7019
b4d97ef5 7020 nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
7b8baf83
AL
7021
7022 err = dl_argv_parse_put(nlh, dl,
211c8d6c
VT
7023 DL_OPT_HANDLE | DL_OPT_HANDLEP |
7024 DL_OPT_HEALTH_REPORTER_NAME, 0);
7b8baf83
AL
7025 if (err)
7026 return err;
7027
af646bf9 7028 cmd_fmsg_init(dl, &data);
7b8baf83 7029 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data);
af646bf9 7030 free(data.name);
7b8baf83
AL
7031 return err;
7032}
7033
041e6e65
AL
7034static int cmd_health_dump_show(struct dl *dl)
7035{
b4d97ef5
AL
7036 return cmd_health_object_common(dl,
7037 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
7038 NLM_F_DUMP);
041e6e65
AL
7039}
7040
7b8baf83
AL
7041static int cmd_health_diagnose(struct dl *dl)
7042{
b4d97ef5
AL
7043 return cmd_health_object_common(dl,
7044 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
7045 0);
7b8baf83
AL
7046}
7047
9083a134
AL
7048static int cmd_health_recover(struct dl *dl)
7049{
7050 struct nlmsghdr *nlh;
7051 int err;
7052
7053 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
7054 NLM_F_REQUEST | NLM_F_ACK);
7055
7056 err = dl_argv_parse_put(nlh, dl,
211c8d6c
VT
7057 DL_OPT_HANDLE | DL_OPT_HANDLEP |
7058 DL_OPT_HEALTH_REPORTER_NAME, 0);
9083a134
AL
7059 if (err)
7060 return err;
7061
7062 dl_opts_put(nlh, dl);
7063 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7064}
7065
2f1242ef
AL
7066enum devlink_health_reporter_state {
7067 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
7068 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
7069};
7070
7071static const char *health_state_name(uint8_t state)
7072{
7073 switch (state) {
7074 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY:
7075 return HEALTH_REPORTER_STATE_HEALTHY_STR;
7076 case DEVLINK_HEALTH_REPORTER_STATE_ERROR:
7077 return HEALTH_REPORTER_STATE_ERROR_STR;
7078 default:
7079 return "<unknown state>";
7080 }
7081}
7082
f678a2d0 7083static void pr_out_dump_reporter_format_logtime(struct dl *dl, const struct nlattr *attr)
2f1242ef 7084{
f678a2d0
AL
7085 char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7086 char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7087 uint64_t time_ms = mnl_attr_get_u64(attr);
2f1242ef
AL
7088 struct sysinfo s_info;
7089 struct tm *info;
7090 time_t now, sec;
7091 int err;
7092
7093 time(&now);
7094 info = localtime(&now);
7095 err = sysinfo(&s_info);
7096 if (err)
7097 goto out;
7098 /* Subtract uptime in sec from now yields the time of system
7099 * uptime. To this, add time_ms which is the amount of
7100 * milliseconds elapsed between uptime and the dump taken.
7101 */
7102 sec = now - s_info.uptime + time_ms / 1000;
7103 info = localtime(&sec);
7104out:
f678a2d0
AL
7105 strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
7106 strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
3666eb0e
RD
7107 check_indent_newline(dl);
7108 print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
7109 print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
2f1242ef
AL
7110}
7111
746b66b0
AL
7112static void pr_out_dump_report_timestamp(struct dl *dl, const struct nlattr *attr)
7113{
7114 char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7115 char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
7116 time_t tv_sec;
7117 struct tm *tm;
7118 uint64_t ts;
7119
7120 ts = mnl_attr_get_u64(attr);
7121 tv_sec = ts / 1000000000;
7122 tm = localtime(&tv_sec);
7123
7124 strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", tm);
7125 strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", tm);
7126
3666eb0e
RD
7127 check_indent_newline(dl);
7128 print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
7129 print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
746b66b0
AL
7130}
7131
211c8d6c
VT
7132static void pr_out_health(struct dl *dl, struct nlattr **tb_health,
7133 bool print_device, bool print_port)
2f1242ef
AL
7134{
7135 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7136 enum devlink_health_reporter_state state;
2f1242ef
AL
7137 int err;
7138
7139 err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER],
7140 attr_cb, tb);
7141 if (err != MNL_CB_OK)
7142 return;
7143
7144 if (!tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME] ||
7145 !tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] ||
7146 !tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] ||
7147 !tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE])
7148 return;
7149
211c8d6c
VT
7150 if (!print_device && !print_port)
7151 return;
7152 if (print_port) {
7153 if (!print_device && !tb_health[DEVLINK_ATTR_PORT_INDEX])
7154 return;
7155 else if (tb_health[DEVLINK_ATTR_PORT_INDEX])
7156 pr_out_port_handle_start_arr(dl, tb_health, false);
7157 }
7158 if (print_device) {
7159 if (!print_port && tb_health[DEVLINK_ATTR_PORT_INDEX])
7160 return;
7161 else if (!tb_health[DEVLINK_ATTR_PORT_INDEX])
7162 pr_out_handle_start_arr(dl, tb_health);
7163 }
2f1242ef 7164
3666eb0e
RD
7165 check_indent_newline(dl);
7166 print_string(PRINT_ANY, "reporter", "reporter %s",
7167 mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
2f1242ef
AL
7168 if (!dl->json_output) {
7169 __pr_out_newline();
7170 __pr_out_indent_inc();
7171 }
7172 state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]);
3666eb0e
RD
7173 check_indent_newline(dl);
7174 print_string(PRINT_ANY, "state", "state %s", health_state_name(state));
2f1242ef
AL
7175 pr_out_u64(dl, "error",
7176 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT]));
7177 pr_out_u64(dl, "recover",
7178 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT]));
746b66b0
AL
7179 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS])
7180 pr_out_dump_report_timestamp(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]);
7181 else if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS])
f678a2d0 7182 pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]);
2f1242ef
AL
7183 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
7184 pr_out_u64(dl, "grace_period",
7185 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]));
7186 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
ff360fe9
RD
7187 print_bool(PRINT_ANY, "auto_recover", " auto_recover %s",
7188 mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]));
4aa0c9c9
EBE
7189 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP])
7190 print_bool(PRINT_ANY, "auto_dump", " auto_dump %s",
7191 mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_DUMP]));
2f1242ef
AL
7192
7193 __pr_out_indent_dec();
7194 pr_out_handle_end(dl);
7195}
7196
211c8d6c
VT
7197struct health_ctx {
7198 struct dl *dl;
7199 bool show_device;
7200 bool show_port;
7201};
7202
2f1242ef
AL
7203static int cmd_health_show_cb(const struct nlmsghdr *nlh, void *data)
7204{
7205 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7206 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
211c8d6c
VT
7207 struct health_ctx *ctx = data;
7208 struct dl *dl = ctx->dl;
2f1242ef
AL
7209
7210 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7211 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7212 !tb[DEVLINK_ATTR_HEALTH_REPORTER])
7213 return MNL_CB_ERROR;
7214
211c8d6c 7215 pr_out_health(dl, tb, ctx->show_device, ctx->show_port);
2f1242ef
AL
7216
7217 return MNL_CB_OK;
7218}
7219
211c8d6c 7220static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port)
2f1242ef
AL
7221{
7222 struct nlmsghdr *nlh;
211c8d6c 7223 struct health_ctx ctx = { dl, show_device, show_port };
2f1242ef
AL
7224 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7225 int err;
7226
7227 if (dl_argc(dl) == 0)
7228 flags |= NLM_F_DUMP;
7229 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET,
7230 flags);
7231
7232 if (dl_argc(dl) > 0) {
211c8d6c 7233 ctx.show_port = true;
2f1242ef 7234 err = dl_argv_parse_put(nlh, dl,
211c8d6c 7235 DL_OPT_HANDLE | DL_OPT_HANDLEP |
2f1242ef
AL
7236 DL_OPT_HEALTH_REPORTER_NAME, 0);
7237 if (err)
7238 return err;
7239 }
7240 pr_out_section_start(dl, "health");
7241
211c8d6c 7242 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_health_show_cb, &ctx);
2f1242ef
AL
7243 pr_out_section_end(dl);
7244 return err;
7245}
7246
7247static void cmd_health_help(void)
7248{
211c8d6c
VT
7249 pr_err("Usage: devlink health show [ { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME ]\n");
7250 pr_err(" devlink health recover { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7251 pr_err(" devlink health diagnose { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7252 pr_err(" devlink health dump show { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7253 pr_err(" devlink health dump clear { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
7254 pr_err(" devlink health set { DEV | DEV/PORT_INDEX } reporter REPORTER_NAME\n");
90ce848b
JP
7255 pr_err(" [ grace_period MSEC ]\n");
7256 pr_err(" [ auto_recover { true | false } ]\n");
4aa0c9c9 7257 pr_err(" [ auto_dump { true | false } ]\n");
2f1242ef
AL
7258}
7259
7260static int cmd_health(struct dl *dl)
7261{
7262 if (dl_argv_match(dl, "help")) {
7263 cmd_health_help();
7264 return 0;
7265 } else if (dl_argv_match(dl, "show") ||
7266 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7267 dl_arg_inc(dl);
211c8d6c 7268 return __cmd_health_show(dl, true, true);
9083a134
AL
7269 } else if (dl_argv_match(dl, "recover")) {
7270 dl_arg_inc(dl);
7271 return cmd_health_recover(dl);
7b8baf83
AL
7272 } else if (dl_argv_match(dl, "diagnose")) {
7273 dl_arg_inc(dl);
7274 return cmd_health_diagnose(dl);
041e6e65
AL
7275 } else if (dl_argv_match(dl, "dump")) {
7276 dl_arg_inc(dl);
7277 if (dl_argv_match(dl, "show")) {
7278 dl_arg_inc(dl);
7279 return cmd_health_dump_show(dl);
04b583d0
AL
7280 } else if (dl_argv_match(dl, "clear")) {
7281 dl_arg_inc(dl);
7282 return cmd_health_dump_clear(dl);
041e6e65 7283 }
b18d8919
AL
7284 } else if (dl_argv_match(dl, "set")) {
7285 dl_arg_inc(dl);
7286 return cmd_health_set_params(dl);
2f1242ef
AL
7287 }
7288 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7289 return -ENOENT;
7290}
7291
ef12d6da
IS
7292static const char *trap_type_name(uint8_t type)
7293{
7294 switch (type) {
7295 case DEVLINK_TRAP_TYPE_DROP:
7296 return "drop";
7297 case DEVLINK_TRAP_TYPE_EXCEPTION:
7298 return "exception";
fd71244a
IS
7299 case DEVLINK_TRAP_TYPE_CONTROL:
7300 return "control";
ef12d6da
IS
7301 default:
7302 return "<unknown type>";
7303 }
7304}
7305
7306static const char *trap_action_name(uint8_t action)
7307{
7308 switch (action) {
7309 case DEVLINK_TRAP_ACTION_DROP:
7310 return "drop";
7311 case DEVLINK_TRAP_ACTION_TRAP:
7312 return "trap";
abda1e9d
IS
7313 case DEVLINK_TRAP_ACTION_MIRROR:
7314 return "mirror";
ef12d6da
IS
7315 default:
7316 return "<unknown action>";
7317 }
7318}
7319
7320static const char *trap_metadata_name(const struct nlattr *attr)
7321{
7322 switch (attr->nla_type) {
7323 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT:
7324 return "input_port";
4fe07b81
JP
7325 case DEVLINK_ATTR_TRAP_METADATA_TYPE_FA_COOKIE:
7326 return "flow_action_cookie";
ef12d6da
IS
7327 default:
7328 return "<unknown metadata type>";
7329 }
7330}
7331static void pr_out_trap_metadata(struct dl *dl, struct nlattr *attr)
7332{
7333 struct nlattr *attr_metadata;
7334
7335 pr_out_array_start(dl, "metadata");
3666eb0e
RD
7336 mnl_attr_for_each_nested(attr_metadata, attr) {
7337 check_indent_newline(dl);
7338 print_string(PRINT_ANY, NULL, "%s",
7339 trap_metadata_name(attr_metadata));
7340 }
ef12d6da
IS
7341 pr_out_array_end(dl);
7342}
7343
7344static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array)
7345{
7346 uint8_t action = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_ACTION]);
7347 uint8_t type = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_TYPE]);
7348
7349 if (array)
7350 pr_out_handle_start_arr(dl, tb);
7351 else
7352 __pr_out_handle_start(dl, tb, true, false);
7353
3666eb0e
RD
7354 check_indent_newline(dl);
7355 print_string(PRINT_ANY, "name", "name %s",
7356 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_NAME]));
7357 print_string(PRINT_ANY, "type", " type %s", trap_type_name(type));
ff360fe9 7358 print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
3666eb0e
RD
7359 print_string(PRINT_ANY, "action", " action %s", trap_action_name(action));
7360 print_string(PRINT_ANY, "group", " group %s",
7361 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
ef12d6da
IS
7362 if (dl->verbose)
7363 pr_out_trap_metadata(dl, tb[DEVLINK_ATTR_TRAP_METADATA]);
7364 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7365 pr_out_handle_end(dl);
7366}
7367
7368static int cmd_trap_show_cb(const struct nlmsghdr *nlh, void *data)
7369{
7370 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7371 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7372 struct dl *dl = data;
7373
7374 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7375 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7376 !tb[DEVLINK_ATTR_TRAP_NAME] || !tb[DEVLINK_ATTR_TRAP_TYPE] ||
7377 !tb[DEVLINK_ATTR_TRAP_ACTION] ||
7378 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
7379 !tb[DEVLINK_ATTR_TRAP_METADATA] || !tb[DEVLINK_ATTR_STATS])
7380 return MNL_CB_ERROR;
7381
7382 pr_out_trap(dl, tb, true);
7383
7384 return MNL_CB_OK;
7385}
7386
7387static void cmd_trap_help(void)
7388{
abda1e9d 7389 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop | mirror } ]\n");
ef12d6da 7390 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
abda1e9d 7391 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop | mirror } ]\n");
02a2a668 7392 pr_err(" [ policer POLICER ] [ nopolicer ]\n");
4ede9e9d 7393 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
a66af556
IS
7394 pr_err(" devlink trap policer set DEV policer POLICER [ rate RATE ] [ burst BURST ]\n");
7395 pr_err(" devlink trap policer show DEV policer POLICER\n");
ef12d6da
IS
7396}
7397
7398static int cmd_trap_show(struct dl *dl)
7399{
7400 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7401 struct nlmsghdr *nlh;
7402 int err;
7403
7404 if (dl_argc(dl) == 0)
7405 flags |= NLM_F_DUMP;
7406
7407 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GET, flags);
7408
7409 if (dl_argc(dl) > 0) {
7410 err = dl_argv_parse_put(nlh, dl,
7411 DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0);
7412 if (err)
7413 return err;
7414 }
7415
7416 pr_out_section_start(dl, "trap");
7417 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_show_cb, dl);
7418 pr_out_section_end(dl);
7419
7420 return err;
7421}
7422
7423static int cmd_trap_set(struct dl *dl)
7424{
7425 struct nlmsghdr *nlh;
7426 int err;
7427
7428 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_SET,
7429 NLM_F_REQUEST | NLM_F_ACK);
7430
7431 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME,
7432 DL_OPT_TRAP_ACTION);
7433 if (err)
7434 return err;
7435
7436 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7437}
7438
4ede9e9d
IS
7439static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array)
7440{
7441 if (array)
7442 pr_out_handle_start_arr(dl, tb);
7443 else
7444 __pr_out_handle_start(dl, tb, true, false);
7445
3666eb0e
RD
7446 check_indent_newline(dl);
7447 print_string(PRINT_ANY, "name", "name %s",
7448 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
ff360fe9 7449 print_bool(PRINT_ANY, "generic", " generic %s", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
02a2a668
IS
7450 if (tb[DEVLINK_ATTR_TRAP_POLICER_ID])
7451 print_uint(PRINT_ANY, "policer", " policer %u",
7452 mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
4ede9e9d
IS
7453 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7454 pr_out_handle_end(dl);
7455}
7456
7457static int cmd_trap_group_show_cb(const struct nlmsghdr *nlh, void *data)
7458{
7459 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7460 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7461 struct dl *dl = data;
7462
7463 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7464 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7465 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] || !tb[DEVLINK_ATTR_STATS])
7466 return MNL_CB_ERROR;
7467
7468 pr_out_trap_group(dl, tb, true);
7469
7470 return MNL_CB_OK;
7471}
7472
7473static int cmd_trap_group_show(struct dl *dl)
7474{
7475 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7476 struct nlmsghdr *nlh;
7477 int err;
7478
7479 if (dl_argc(dl) == 0)
7480 flags |= NLM_F_DUMP;
7481
7482 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags);
7483
7484 if (dl_argc(dl) > 0) {
7485 err = dl_argv_parse_put(nlh, dl,
7486 DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
7487 0);
7488 if (err)
7489 return err;
7490 }
7491
7492 pr_out_section_start(dl, "trap_group");
7493 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_group_show_cb, dl);
7494 pr_out_section_end(dl);
7495
7496 return err;
7497}
7498
7499static int cmd_trap_group_set(struct dl *dl)
7500{
7501 struct nlmsghdr *nlh;
7502 int err;
7503
7504 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET,
7505 NLM_F_REQUEST | NLM_F_ACK);
7506
7507 err = dl_argv_parse_put(nlh, dl,
7508 DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
02a2a668 7509 DL_OPT_TRAP_ACTION | DL_OPT_TRAP_POLICER_ID);
4ede9e9d
IS
7510 if (err)
7511 return err;
7512
7513 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7514}
7515
7516static int cmd_trap_group(struct dl *dl)
7517{
7518 if (dl_argv_match(dl, "help")) {
7519 cmd_trap_help();
7520 return 0;
7521 } else if (dl_argv_match(dl, "show") ||
7522 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7523 dl_arg_inc(dl);
7524 return cmd_trap_group_show(dl);
7525 } else if (dl_argv_match(dl, "set")) {
7526 dl_arg_inc(dl);
7527 return cmd_trap_group_set(dl);
7528 }
7529 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7530 return -ENOENT;
7531}
7532
a66af556
IS
7533static void pr_out_trap_policer(struct dl *dl, struct nlattr **tb, bool array)
7534{
7535 if (array)
7536 pr_out_handle_start_arr(dl, tb);
7537 else
7538 __pr_out_handle_start(dl, tb, true, false);
7539
7540 check_indent_newline(dl);
7541 print_uint(PRINT_ANY, "policer", "policer %u",
7542 mnl_attr_get_u32(tb[DEVLINK_ATTR_TRAP_POLICER_ID]));
7543 print_u64(PRINT_ANY, "rate", " rate %llu",
7544 mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_RATE]));
7545 print_u64(PRINT_ANY, "burst", " burst %llu",
7546 mnl_attr_get_u64(tb[DEVLINK_ATTR_TRAP_POLICER_BURST]));
7547 if (tb[DEVLINK_ATTR_STATS])
7548 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7549 pr_out_handle_end(dl);
7550}
7551
7552static int cmd_trap_policer_show_cb(const struct nlmsghdr *nlh, void *data)
7553{
7554 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7555 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7556 struct dl *dl = data;
7557
7558 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7559 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7560 !tb[DEVLINK_ATTR_TRAP_POLICER_ID] ||
7561 !tb[DEVLINK_ATTR_TRAP_POLICER_RATE] ||
7562 !tb[DEVLINK_ATTR_TRAP_POLICER_BURST])
7563 return MNL_CB_ERROR;
7564
7565 pr_out_trap_policer(dl, tb, true);
7566
7567 return MNL_CB_OK;
7568}
7569
7570static int cmd_trap_policer_show(struct dl *dl)
7571{
7572 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7573 struct nlmsghdr *nlh;
7574 int err;
7575
7576 if (dl_argc(dl) == 0)
7577 flags |= NLM_F_DUMP;
7578
7579 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_GET, flags);
7580
7581 if (dl_argc(dl) > 0) {
7582 err = dl_argv_parse_put(nlh, dl,
7583 DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
7584 0);
7585 if (err)
7586 return err;
7587 }
7588
7589 pr_out_section_start(dl, "trap_policer");
7590 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_policer_show_cb, dl);
7591 pr_out_section_end(dl);
7592
7593 return err;
7594}
7595
7596static int cmd_trap_policer_set(struct dl *dl)
7597{
7598 struct nlmsghdr *nlh;
7599 int err;
7600
7601 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_POLICER_SET,
7602 NLM_F_REQUEST | NLM_F_ACK);
7603
7604 err = dl_argv_parse_put(nlh, dl,
7605 DL_OPT_HANDLE | DL_OPT_TRAP_POLICER_ID,
7606 DL_OPT_TRAP_POLICER_RATE |
7607 DL_OPT_TRAP_POLICER_BURST);
7608 if (err)
7609 return err;
7610
7611 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7612}
7613
7614static int cmd_trap_policer(struct dl *dl)
7615{
7616 if (dl_argv_match(dl, "help")) {
7617 cmd_trap_help();
7618 return 0;
7619 } else if (dl_argv_match(dl, "show") ||
7620 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7621 dl_arg_inc(dl);
7622 return cmd_trap_policer_show(dl);
7623 } else if (dl_argv_match(dl, "set")) {
7624 dl_arg_inc(dl);
7625 return cmd_trap_policer_set(dl);
7626 }
7627 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7628 return -ENOENT;
7629}
7630
ef12d6da
IS
7631static int cmd_trap(struct dl *dl)
7632{
7633 if (dl_argv_match(dl, "help")) {
7634 cmd_trap_help();
7635 return 0;
7636 } else if (dl_argv_match(dl, "show") ||
7637 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7638 dl_arg_inc(dl);
7639 return cmd_trap_show(dl);
7640 } else if (dl_argv_match(dl, "set")) {
7641 dl_arg_inc(dl);
7642 return cmd_trap_set(dl);
4ede9e9d
IS
7643 } else if (dl_argv_match(dl, "group")) {
7644 dl_arg_inc(dl);
7645 return cmd_trap_group(dl);
a66af556
IS
7646 } else if (dl_argv_match(dl, "policer")) {
7647 dl_arg_inc(dl);
7648 return cmd_trap_policer(dl);
ef12d6da
IS
7649 }
7650 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7651 return -ENOENT;
7652}
7653
153c1a9b
AS
7654static void help(void)
7655{
7656 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
29993df8 7657 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
ef12d6da
IS
7658 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
7659 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
153c1a9b
AS
7660}
7661
3e897912 7662static int dl_cmd(struct dl *dl, int argc, char **argv)
153c1a9b 7663{
3e897912
IV
7664 dl->argc = argc;
7665 dl->argv = argv;
7666
153c1a9b
AS
7667 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
7668 help();
7669 return 0;
7670 } else if (dl_argv_match(dl, "dev")) {
7671 dl_arg_inc(dl);
7672 return cmd_dev(dl);
7673 } else if (dl_argv_match(dl, "port")) {
7674 dl_arg_inc(dl);
7675 return cmd_port(dl);
7676 } else if (dl_argv_match(dl, "sb")) {
7677 dl_arg_inc(dl);
7678 return cmd_sb(dl);
7679 } else if (dl_argv_match(dl, "monitor")) {
7680 dl_arg_inc(dl);
7681 return cmd_mon(dl);
7682 } else if (dl_argv_match(dl, "dpipe")) {
7683 dl_arg_inc(dl);
7684 return cmd_dpipe(dl);
8cd64409
AS
7685 } else if (dl_argv_match(dl, "resource")) {
7686 dl_arg_inc(dl);
7687 return cmd_resource(dl);
8b4fbf0b
AV
7688 } else if (dl_argv_match(dl, "region")) {
7689 dl_arg_inc(dl);
7690 return cmd_region(dl);
2f1242ef
AL
7691 } else if (dl_argv_match(dl, "health")) {
7692 dl_arg_inc(dl);
7693 return cmd_health(dl);
ef12d6da
IS
7694 } else if (dl_argv_match(dl, "trap")) {
7695 dl_arg_inc(dl);
7696 return cmd_trap(dl);
153c1a9b
AS
7697 }
7698 pr_err("Object \"%s\" not found\n", dl_argv(dl));
7699 return -ENOENT;
7700}
7701
3e897912 7702static int dl_init(struct dl *dl)
153c1a9b
AS
7703{
7704 int err;
7705
153c1a9b
AS
7706 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
7707 if (!dl->nlg) {
7708 pr_err("Failed to connect to devlink Netlink\n");
7709 return -errno;
7710 }
7711
7712 err = ifname_map_init(dl);
7713 if (err) {
7714 pr_err("Failed to create index map\n");
7715 goto err_ifname_map_create;
7716 }
b20555e4 7717 new_json_obj_plain(dl->json_output);
153c1a9b
AS
7718 return 0;
7719
153c1a9b
AS
7720err_ifname_map_create:
7721 mnlg_socket_close(dl->nlg);
7722 return err;
7723}
7724
7725static void dl_fini(struct dl *dl)
7726{
b20555e4 7727 delete_json_obj_plain();
153c1a9b
AS
7728 ifname_map_fini(dl);
7729 mnlg_socket_close(dl->nlg);
7730}
7731
7732static struct dl *dl_alloc(void)
7733{
7734 struct dl *dl;
7735
7736 dl = calloc(1, sizeof(*dl));
7737 if (!dl)
7738 return NULL;
7739 return dl;
7740}
7741
7742static void dl_free(struct dl *dl)
7743{
7744 free(dl);
7745}
7746
3e897912
IV
7747static int dl_batch(struct dl *dl, const char *name, bool force)
7748{
7749 char *line = NULL;
7750 size_t len = 0;
7751 int ret = EXIT_SUCCESS;
7752
7753 if (name && strcmp(name, "-") != 0) {
7754 if (freopen(name, "r", stdin) == NULL) {
7755 fprintf(stderr,
7756 "Cannot open file \"%s\" for reading: %s\n",
7757 name, strerror(errno));
7758 return EXIT_FAILURE;
7759 }
7760 }
7761
7762 cmdlineno = 0;
7763 while (getcmdline(&line, &len, stdin) != -1) {
7764 char *largv[100];
7765 int largc;
7766
7767 largc = makeargs(line, largv, 100);
7768 if (!largc)
7769 continue; /* blank line */
7770
7771 if (dl_cmd(dl, largc, largv)) {
7772 fprintf(stderr, "Command failed %s:%d\n",
7773 name, cmdlineno);
7774 ret = EXIT_FAILURE;
7775 if (!force)
7776 break;
7777 }
7778 }
7779
7780 if (line)
7781 free(line);
7782
7783 return ret;
7784}
7785
153c1a9b
AS
7786int main(int argc, char **argv)
7787{
7788 static const struct option long_options[] = {
7789 { "Version", no_argument, NULL, 'V' },
3e897912
IV
7790 { "force", no_argument, NULL, 'f' },
7791 { "batch", required_argument, NULL, 'b' },
153c1a9b
AS
7792 { "no-nice-names", no_argument, NULL, 'n' },
7793 { "json", no_argument, NULL, 'j' },
7794 { "pretty", no_argument, NULL, 'p' },
7795 { "verbose", no_argument, NULL, 'v' },
ef12d6da 7796 { "statistics", no_argument, NULL, 's' },
29993df8 7797 { "Netns", required_argument, NULL, 'N' },
153c1a9b
AS
7798 { NULL, 0, NULL, 0 }
7799 };
3e897912
IV
7800 const char *batch_file = NULL;
7801 bool force = false;
153c1a9b
AS
7802 struct dl *dl;
7803 int opt;
7804 int err;
7805 int ret;
7806
7807 dl = dl_alloc();
7808 if (!dl) {
7809 pr_err("Failed to allocate memory for devlink\n");
7810 return EXIT_FAILURE;
7811 }
7812
29993df8 7813 while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:",
153c1a9b
AS
7814 long_options, NULL)) >= 0) {
7815
7816 switch (opt) {
7817 case 'V':
fbef6555 7818 printf("devlink utility, iproute2-%s\n", version);
153c1a9b
AS
7819 ret = EXIT_SUCCESS;
7820 goto dl_free;
3e897912
IV
7821 case 'f':
7822 force = true;
7823 break;
7824 case 'b':
7825 batch_file = optarg;
7826 break;
153c1a9b
AS
7827 case 'n':
7828 dl->no_nice_names = true;
7829 break;
7830 case 'j':
7831 dl->json_output = true;
7832 break;
7833 case 'p':
b20555e4 7834 pretty = true;
153c1a9b
AS
7835 break;
7836 case 'v':
7837 dl->verbose = true;
e3d0f0c0 7838 break;
ef12d6da
IS
7839 case 's':
7840 dl->stats = true;
7841 break;
29993df8
JP
7842 case 'N':
7843 if (netns_switch(optarg)) {
7844 ret = EXIT_FAILURE;
7845 goto dl_free;
7846 }
7847 break;
a3c4b484
JP
7848 default:
7849 pr_err("Unknown option.\n");
7850 help();
b77c77d2
LR
7851 ret = EXIT_FAILURE;
7852 goto dl_free;
a3c4b484
JP
7853 }
7854 }
7855
7856 argc -= optind;
7857 argv += optind;
7858
3e897912 7859 err = dl_init(dl);
a3c4b484
JP
7860 if (err) {
7861 ret = EXIT_FAILURE;
7862 goto dl_free;
7863 }
7864
3e897912
IV
7865 if (batch_file)
7866 err = dl_batch(dl, batch_file, force);
7867 else
7868 err = dl_cmd(dl, argc, argv);
7869
a3c4b484
JP
7870 if (err) {
7871 ret = EXIT_FAILURE;
7872 goto dl_fini;
7873 }
7874
7875 ret = EXIT_SUCCESS;
7876
7877dl_fini:
7878 dl_fini(dl);
7879dl_free:
7880 dl_free(dl);
7881
7882 return ret;
7883}