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