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