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