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