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