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