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