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