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