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