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