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