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