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