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