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