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