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