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