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