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