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