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