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 union {
3040 uint8_t vu8;
3041 uint16_t vu16;
3042 uint32_t vu32;
3043 const char *vstr;
3044 bool vbool;
3045 } value;
3046};
3047
3048static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
3049{
3050 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3051 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
3052 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3053 struct nlattr *param_value_attr;
3054 enum devlink_param_cmode cmode;
3055 struct param_ctx *ctx = data;
3056 struct dl *dl = ctx->dl;
3057 int nla_type;
3058 int err;
3059
3060 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3061 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3062 !tb[DEVLINK_ATTR_PARAM])
3063 return MNL_CB_ERROR;
3064
3065 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
3066 if (err != MNL_CB_OK)
3067 return MNL_CB_ERROR;
3068
3069 if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
3070 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
3071 return MNL_CB_ERROR;
3072
3073 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
3074 mnl_attr_for_each_nested(param_value_attr,
3075 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
3076 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
3077 struct nlattr *val_attr;
3078
3079 err = mnl_attr_parse_nested(param_value_attr,
3080 attr_cb, nla_value);
3081 if (err != MNL_CB_OK)
3082 return MNL_CB_ERROR;
3083
3084 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
3085 (nla_type != MNL_TYPE_FLAG &&
3086 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
3087 return MNL_CB_ERROR;
3088
3089 cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
3090 if (cmode == dl->opts.cmode) {
3091 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
3092 switch (nla_type) {
3093 case MNL_TYPE_U8:
3094 ctx->value.vu8 = mnl_attr_get_u8(val_attr);
3095 break;
3096 case MNL_TYPE_U16:
3097 ctx->value.vu16 = mnl_attr_get_u16(val_attr);
3098 break;
3099 case MNL_TYPE_U32:
3100 ctx->value.vu32 = mnl_attr_get_u32(val_attr);
3101 break;
3102 case MNL_TYPE_STRING:
3103 ctx->value.vstr = mnl_attr_get_str(val_attr);
3104 break;
3105 case MNL_TYPE_FLAG:
3106 ctx->value.vbool = val_attr ? true : false;
3107 break;
3108 }
3109 break;
3110 }
3111 }
3112 ctx->nla_type = nla_type;
3113 return MNL_CB_OK;
3114}
3115
3116static int cmd_dev_param_set(struct dl *dl)
3117{
3118 struct param_ctx ctx = {};
3119 struct nlmsghdr *nlh;
3120 bool conv_exists;
3121 uint32_t val_u32 = 0;
3122 uint16_t val_u16;
3123 uint8_t val_u8;
3124 bool val_bool;
3125 int err;
3126
3127 err = dl_argv_parse(dl, DL_OPT_HANDLE |
3128 DL_OPT_PARAM_NAME |
3129 DL_OPT_PARAM_VALUE |
3130 DL_OPT_PARAM_CMODE, 0);
3131 if (err)
3132 return err;
3133
3134
3135 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET,
3136 NLM_F_REQUEST | NLM_F_ACK);
3137 dl_opts_put(nlh, dl);
3138
3139 ctx.dl = dl;
3140 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
3141 if (err)
3142 return err;
3143
3144 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_SET,
3145 NLM_F_REQUEST | NLM_F_ACK);
3146 dl_opts_put(nlh, dl);
3147
3148 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
3149 dl->opts.param_name);
3150
3151 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
3152 switch (ctx.nla_type) {
3153 case MNL_TYPE_U8:
3154 if (conv_exists) {
3155 err = param_val_conv_uint_get(param_val_conv,
3156 PARAM_VAL_CONV_LEN,
3157 dl->opts.param_name,
3158 dl->opts.param_value,
3159 &val_u32);
3160 val_u8 = val_u32;
3161 } else {
3162 err = strtouint8_t(dl->opts.param_value, &val_u8);
3163 }
3164 if (err)
3165 goto err_param_value_parse;
3166 if (val_u8 == ctx.value.vu8)
3167 return 0;
3168 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
3169 break;
3170 case MNL_TYPE_U16:
3171 if (conv_exists) {
3172 err = param_val_conv_uint_get(param_val_conv,
3173 PARAM_VAL_CONV_LEN,
3174 dl->opts.param_name,
3175 dl->opts.param_value,
3176 &val_u32);
3177 val_u16 = val_u32;
3178 } else {
3179 err = strtouint16_t(dl->opts.param_value, &val_u16);
3180 }
3181 if (err)
3182 goto err_param_value_parse;
3183 if (val_u16 == ctx.value.vu16)
3184 return 0;
3185 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
3186 break;
3187 case MNL_TYPE_U32:
3188 if (conv_exists)
3189 err = param_val_conv_uint_get(param_val_conv,
3190 PARAM_VAL_CONV_LEN,
3191 dl->opts.param_name,
3192 dl->opts.param_value,
3193 &val_u32);
3194 else
3195 err = strtouint32_t(dl->opts.param_value, &val_u32);
3196 if (err)
3197 goto err_param_value_parse;
3198 if (val_u32 == ctx.value.vu32)
3199 return 0;
3200 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
3201 break;
3202 case MNL_TYPE_FLAG:
3203 err = strtobool(dl->opts.param_value, &val_bool);
3204 if (err)
3205 goto err_param_value_parse;
3206 if (val_bool == ctx.value.vbool)
3207 return 0;
3208 if (val_bool)
3209 mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
3210 0, NULL);
3211 break;
3212 case MNL_TYPE_STRING:
3213 mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
3214 dl->opts.param_value);
3215 if (!strcmp(dl->opts.param_value, ctx.value.vstr))
3216 return 0;
3217 break;
3218 default:
3219 printf("Value type not supported\n");
3220 return -ENOTSUP;
3221 }
3222 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
3223
3224err_param_value_parse:
3225 pr_err("Value \"%s\" is not a number or not within range\n",
3226 dl->opts.param_value);
3227 return err;
3228}
3229
3230static int cmd_port_param_show_cb(const struct nlmsghdr *nlh, void *data)
3231{
3232 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3233 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3234 struct dl *dl = data;
3235
3236 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3237 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3238 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_PARAM])
3239 return MNL_CB_ERROR;
3240
3241 pr_out_param(dl, tb, true, true);
3242 return MNL_CB_OK;
3243}
3244
3245static int cmd_dev_param_show(struct dl *dl)
3246{
3247 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3248 struct nlmsghdr *nlh;
3249 int err;
3250
3251 if (dl_argc(dl) == 0)
3252 flags |= NLM_F_DUMP;
3253
3254 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
3255
3256 if (dl_argc(dl) > 0) {
3257 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
3258 DL_OPT_PARAM_NAME, 0);
3259 if (err)
3260 return err;
3261 }
3262
3263 pr_out_section_start(dl, "param");
3264 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_param_show_cb, dl);
3265 pr_out_section_end(dl);
3266 return err;
3267}
3268
3269static int cmd_dev_param(struct dl *dl)
3270{
3271 if (dl_argv_match(dl, "help")) {
3272 cmd_dev_help();
3273 return 0;
3274 } else if (dl_argv_match(dl, "show") ||
3275 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3276 dl_arg_inc(dl);
3277 return cmd_dev_param_show(dl);
3278 } else if (dl_argv_match(dl, "set")) {
3279 dl_arg_inc(dl);
3280 return cmd_dev_param_set(dl);
3281 }
3282 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3283 return -ENOENT;
3284}
3285
3286static void pr_out_action_stats(struct dl *dl, struct nlattr *action_stats)
3287{
3288 struct nlattr *tb_stats_entry[DEVLINK_ATTR_MAX + 1] = {};
3289 struct nlattr *nla_reload_stats_entry, *nla_limit, *nla_value;
3290 enum devlink_reload_limit limit;
3291 uint32_t value;
3292 int err;
3293
3294 mnl_attr_for_each_nested(nla_reload_stats_entry, action_stats) {
3295 err = mnl_attr_parse_nested(nla_reload_stats_entry, attr_cb,
3296 tb_stats_entry);
3297 if (err != MNL_CB_OK)
3298 return;
3299
3300 nla_limit = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_LIMIT];
3301 nla_value = tb_stats_entry[DEVLINK_ATTR_RELOAD_STATS_VALUE];
3302 if (!nla_limit || !nla_value)
3303 return;
3304
3305 check_indent_newline(dl);
3306 limit = mnl_attr_get_u8(nla_limit);
3307 value = mnl_attr_get_u32(nla_value);
3308 print_uint_name_value(reload_limit_name(limit), value);
3309 }
3310}
3311
3312static void pr_out_reload_stats(struct dl *dl, struct nlattr *reload_stats)
3313{
3314 struct nlattr *nla_action_info, *nla_action, *nla_action_stats;
3315 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3316 enum devlink_reload_action action;
3317 int err;
3318
3319 mnl_attr_for_each_nested(nla_action_info, reload_stats) {
3320 err = mnl_attr_parse_nested(nla_action_info, attr_cb, tb);
3321 if (err != MNL_CB_OK)
3322 return;
3323 nla_action = tb[DEVLINK_ATTR_RELOAD_ACTION];
3324 nla_action_stats = tb[DEVLINK_ATTR_RELOAD_ACTION_STATS];
3325 if (!nla_action || !nla_action_stats)
3326 return;
3327
3328 action = mnl_attr_get_u8(nla_action);
3329 pr_out_object_start(dl, reload_action_name(action));
3330 pr_out_action_stats(dl, nla_action_stats);
3331 pr_out_object_end(dl);
3332 }
3333}
3334
3335static void pr_out_reload_data(struct dl *dl, struct nlattr **tb)
3336{
3337 struct nlattr *nla_reload_stats, *nla_remote_reload_stats;
3338 struct nlattr *tb_stats[DEVLINK_ATTR_MAX + 1] = {};
3339 uint8_t reload_failed = 0;
3340 int err;
3341
3342 if (tb[DEVLINK_ATTR_RELOAD_FAILED])
3343 reload_failed = mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED]);
3344
3345 if (reload_failed) {
3346 check_indent_newline(dl);
3347 print_bool(PRINT_ANY, "reload_failed", "reload_failed %s", true);
3348 }
3349 if (!tb[DEVLINK_ATTR_DEV_STATS] || !dl->stats)
3350 return;
3351 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_DEV_STATS], attr_cb,
3352 tb_stats);
3353 if (err != MNL_CB_OK)
3354 return;
3355
3356 pr_out_object_start(dl, "stats");
3357
3358 nla_reload_stats = tb_stats[DEVLINK_ATTR_RELOAD_STATS];
3359 if (nla_reload_stats) {
3360 pr_out_object_start(dl, "reload");
3361 pr_out_reload_stats(dl, nla_reload_stats);
3362 pr_out_object_end(dl);
3363 }
3364 nla_remote_reload_stats = tb_stats[DEVLINK_ATTR_REMOTE_RELOAD_STATS];
3365 if (nla_remote_reload_stats) {
3366 pr_out_object_start(dl, "remote_reload");
3367 pr_out_reload_stats(dl, nla_remote_reload_stats);
3368 pr_out_object_end(dl);
3369 }
3370
3371 pr_out_object_end(dl);
3372}
3373
3374
3375static void pr_out_dev(struct dl *dl, struct nlattr **tb)
3376{
3377 if ((tb[DEVLINK_ATTR_RELOAD_FAILED] && mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED])) ||
3378 (tb[DEVLINK_ATTR_DEV_STATS] && dl->stats)) {
3379 __pr_out_handle_start(dl, tb, true, false);
3380 pr_out_reload_data(dl, tb);
3381 pr_out_handle_end(dl);
3382 } else {
3383 pr_out_handle(dl, tb);
3384 }
3385}
3386
3387static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
3388{
3389 struct dl *dl = data;
3390 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3391 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3392
3393 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3394 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3395 return MNL_CB_ERROR;
3396
3397 pr_out_dev(dl, tb);
3398 return MNL_CB_OK;
3399}
3400
3401static int cmd_dev_show(struct dl *dl)
3402{
3403 struct nlmsghdr *nlh;
3404 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3405 int err;
3406
3407 if (dl_argc(dl) == 0)
3408 flags |= NLM_F_DUMP;
3409
3410 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_GET, flags);
3411
3412 if (dl_argc(dl) > 0) {
3413 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3414 if (err)
3415 return err;
3416 }
3417
3418 pr_out_section_start(dl, "dev");
3419 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_show_cb, dl);
3420 pr_out_section_end(dl);
3421 return err;
3422}
3423
3424static void pr_out_reload_actions_performed(struct dl *dl, struct nlattr **tb)
3425{
3426 struct nlattr *nla_actions_performed;
3427 struct nla_bitfield32 *actions;
3428 uint32_t actions_performed;
3429 uint16_t len;
3430 int action;
3431
3432 if (!tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3433 return;
3434
3435 nla_actions_performed = tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED];
3436 len = mnl_attr_get_payload_len(nla_actions_performed);
3437 if (len != sizeof(*actions))
3438 return;
3439 actions = mnl_attr_get_payload(nla_actions_performed);
3440 if (!actions)
3441 return;
3442 g_new_line_count = 1;
3443 pr_out_array_start(dl, "reload_actions_performed");
3444 actions_performed = actions->value & actions->selector;
3445 for (action = 0; action <= DEVLINK_RELOAD_ACTION_MAX; action++) {
3446 if (BIT(action) & actions_performed) {
3447 check_indent_newline(dl);
3448 print_string(PRINT_ANY, NULL, "%s",
3449 reload_action_name(action));
3450 }
3451 }
3452 pr_out_array_end(dl);
3453 if (!dl->json_output)
3454 __pr_out_newline();
3455}
3456
3457static int cmd_dev_reload_cb(const struct nlmsghdr *nlh, void *data)
3458{
3459 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3460 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3461 struct dl *dl = data;
3462
3463 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3464 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3465 !tb[DEVLINK_ATTR_RELOAD_ACTIONS_PERFORMED])
3466 return MNL_CB_ERROR;
3467
3468 pr_out_section_start(dl, "reload");
3469 pr_out_reload_actions_performed(dl, tb);
3470 pr_out_section_end(dl);
3471
3472 return MNL_CB_OK;
3473}
3474
3475static int cmd_dev_reload(struct dl *dl)
3476{
3477 struct nlmsghdr *nlh;
3478 int err;
3479
3480 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3481 cmd_dev_help();
3482 return 0;
3483 }
3484
3485 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RELOAD,
3486 NLM_F_REQUEST | NLM_F_ACK);
3487
3488 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
3489 DL_OPT_NETNS | DL_OPT_RELOAD_ACTION |
3490 DL_OPT_RELOAD_LIMIT);
3491 if (err)
3492 return err;
3493
3494 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_dev_reload_cb, dl);
3495}
3496
3497static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
3498 const char *name, int type)
3499{
3500 struct nlattr *version;
3501
3502 mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) {
3503 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3504 const char *ver_value;
3505 const char *ver_name;
3506 int err;
3507
3508 if (mnl_attr_get_type(version) != type)
3509 continue;
3510
3511 err = mnl_attr_parse_nested(version, attr_cb, tb);
3512 if (err != MNL_CB_OK)
3513 continue;
3514
3515 if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] ||
3516 !tb[DEVLINK_ATTR_INFO_VERSION_VALUE])
3517 continue;
3518
3519 if (name) {
3520 pr_out_object_start(dl, name);
3521 name = NULL;
3522 }
3523
3524 ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
3525 ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
3526
3527 check_indent_newline(dl);
3528 print_string_name_value(ver_name, ver_value);
3529 if (!dl->json_output)
3530 __pr_out_newline();
3531 }
3532
3533 if (!name)
3534 pr_out_object_end(dl);
3535}
3536
3537static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh,
3538 struct nlattr **tb, bool has_versions)
3539{
3540 __pr_out_handle_start(dl, tb, true, false);
3541
3542 __pr_out_indent_inc();
3543 if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) {
3544 struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME];
3545
3546 if (!dl->json_output)
3547 __pr_out_newline();
3548 check_indent_newline(dl);
3549 print_string(PRINT_ANY, "driver", "driver %s",
3550 mnl_attr_get_str(nla_drv));
3551 }
3552
3553 if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
3554 struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER];
3555
3556 if (!dl->json_output)
3557 __pr_out_newline();
3558 check_indent_newline(dl);
3559 print_string(PRINT_ANY, "serial_number", "serial_number %s",
3560 mnl_attr_get_str(nla_sn));
3561 }
3562
3563 if (tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER]) {
3564 struct nlattr *nla_bsn = tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER];
3565
3566 if (!dl->json_output)
3567 __pr_out_newline();
3568 check_indent_newline(dl);
3569 print_string(PRINT_ANY, "board.serial_number", "board.serial_number %s",
3570 mnl_attr_get_str(nla_bsn));
3571 }
3572 __pr_out_indent_dec();
3573
3574 if (has_versions) {
3575 pr_out_object_start(dl, "versions");
3576
3577 pr_out_versions_single(dl, nlh, "fixed",
3578 DEVLINK_ATTR_INFO_VERSION_FIXED);
3579 pr_out_versions_single(dl, nlh, "running",
3580 DEVLINK_ATTR_INFO_VERSION_RUNNING);
3581 pr_out_versions_single(dl, nlh, "stored",
3582 DEVLINK_ATTR_INFO_VERSION_STORED);
3583
3584 pr_out_object_end(dl);
3585 }
3586
3587 pr_out_handle_end(dl);
3588}
3589
3590static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data)
3591{
3592 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3593 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3594 bool has_versions, has_info;
3595 struct dl *dl = data;
3596
3597 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3598
3599 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3600 return MNL_CB_ERROR;
3601
3602 has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] ||
3603 tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] ||
3604 tb[DEVLINK_ATTR_INFO_VERSION_STORED];
3605 has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] ||
3606 tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] ||
3607 tb[DEVLINK_ATTR_INFO_BOARD_SERIAL_NUMBER] ||
3608 has_versions;
3609
3610 if (has_info)
3611 pr_out_info(dl, nlh, tb, has_versions);
3612
3613 return MNL_CB_OK;
3614}
3615
3616static int cmd_dev_info(struct dl *dl)
3617{
3618 struct nlmsghdr *nlh;
3619 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3620 int err;
3621
3622 if (dl_argv_match(dl, "help")) {
3623 cmd_dev_help();
3624 return 0;
3625 }
3626
3627 if (dl_argc(dl) == 0)
3628 flags |= NLM_F_DUMP;
3629
3630 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_INFO_GET, flags);
3631
3632 if (dl_argc(dl) > 0) {
3633 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3634 if (err)
3635 return err;
3636 }
3637
3638 pr_out_section_start(dl, "info");
3639 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_versions_show_cb, dl);
3640 pr_out_section_end(dl);
3641 return err;
3642}
3643
3644struct cmd_dev_flash_status_ctx {
3645 struct dl *dl;
3646 struct timespec time_of_last_status;
3647 uint64_t status_msg_timeout;
3648 size_t elapsed_time_msg_len;
3649 char *last_msg;
3650 char *last_component;
3651 uint8_t not_first:1,
3652 last_pc:1,
3653 received_end:1,
3654 flash_done:1;
3655};
3656
3657static int nullstrcmp(const char *str1, const char *str2)
3658{
3659 if (str1 && str2)
3660 return strcmp(str1, str2);
3661 if (!str1 && !str2)
3662 return 0;
3663 return str1 ? 1 : -1;
3664}
3665
3666static void cmd_dev_flash_clear_elapsed_time(struct cmd_dev_flash_status_ctx *ctx)
3667{
3668 int i;
3669
3670 for (i = 0; i < ctx->elapsed_time_msg_len; i++)
3671 pr_out_tty("\b \b");
3672
3673 ctx->elapsed_time_msg_len = 0;
3674}
3675
3676static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
3677{
3678 struct cmd_dev_flash_status_ctx *ctx = data;
3679 struct dl_opts *opts = &ctx->dl->opts;
3680 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3681 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3682 const char *component = NULL;
3683 uint64_t done = 0, total = 0;
3684 const char *msg = NULL;
3685 const char *bus_name;
3686 const char *dev_name;
3687
3688 cmd_dev_flash_clear_elapsed_time(ctx);
3689
3690 if (genl->cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS &&
3691 genl->cmd != DEVLINK_CMD_FLASH_UPDATE_END)
3692 return MNL_CB_STOP;
3693
3694 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3695 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
3696 return MNL_CB_ERROR;
3697 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
3698 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
3699 if (strcmp(bus_name, opts->bus_name) ||
3700 strcmp(dev_name, opts->dev_name))
3701 return MNL_CB_ERROR;
3702
3703 if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END) {
3704 pr_out("\n");
3705 free(ctx->last_msg);
3706 free(ctx->last_component);
3707 ctx->received_end = 1;
3708 return MNL_CB_STOP;
3709 }
3710
3711 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG])
3712 msg = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]);
3713 if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT])
3714 component = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]);
3715 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
3716 done = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]);
3717 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
3718 total = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]);
3719 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT])
3720 ctx->status_msg_timeout = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TIMEOUT]);
3721 else
3722 ctx->status_msg_timeout = 0;
3723
3724 if (!nullstrcmp(msg, ctx->last_msg) &&
3725 !nullstrcmp(component, ctx->last_component) &&
3726 ctx->last_pc && ctx->not_first) {
3727 pr_out_tty("\b\b\b\b\b");
3728 } else {
3729
3730 clock_gettime(CLOCK_MONOTONIC, &ctx->time_of_last_status);
3731
3732 if (ctx->not_first)
3733 pr_out("\n");
3734 if (component) {
3735 pr_out("[%s] ", component);
3736 free(ctx->last_component);
3737 ctx->last_component = strdup(component);
3738 }
3739 if (msg) {
3740 pr_out("%s", msg);
3741 free(ctx->last_msg);
3742 ctx->last_msg = strdup(msg);
3743 }
3744 }
3745 if (total) {
3746 pr_out_tty(" %3"PRIu64"%%", (done * 100) / total);
3747 ctx->last_pc = 1;
3748 } else {
3749 ctx->last_pc = 0;
3750 }
3751 fflush(stdout);
3752 ctx->not_first = 1;
3753
3754 return MNL_CB_STOP;
3755}
3756
3757static void cmd_dev_flash_time_elapsed(struct cmd_dev_flash_status_ctx *ctx)
3758{
3759 struct timespec now, res;
3760
3761 clock_gettime(CLOCK_MONOTONIC, &now);
3762
3763 res.tv_sec = now.tv_sec - ctx->time_of_last_status.tv_sec;
3764 res.tv_nsec = now.tv_nsec - ctx->time_of_last_status.tv_nsec;
3765 if (res.tv_nsec < 0) {
3766 res.tv_sec--;
3767 res.tv_nsec += 1000000000L;
3768 }
3769
3770
3771
3772
3773
3774 if (res.tv_sec > 2 || ctx->status_msg_timeout) {
3775 uint64_t elapsed_m, elapsed_s;
3776 char msg[128];
3777 size_t len;
3778
3779
3780 cmd_dev_flash_clear_elapsed_time(ctx);
3781
3782 elapsed_m = res.tv_sec / 60;
3783 elapsed_s = res.tv_sec % 60;
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799 if (!ctx->status_msg_timeout) {
3800 len = snprintf(msg, sizeof(msg),
3801 " ( %"PRIu64"m %"PRIu64"s )", elapsed_m, elapsed_s);
3802 } else if (res.tv_sec <= ctx->status_msg_timeout) {
3803 uint64_t timeout_m, timeout_s;
3804
3805 timeout_m = ctx->status_msg_timeout / 60;
3806 timeout_s = ctx->status_msg_timeout % 60;
3807
3808 len = snprintf(msg, sizeof(msg),
3809 " ( %"PRIu64"m %"PRIu64"s : %"PRIu64"m %"PRIu64"s )",
3810 elapsed_m, elapsed_s, timeout_m, timeout_s);
3811 } else {
3812 len = snprintf(msg, sizeof(msg),
3813 " ( %"PRIu64"m %"PRIu64"s : timeout reached )", elapsed_m, elapsed_s);
3814 }
3815
3816 ctx->elapsed_time_msg_len = len;
3817
3818 pr_out_tty("%s", msg);
3819 fflush(stdout);
3820 }
3821}
3822
3823static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx,
3824 struct mnlu_gen_socket *nlg_ntf,
3825 int pipe_r)
3826{
3827 int nlfd = mnlg_socket_get_fd(nlg_ntf);
3828 struct timeval timeout;
3829 fd_set fds[3];
3830 int fdmax;
3831 int i;
3832 int err;
3833 int err2;
3834
3835 for (i = 0; i < 3; i++)
3836 FD_ZERO(&fds[i]);
3837 FD_SET(pipe_r, &fds[0]);
3838 fdmax = pipe_r + 1;
3839 FD_SET(nlfd, &fds[0]);
3840 if (nlfd >= fdmax)
3841 fdmax = nlfd + 1;
3842
3843
3844
3845
3846
3847 timeout.tv_sec = 0;
3848 timeout.tv_usec = 100000;
3849
3850 while (select(fdmax, &fds[0], &fds[1], &fds[2], &timeout) < 0) {
3851 if (errno == EINTR)
3852 continue;
3853 pr_err("select() failed\n");
3854 return -errno;
3855 }
3856 if (FD_ISSET(nlfd, &fds[0])) {
3857 err = mnlu_gen_socket_recv_run(nlg_ntf,
3858 cmd_dev_flash_status_cb, ctx);
3859 if (err)
3860 return err;
3861 }
3862 if (FD_ISSET(pipe_r, &fds[0])) {
3863 err = read(pipe_r, &err2, sizeof(err2));
3864 if (err == -1) {
3865 pr_err("Failed to read pipe\n");
3866 return -errno;
3867 }
3868 if (err2)
3869 return err2;
3870 ctx->flash_done = 1;
3871 }
3872 cmd_dev_flash_time_elapsed(ctx);
3873 return 0;
3874}
3875
3876
3877static int cmd_dev_flash(struct dl *dl)
3878{
3879 struct cmd_dev_flash_status_ctx ctx = {.dl = dl,};
3880 struct mnlu_gen_socket nlg_ntf;
3881 struct nlmsghdr *nlh;
3882 int pipe_r, pipe_w;
3883 int pipe_fds[2];
3884 pid_t pid;
3885 int err;
3886
3887 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3888 cmd_dev_help();
3889 return 0;
3890 }
3891
3892 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
3893 NLM_F_REQUEST | NLM_F_ACK);
3894
3895 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
3896 DL_OPT_FLASH_COMPONENT | DL_OPT_FLASH_OVERWRITE);
3897 if (err)
3898 return err;
3899
3900 err = mnlu_gen_socket_open(&nlg_ntf, DEVLINK_GENL_NAME,
3901 DEVLINK_GENL_VERSION);
3902 if (err)
3903 return err;
3904
3905 err = _mnlg_socket_group_add(&nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME);
3906 if (err)
3907 goto err_socket;
3908
3909 err = pipe(pipe_fds);
3910 if (err == -1) {
3911 err = -errno;
3912 goto err_socket;
3913 }
3914 pipe_r = pipe_fds[0];
3915 pipe_w = pipe_fds[1];
3916
3917 pid = fork();
3918 if (pid == -1) {
3919 close(pipe_w);
3920 err = -errno;
3921 goto out;
3922 } else if (!pid) {
3923
3924
3925
3926 int cc;
3927
3928 close(pipe_r);
3929 err = _mnlg_socket_send(&dl->nlg, nlh);
3930 cc = write(pipe_w, &err, sizeof(err));
3931 close(pipe_w);
3932 exit(cc != sizeof(err));
3933 }
3934 close(pipe_w);
3935
3936
3937
3938
3939 clock_gettime(CLOCK_MONOTONIC, &ctx.time_of_last_status);
3940
3941 do {
3942 err = cmd_dev_flash_fds_process(&ctx, &nlg_ntf, pipe_r);
3943 if (err)
3944 goto out;
3945 } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end));
3946
3947 err = mnlu_gen_socket_recv_run(&dl->nlg, NULL, NULL);
3948
3949out:
3950 close(pipe_r);
3951err_socket:
3952 mnlu_gen_socket_close(&nlg_ntf);
3953 return err;
3954}
3955
3956static int cmd_dev(struct dl *dl)
3957{
3958 if (dl_argv_match(dl, "help")) {
3959 cmd_dev_help();
3960 return 0;
3961 } else if (dl_argv_match(dl, "show") ||
3962 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3963 dl_arg_inc(dl);
3964 return cmd_dev_show(dl);
3965 } else if (dl_argv_match(dl, "eswitch")) {
3966 dl_arg_inc(dl);
3967 return cmd_dev_eswitch(dl);
3968 } else if (dl_argv_match(dl, "reload")) {
3969 dl_arg_inc(dl);
3970 return cmd_dev_reload(dl);
3971 } else if (dl_argv_match(dl, "param")) {
3972 dl_arg_inc(dl);
3973 return cmd_dev_param(dl);
3974 } else if (dl_argv_match(dl, "info")) {
3975 dl_arg_inc(dl);
3976 return cmd_dev_info(dl);
3977 } else if (dl_argv_match(dl, "flash")) {
3978 dl_arg_inc(dl);
3979 return cmd_dev_flash(dl);
3980 }
3981 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3982 return -ENOENT;
3983}
3984
3985static void cmd_port_help(void)
3986{
3987 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3988 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3989 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3990 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3991 pr_err(" devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state { active | inactive } ]\n");
3992 pr_err(" devlink port function rate { help | show | add | del | set }\n");
3993 pr_err(" devlink port param set DEV/PORT_INDEX name PARAMETER value VALUE cmode { permanent | driverinit | runtime }\n");
3994 pr_err(" devlink port param show [DEV/PORT_INDEX name PARAMETER]\n");
3995 pr_err(" devlink port health show [ DEV/PORT_INDEX reporter REPORTER_NAME ]\n");
3996 pr_err(" devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
3997 " [ sfnum SFNUM ][ controller CNUM ]\n");
3998 pr_err(" devlink port del DEV/PORT_INDEX\n");
3999}
4000
4001static const char *port_type_name(uint32_t type)
4002{
4003 switch (type) {
4004 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
4005 case DEVLINK_PORT_TYPE_AUTO: return "auto";
4006 case DEVLINK_PORT_TYPE_ETH: return "eth";
4007 case DEVLINK_PORT_TYPE_IB: return "ib";
4008 default: return "<unknown type>";
4009 }
4010}
4011
4012static const char *port_flavour_name(uint16_t flavour)
4013{
4014 const char *str;
4015
4016 str = str_map_lookup_u16(port_flavour_map, flavour);
4017 return str ? str : "<unknown flavour>";
4018}
4019
4020static void pr_out_port_pfvfsf_num(struct dl *dl, struct nlattr **tb)
4021{
4022 uint16_t fn_num;
4023
4024 if (tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER])
4025 print_uint(PRINT_ANY, "controller", " controller %u",
4026 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER]));
4027 if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
4028 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
4029 print_uint(PRINT_ANY, "pfnum", " pfnum %u", fn_num);
4030 }
4031 if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
4032 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
4033 print_uint(PRINT_ANY, "vfnum", " vfnum %u", fn_num);
4034 }
4035 if (tb[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]) {
4036 fn_num = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_PCI_SF_NUMBER]);
4037 print_uint(PRINT_ANY, "sfnum", " sfnum %u", fn_num);
4038 }
4039 if (tb[DEVLINK_ATTR_PORT_EXTERNAL]) {
4040 uint8_t external;
4041
4042 external = mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_EXTERNAL]);
4043 print_bool(PRINT_ANY, "external", " external %s", external);
4044 }
4045}
4046
4047static const char *port_fn_state(uint8_t state)
4048{
4049 const char *str;
4050
4051 str = str_map_lookup_u8(port_fn_state_map, state);
4052 return str ? str : "<unknown state>";
4053}
4054
4055static const char *port_fn_opstate(uint8_t state)
4056{
4057 const char *str;
4058
4059 str = str_map_lookup_u8(port_fn_opstate_map, state);
4060 return str ? str : "<unknown state>";
4061}
4062
4063static void pr_out_port_function(struct dl *dl, struct nlattr **tb_port)
4064{
4065 struct nlattr *tb[DEVLINK_PORT_FUNCTION_ATTR_MAX + 1] = {};
4066 unsigned char *data;
4067 SPRINT_BUF(hw_addr);
4068 uint32_t len;
4069 int err;
4070
4071 if (!tb_port[DEVLINK_ATTR_PORT_FUNCTION])
4072 return;
4073
4074 err = mnl_attr_parse_nested(tb_port[DEVLINK_ATTR_PORT_FUNCTION],
4075 function_attr_cb, tb);
4076 if (err != MNL_CB_OK)
4077 return;
4078
4079 pr_out_object_start(dl, "function");
4080 check_indent_newline(dl);
4081
4082 if (tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]) {
4083 len = mnl_attr_get_payload_len(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
4084 data = mnl_attr_get_payload(tb[DEVLINK_PORT_FUNCTION_ATTR_HW_ADDR]);
4085
4086 print_string(PRINT_ANY, "hw_addr", "hw_addr %s",
4087 ll_addr_n2a(data, len, 0, hw_addr, sizeof(hw_addr)));
4088 }
4089 if (tb[DEVLINK_PORT_FN_ATTR_STATE]) {
4090 uint8_t state;
4091
4092 state = mnl_attr_get_u8(tb[DEVLINK_PORT_FN_ATTR_STATE]);
4093
4094 print_string(PRINT_ANY, "state", " state %s",
4095 port_fn_state(state));
4096 }
4097 if (tb[DEVLINK_PORT_FN_ATTR_OPSTATE]) {
4098 uint8_t state;
4099
4100 state = mnl_attr_get_u8(tb[DEVLINK_PORT_FN_ATTR_OPSTATE]);
4101
4102 print_string(PRINT_ANY, "opstate", " opstate %s",
4103 port_fn_opstate(state));
4104 }
4105
4106 if (!dl->json_output)
4107 __pr_out_indent_dec();
4108 pr_out_object_end(dl);
4109}
4110
4111static void pr_out_port(struct dl *dl, struct nlattr **tb)
4112{
4113 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
4114 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
4115
4116 pr_out_port_handle_start(dl, tb, false);
4117 check_indent_newline(dl);
4118 if (pt_attr) {
4119 uint16_t port_type = mnl_attr_get_u16(pt_attr);
4120
4121 print_string(PRINT_ANY, "type", "type %s",
4122 port_type_name(port_type));
4123 if (dpt_attr) {
4124 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
4125
4126 if (port_type != des_port_type)
4127 print_string(PRINT_ANY, "des_type", " des_type %s",
4128 port_type_name(des_port_type));
4129 }
4130 }
4131 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) {
4132 print_string(PRINT_ANY, "netdev", " netdev %s",
4133 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
4134 }
4135 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) {
4136 print_string(PRINT_ANY, "ibdev", " ibdev %s",
4137 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
4138 }
4139 if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
4140 uint16_t port_flavour =
4141 mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
4142
4143 print_string(PRINT_ANY, "flavour", " flavour %s",
4144 port_flavour_name(port_flavour));
4145
4146 switch (port_flavour) {
4147 case DEVLINK_PORT_FLAVOUR_PCI_PF:
4148 case DEVLINK_PORT_FLAVOUR_PCI_VF:
4149 case DEVLINK_PORT_FLAVOUR_PCI_SF:
4150 pr_out_port_pfvfsf_num(dl, tb);
4151 break;
4152 default:
4153 break;
4154 }
4155 }
4156 if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
4157 uint32_t port_number;
4158
4159 port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
4160 print_uint(PRINT_ANY, "port", " port %u", port_number);
4161 }
4162 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
4163 print_uint(PRINT_ANY, "split_group", " split_group %u",
4164 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
4165 if (tb[DEVLINK_ATTR_PORT_SPLITTABLE])
4166 print_bool(PRINT_ANY, "splittable", " splittable %s",
4167 mnl_attr_get_u8(tb[DEVLINK_ATTR_PORT_SPLITTABLE]));
4168 if (tb[DEVLINK_ATTR_PORT_LANES])
4169 print_uint(PRINT_ANY, "lanes", " lanes %u",
4170 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_LANES]));
4171
4172 pr_out_port_function(dl, tb);
4173 pr_out_port_handle_end(dl);
4174}
4175
4176static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
4177{
4178 struct dl *dl = data;
4179 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4180 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4181
4182 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4183 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4184 !tb[DEVLINK_ATTR_PORT_INDEX])
4185 return MNL_CB_ERROR;
4186 pr_out_port(dl, tb);
4187 return MNL_CB_OK;
4188}
4189
4190static int cmd_port_show(struct dl *dl)
4191{
4192 struct nlmsghdr *nlh;
4193 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4194 int err;
4195
4196 if (dl_argc(dl) == 0)
4197 flags |= NLM_F_DUMP;
4198
4199 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_GET, flags);
4200
4201 if (dl_argc(dl) > 0) {
4202 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4203 if (err)
4204 return err;
4205 }
4206
4207 pr_out_section_start(dl, "port");
4208 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl);
4209 pr_out_section_end(dl);
4210 return err;
4211}
4212
4213static int cmd_port_set(struct dl *dl)
4214{
4215 struct nlmsghdr *nlh;
4216 int err;
4217
4218 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET,
4219 NLM_F_REQUEST | NLM_F_ACK);
4220
4221 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
4222 if (err)
4223 return err;
4224
4225 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4226}
4227
4228static int cmd_port_split(struct dl *dl)
4229{
4230 struct nlmsghdr *nlh;
4231 int err;
4232
4233 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SPLIT,
4234 NLM_F_REQUEST | NLM_F_ACK);
4235
4236 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
4237 if (err)
4238 return err;
4239
4240 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4241}
4242
4243static int cmd_port_unsplit(struct dl *dl)
4244{
4245 struct nlmsghdr *nlh;
4246 int err;
4247
4248 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
4249 NLM_F_REQUEST | NLM_F_ACK);
4250
4251 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4252 if (err)
4253 return err;
4254
4255 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4256}
4257
4258static int cmd_port_param_show(struct dl *dl)
4259{
4260 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4261 struct nlmsghdr *nlh;
4262 int err;
4263
4264 if (dl_argc(dl) == 0)
4265 flags |= NLM_F_DUMP;
4266
4267 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET,
4268 flags);
4269
4270 if (dl_argc(dl) > 0) {
4271 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP |
4272 DL_OPT_PARAM_NAME, 0);
4273 if (err)
4274 return err;
4275 }
4276
4277 pr_out_section_start(dl, "param");
4278 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_show_cb, dl);
4279 pr_out_section_end(dl);
4280
4281 return err;
4282}
4283
4284static void cmd_port_function_help(void)
4285{
4286 pr_err("Usage: devlink port function set DEV/PORT_INDEX [ hw_addr ADDR ] [ state STATE ]\n");
4287 pr_err(" devlink port function rate { help | show | add | del | set }\n");
4288}
4289
4290static int cmd_port_function_set(struct dl *dl)
4291{
4292 struct nlmsghdr *nlh;
4293 int err;
4294
4295 if (dl_no_arg(dl)) {
4296 cmd_port_function_help();
4297 return 0;
4298 }
4299 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_SET,
4300 NLM_F_REQUEST | NLM_F_ACK);
4301
4302 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP,
4303 DL_OPT_PORT_FUNCTION_HW_ADDR | DL_OPT_PORT_FUNCTION_STATE);
4304 if (err)
4305 return err;
4306
4307 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4308}
4309
4310static int cmd_port_param_set_cb(const struct nlmsghdr *nlh, void *data)
4311{
4312 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4313 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
4314 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4315 struct nlattr *param_value_attr;
4316 enum devlink_param_cmode cmode;
4317 struct param_ctx *ctx = data;
4318 struct dl *dl = ctx->dl;
4319 int nla_type;
4320 int err;
4321
4322 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4323 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4324 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_PARAM])
4325 return MNL_CB_ERROR;
4326
4327 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
4328 if (err != MNL_CB_OK)
4329 return MNL_CB_ERROR;
4330
4331 if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
4332 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
4333 return MNL_CB_ERROR;
4334
4335 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
4336 mnl_attr_for_each_nested(param_value_attr,
4337 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
4338 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
4339 struct nlattr *val_attr;
4340
4341 err = mnl_attr_parse_nested(param_value_attr,
4342 attr_cb, nla_value);
4343 if (err != MNL_CB_OK)
4344 return MNL_CB_ERROR;
4345
4346 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
4347 (nla_type != MNL_TYPE_FLAG &&
4348 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
4349 return MNL_CB_ERROR;
4350
4351 cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
4352 if (cmode == dl->opts.cmode) {
4353 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
4354 switch (nla_type) {
4355 case MNL_TYPE_U8:
4356 ctx->value.vu8 = mnl_attr_get_u8(val_attr);
4357 break;
4358 case MNL_TYPE_U16:
4359 ctx->value.vu16 = mnl_attr_get_u16(val_attr);
4360 break;
4361 case MNL_TYPE_U32:
4362 ctx->value.vu32 = mnl_attr_get_u32(val_attr);
4363 break;
4364 case MNL_TYPE_STRING:
4365 ctx->value.vstr = mnl_attr_get_str(val_attr);
4366 break;
4367 case MNL_TYPE_FLAG:
4368 ctx->value.vbool = val_attr ? true : false;
4369 break;
4370 }
4371 break;
4372 }
4373 }
4374 ctx->nla_type = nla_type;
4375 return MNL_CB_OK;
4376}
4377
4378static int cmd_port_param_set(struct dl *dl)
4379{
4380 struct param_ctx ctx = {};
4381 struct nlmsghdr *nlh;
4382 bool conv_exists;
4383 uint32_t val_u32 = 0;
4384 uint16_t val_u16;
4385 uint8_t val_u8;
4386 bool val_bool;
4387 int err;
4388
4389 err = dl_argv_parse(dl, DL_OPT_HANDLEP |
4390 DL_OPT_PARAM_NAME |
4391 DL_OPT_PARAM_VALUE |
4392 DL_OPT_PARAM_CMODE, 0);
4393 if (err)
4394 return err;
4395
4396
4397 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_GET,
4398 NLM_F_REQUEST | NLM_F_ACK);
4399 dl_opts_put(nlh, dl);
4400
4401 ctx.dl = dl;
4402 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_param_set_cb, &ctx);
4403 if (err)
4404 return err;
4405
4406 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_PARAM_SET,
4407 NLM_F_REQUEST | NLM_F_ACK);
4408 dl_opts_put(nlh, dl);
4409
4410 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
4411 dl->opts.param_name);
4412
4413 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
4414 switch (ctx.nla_type) {
4415 case MNL_TYPE_U8:
4416 if (conv_exists) {
4417 err = param_val_conv_uint_get(param_val_conv,
4418 PARAM_VAL_CONV_LEN,
4419 dl->opts.param_name,
4420 dl->opts.param_value,
4421 &val_u32);
4422 val_u8 = val_u32;
4423 } else {
4424 err = strtouint8_t(dl->opts.param_value, &val_u8);
4425 }
4426 if (err)
4427 goto err_param_value_parse;
4428 if (val_u8 == ctx.value.vu8)
4429 return 0;
4430 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
4431 break;
4432 case MNL_TYPE_U16:
4433 if (conv_exists) {
4434 err = param_val_conv_uint_get(param_val_conv,
4435 PARAM_VAL_CONV_LEN,
4436 dl->opts.param_name,
4437 dl->opts.param_value,
4438 &val_u32);
4439 val_u16 = val_u32;
4440 } else {
4441 err = strtouint16_t(dl->opts.param_value, &val_u16);
4442 }
4443 if (err)
4444 goto err_param_value_parse;
4445 if (val_u16 == ctx.value.vu16)
4446 return 0;
4447 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
4448 break;
4449 case MNL_TYPE_U32:
4450 if (conv_exists)
4451 err = param_val_conv_uint_get(param_val_conv,
4452 PARAM_VAL_CONV_LEN,
4453 dl->opts.param_name,
4454 dl->opts.param_value,
4455 &val_u32);
4456 else
4457 err = strtouint32_t(dl->opts.param_value, &val_u32);
4458 if (err)
4459 goto err_param_value_parse;
4460 if (val_u32 == ctx.value.vu32)
4461 return 0;
4462 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
4463 break;
4464 case MNL_TYPE_FLAG:
4465 err = strtobool(dl->opts.param_value, &val_bool);
4466 if (err)
4467 goto err_param_value_parse;
4468 if (val_bool == ctx.value.vbool)
4469 return 0;
4470 if (val_bool)
4471 mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
4472 0, NULL);
4473 break;
4474 case MNL_TYPE_STRING:
4475 mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
4476 dl->opts.param_value);
4477 if (!strcmp(dl->opts.param_value, ctx.value.vstr))
4478 return 0;
4479 break;
4480 default:
4481 printf("Value type not supported\n");
4482 return -ENOTSUP;
4483 }
4484 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4485
4486err_param_value_parse:
4487 pr_err("Value \"%s\" is not a number or not within range\n",
4488 dl->opts.param_value);
4489 return err;
4490}
4491
4492static int cmd_port_param(struct dl *dl)
4493{
4494 if (dl_argv_match(dl, "help")) {
4495 cmd_port_help();
4496 return 0;
4497 } else if (dl_argv_match(dl, "show") ||
4498 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4499 dl_arg_inc(dl);
4500 return cmd_port_param_show(dl);
4501 } else if (dl_argv_match(dl, "set")) {
4502 dl_arg_inc(dl);
4503 return cmd_port_param_set(dl);
4504 }
4505 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4506 return -ENOENT;
4507}
4508
4509static void
4510pr_out_port_rate_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
4511{
4512 const char *bus_name;
4513 const char *dev_name;
4514 const char *node_name;
4515 static char buf[64];
4516
4517 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
4518 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
4519 node_name = mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_NODE_NAME]);
4520 sprintf(buf, "%s/%s/%s", bus_name, dev_name, node_name);
4521 if (dl->json_output)
4522 open_json_object(buf);
4523 else
4524 pr_out("%s:", buf);
4525}
4526
4527static char *port_rate_type_name(uint16_t type)
4528{
4529 switch (type) {
4530 case DEVLINK_RATE_TYPE_LEAF:
4531 return "leaf";
4532 case DEVLINK_RATE_TYPE_NODE:
4533 return "node";
4534 default:
4535 return "<unknown type>";
4536 }
4537}
4538
4539static void pr_out_port_fn_rate(struct dl *dl, struct nlattr **tb)
4540{
4541
4542 if (!tb[DEVLINK_ATTR_RATE_NODE_NAME])
4543 pr_out_port_handle_start(dl, tb, false);
4544 else
4545 pr_out_port_rate_handle_start(dl, tb, false);
4546 check_indent_newline(dl);
4547
4548 if (tb[DEVLINK_ATTR_RATE_TYPE]) {
4549 uint16_t type =
4550 mnl_attr_get_u16(tb[DEVLINK_ATTR_RATE_TYPE]);
4551
4552 print_string(PRINT_ANY, "type", "type %s",
4553 port_rate_type_name(type));
4554 }
4555 if (tb[DEVLINK_ATTR_RATE_TX_SHARE]) {
4556 uint64_t rate =
4557 mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
4558
4559 if (rate)
4560 print_rate(use_iec, PRINT_ANY, "tx_share",
4561 " tx_share %s", rate);
4562 }
4563 if (tb[DEVLINK_ATTR_RATE_TX_MAX]) {
4564 uint64_t rate =
4565 mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
4566
4567 if (rate)
4568 print_rate(use_iec, PRINT_ANY, "tx_max",
4569 " tx_max %s", rate);
4570 }
4571 if (tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]) {
4572 const char *parent =
4573 mnl_attr_get_str(tb[DEVLINK_ATTR_RATE_PARENT_NODE_NAME]);
4574
4575 print_string(PRINT_ANY, "parent", " parent %s", parent);
4576 }
4577
4578 pr_out_port_handle_end(dl);
4579}
4580
4581static int cmd_port_fn_rate_show_cb(const struct nlmsghdr *nlh, void *data)
4582{
4583 struct dl *dl = data;
4584 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4585 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4586
4587 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4588 if ((!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4589 !tb[DEVLINK_ATTR_PORT_INDEX]) &&
4590 !tb[DEVLINK_ATTR_RATE_NODE_NAME]) {
4591 return MNL_CB_ERROR;
4592 }
4593 pr_out_port_fn_rate(dl, tb);
4594 return MNL_CB_OK;
4595}
4596
4597static void cmd_port_fn_rate_help(void)
4598{
4599 pr_err("Usage: devlink port function rate help\n");
4600 pr_err(" devlink port function rate show [ DEV/{ PORT_INDEX | NODE_NAME } ]\n");
4601 pr_err(" devlink port function rate add DEV/NODE_NAME\n");
4602 pr_err(" [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n");
4603 pr_err(" devlink port function rate del DEV/NODE_NAME\n");
4604 pr_err(" devlink port function rate set DEV/{ PORT_INDEX | NODE_NAME }\n");
4605 pr_err(" [ tx_share VAL ][ tx_max VAL ][ { parent NODE_NAME | noparent } ]\n\n");
4606 pr_err(" VAL - float or integer value in units of bits or bytes per second (bit|bps)\n");
4607 pr_err(" and SI (k-, m-, g-, t-) or IEC (ki-, mi-, gi-, ti-) case-insensitive prefix.\n");
4608 pr_err(" Bare number, means bits per second, is possible.\n\n");
4609 pr_err(" For details refer to devlink-rate(8) man page.\n");
4610}
4611
4612static int cmd_port_fn_rate_show(struct dl *dl)
4613{
4614 struct nlmsghdr *nlh;
4615 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4616 int err;
4617
4618 if (dl_argc(dl) == 0)
4619 flags |= NLM_F_DUMP;
4620
4621 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET, flags);
4622
4623 if (dl_argc(dl) > 0) {
4624 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP |
4625 DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
4626 if (err)
4627 return err;
4628 }
4629
4630 pr_out_section_start(dl, "rate");
4631 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_fn_rate_show_cb, dl);
4632 pr_out_section_end(dl);
4633 return err;
4634}
4635
4636static int port_fn_check_tx_rates(uint64_t min_rate, uint64_t max_rate)
4637{
4638 if (max_rate && min_rate > max_rate) {
4639 pr_err("Invalid. Expected tx_share <= tx_max or tx_share == 0.\n");
4640 return -EINVAL;
4641 }
4642 return 0;
4643}
4644
4645static int port_fn_get_and_check_tx_rates(struct dl_opts *reply,
4646 struct dl_opts *request)
4647{
4648 uint64_t min = reply->rate_tx_share;
4649 uint64_t max = reply->rate_tx_max;
4650
4651 if (request->present & DL_OPT_PORT_FN_RATE_TX_SHARE)
4652 return port_fn_check_tx_rates(request->rate_tx_share, max);
4653 return port_fn_check_tx_rates(min, request->rate_tx_max);
4654}
4655
4656static int cmd_port_fn_rate_add(struct dl *dl)
4657{
4658 struct nlmsghdr *nlh;
4659 int err;
4660
4661 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_NEW,
4662 NLM_F_REQUEST | NLM_F_ACK);
4663 err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME,
4664 DL_OPT_PORT_FN_RATE_TX_SHARE |
4665 DL_OPT_PORT_FN_RATE_TX_MAX);
4666 if (err)
4667 return err;
4668
4669 if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
4670 (dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
4671 err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
4672 dl->opts.rate_tx_max);
4673 if (err)
4674 return err;
4675 }
4676
4677 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4678}
4679
4680static int cmd_port_fn_rate_del(struct dl *dl)
4681{
4682 struct nlmsghdr *nlh;
4683 int err;
4684
4685 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_DEL,
4686 NLM_F_REQUEST | NLM_F_ACK);
4687 err = dl_argv_parse_put(nlh, dl, DL_OPT_PORT_FN_RATE_NODE_NAME, 0);
4688 if (err)
4689 return err;
4690
4691 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4692}
4693
4694static int port_fn_get_rates_cb(const struct nlmsghdr *nlh, void *data)
4695{
4696 struct dl_opts *opts = data;
4697 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4698 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4699
4700 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4701 if ((!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4702 !tb[DEVLINK_ATTR_PORT_INDEX]) &&
4703 !tb[DEVLINK_ATTR_RATE_NODE_NAME]) {
4704 return MNL_CB_ERROR;
4705 }
4706
4707 if (tb[DEVLINK_ATTR_RATE_TX_SHARE])
4708 opts->rate_tx_share =
4709 mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_SHARE]);
4710 if (tb[DEVLINK_ATTR_RATE_TX_MAX])
4711 opts->rate_tx_max =
4712 mnl_attr_get_u64(tb[DEVLINK_ATTR_RATE_TX_MAX]);
4713 return MNL_CB_OK;
4714}
4715
4716static int cmd_port_fn_rate_set(struct dl *dl)
4717{
4718 struct dl_opts tmp_opts = {0};
4719 struct nlmsghdr *nlh;
4720 int err;
4721
4722 err = dl_argv_parse(dl, DL_OPT_HANDLEP |
4723 DL_OPT_PORT_FN_RATE_NODE_NAME,
4724 DL_OPT_PORT_FN_RATE_TX_SHARE |
4725 DL_OPT_PORT_FN_RATE_TX_MAX |
4726 DL_OPT_PORT_FN_RATE_PARENT);
4727 if (err)
4728 return err;
4729
4730 if ((dl->opts.present & DL_OPT_PORT_FN_RATE_TX_SHARE) &&
4731 (dl->opts.present & DL_OPT_PORT_FN_RATE_TX_MAX)) {
4732 err = port_fn_check_tx_rates(dl->opts.rate_tx_share,
4733 dl->opts.rate_tx_max);
4734 if (err)
4735 return err;
4736 } else if (dl->opts.present &
4737 (DL_OPT_PORT_FN_RATE_TX_SHARE | DL_OPT_PORT_FN_RATE_TX_MAX)) {
4738 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_GET,
4739 NLM_F_REQUEST | NLM_F_ACK);
4740 tmp_opts = dl->opts;
4741 dl->opts.present &= ~(DL_OPT_PORT_FN_RATE_TX_SHARE |
4742 DL_OPT_PORT_FN_RATE_TX_MAX |
4743 DL_OPT_PORT_FN_RATE_PARENT);
4744 dl_opts_put(nlh, dl);
4745 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, port_fn_get_rates_cb,
4746 &dl->opts);
4747 if (err)
4748 return err;
4749 err = port_fn_get_and_check_tx_rates(&dl->opts, &tmp_opts);
4750 if (err)
4751 return err;
4752 dl->opts = tmp_opts;
4753 }
4754
4755 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_RATE_SET,
4756 NLM_F_REQUEST | NLM_F_ACK);
4757 dl_opts_put(nlh, dl);
4758 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4759}
4760
4761static int cmd_port_function_rate(struct dl *dl)
4762{
4763 if (dl_argv_match(dl, "help")) {
4764 cmd_port_fn_rate_help();
4765 return 0;
4766 } else if (dl_argv_match(dl, "show") || dl_no_arg(dl)) {
4767 dl_arg_inc(dl);
4768 return cmd_port_fn_rate_show(dl);
4769 } else if (dl_argv_match(dl, "add")) {
4770 dl_arg_inc(dl);
4771 return cmd_port_fn_rate_add(dl);
4772 } else if (dl_argv_match(dl, "del")) {
4773 dl_arg_inc(dl);
4774 return cmd_port_fn_rate_del(dl);
4775 } else if (dl_argv_match(dl, "set")) {
4776 dl_arg_inc(dl);
4777 return cmd_port_fn_rate_set(dl);
4778 }
4779 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4780 return -ENOENT;
4781}
4782
4783static int cmd_port_function(struct dl *dl)
4784{
4785 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4786 cmd_port_function_help();
4787 return 0;
4788 } else if (dl_argv_match(dl, "set")) {
4789 dl_arg_inc(dl);
4790 return cmd_port_function_set(dl);
4791 } else if (dl_argv_match(dl, "rate")) {
4792 dl_arg_inc(dl);
4793 return cmd_port_function_rate(dl);
4794 }
4795 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4796 return -ENOENT;
4797}
4798
4799static int cmd_health(struct dl *dl);
4800static int __cmd_health_show(struct dl *dl, bool show_device, bool show_port);
4801
4802static void cmd_port_add_help(void)
4803{
4804 pr_err(" devlink port add DEV/PORT_INDEX flavour FLAVOUR pfnum PFNUM\n"
4805 " [ sfnum SFNUM ][ controller CNUM ]\n");
4806}
4807
4808static int cmd_port_add(struct dl *dl)
4809{
4810 struct nlmsghdr *nlh;
4811 int err;
4812
4813 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4814 cmd_port_add_help();
4815 return 0;
4816 }
4817
4818 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_NEW,
4819 NLM_F_REQUEST | NLM_F_ACK);
4820
4821 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_HANDLEP |
4822 DL_OPT_PORT_FLAVOUR | DL_OPT_PORT_PFNUMBER,
4823 DL_OPT_PORT_SFNUMBER | DL_OPT_PORT_CONTROLLER);
4824 if (err)
4825 return err;
4826
4827 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_port_show_cb, dl);
4828}
4829
4830static void cmd_port_del_help(void)
4831{
4832 pr_err(" devlink port del DEV/PORT_INDEX\n");
4833}
4834
4835static int cmd_port_del(struct dl *dl)
4836{
4837 struct nlmsghdr *nlh;
4838 int err;
4839
4840 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4841 cmd_port_del_help();
4842 return 0;
4843 }
4844
4845 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_PORT_DEL,
4846 NLM_F_REQUEST | NLM_F_ACK);
4847
4848 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
4849 if (err)
4850 return err;
4851
4852 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
4853}
4854
4855static int cmd_port(struct dl *dl)
4856{
4857 if (dl_argv_match(dl, "help")) {
4858 cmd_port_help();
4859 return 0;
4860 } else if (dl_argv_match(dl, "show") ||
4861 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4862 dl_arg_inc(dl);
4863 return cmd_port_show(dl);
4864 } else if (dl_argv_match(dl, "set")) {
4865 dl_arg_inc(dl);
4866 return cmd_port_set(dl);
4867 } else if (dl_argv_match(dl, "split")) {
4868 dl_arg_inc(dl);
4869 return cmd_port_split(dl);
4870 } else if (dl_argv_match(dl, "unsplit")) {
4871 dl_arg_inc(dl);
4872 return cmd_port_unsplit(dl);
4873 } else if (dl_argv_match(dl, "param")) {
4874 dl_arg_inc(dl);
4875 return cmd_port_param(dl);
4876 } else if (dl_argv_match(dl, "function")) {
4877 dl_arg_inc(dl);
4878 return cmd_port_function(dl);
4879 } else if (dl_argv_match(dl, "health")) {
4880 dl_arg_inc(dl);
4881 if (dl_argv_match(dl, "list") || dl_no_arg(dl)
4882 || (dl_argv_match(dl, "show") && dl_argc(dl) == 1)) {
4883 dl_arg_inc(dl);
4884 return __cmd_health_show(dl, false, true);
4885 } else {
4886 return cmd_health(dl);
4887 }
4888 } else if (dl_argv_match(dl, "add")) {
4889 dl_arg_inc(dl);
4890 return cmd_port_add(dl);
4891 } else if (dl_argv_match(dl, "del")) {
4892 dl_arg_inc(dl);
4893 return cmd_port_del(dl);
4894 }
4895
4896 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4897 return -ENOENT;
4898}
4899
4900static void cmd_sb_help(void)
4901{
4902 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
4903 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
4904 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
4905 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
4906 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4907 pr_err(" pool POOL_INDEX ]\n");
4908 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
4909 pr_err(" pool POOL_INDEX th THRESHOLD\n");
4910 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4911 pr_err(" type { ingress | egress } ]\n");
4912 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
4913 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
4914 pr_err(" th THRESHOLD\n");
4915 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
4916 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
4917 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
4918}
4919
4920static void pr_out_sb(struct dl *dl, struct nlattr **tb)
4921{
4922 pr_out_handle_start_arr(dl, tb);
4923 check_indent_newline(dl);
4924 print_uint(PRINT_ANY, "sb", "sb %u",
4925 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
4926 print_uint(PRINT_ANY, "size", " size %u",
4927 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
4928 print_uint(PRINT_ANY, "ing_pools", " ing_pools %u",
4929 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
4930 print_uint(PRINT_ANY, "eg_pools", " eg_pools %u",
4931 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
4932 print_uint(PRINT_ANY, "ing_tcs", " ing_tcs %u",
4933 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
4934 print_uint(PRINT_ANY, "eg_tcs", " eg_tcs %u",
4935 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
4936 pr_out_handle_end(dl);
4937}
4938
4939static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
4940{
4941 struct dl *dl = data;
4942 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4943 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4944
4945 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4946 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4947 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
4948 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
4949 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
4950 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
4951 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
4952 return MNL_CB_ERROR;
4953 pr_out_sb(dl, tb);
4954 return MNL_CB_OK;
4955}
4956
4957static int cmd_sb_show(struct dl *dl)
4958{
4959 struct nlmsghdr *nlh;
4960 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4961 int err;
4962
4963 if (dl_argc(dl) == 0)
4964 flags |= NLM_F_DUMP;
4965
4966 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_GET, flags);
4967
4968 if (dl_argc(dl) > 0) {
4969 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4970 if (err)
4971 return err;
4972 }
4973
4974 pr_out_section_start(dl, "sb");
4975 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_show_cb, dl);
4976 pr_out_section_end(dl);
4977 return err;
4978}
4979
4980static const char *pool_type_name(uint8_t type)
4981{
4982 switch (type) {
4983 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
4984 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
4985 default: return "<unknown type>";
4986 }
4987}
4988
4989static const char *threshold_type_name(uint8_t type)
4990{
4991 switch (type) {
4992 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
4993 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
4994 default: return "<unknown type>";
4995 }
4996}
4997
4998static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
4999{
5000 pr_out_handle_start_arr(dl, tb);
5001 check_indent_newline(dl);
5002 print_uint(PRINT_ANY, "sb", "sb %u",
5003 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5004 print_uint(PRINT_ANY, "pool", " pool %u",
5005 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5006 print_string(PRINT_ANY, "type", " type %s",
5007 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
5008 print_uint(PRINT_ANY, "size", " size %u",
5009 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
5010 print_string(PRINT_ANY, "thtype", " thtype %s",
5011 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
5012 if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
5013 print_uint(PRINT_ANY, "cell_size", " cell size %u",
5014 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
5015 pr_out_handle_end(dl);
5016}
5017
5018static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
5019{
5020 struct dl *dl = data;
5021 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5022 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5023
5024 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5025 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5026 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
5027 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
5028 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
5029 return MNL_CB_ERROR;
5030 pr_out_sb_pool(dl, tb);
5031 return MNL_CB_OK;
5032}
5033
5034static int cmd_sb_pool_show(struct dl *dl)
5035{
5036 struct nlmsghdr *nlh;
5037 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5038 int err;
5039
5040 if (dl_argc(dl) == 0)
5041 flags |= NLM_F_DUMP;
5042
5043 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
5044
5045 if (dl_argc(dl) > 0) {
5046 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
5047 DL_OPT_SB);
5048 if (err)
5049 return err;
5050 }
5051
5052 pr_out_section_start(dl, "pool");
5053 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
5054 pr_out_section_end(dl);
5055 return err;
5056}
5057
5058static int cmd_sb_pool_set(struct dl *dl)
5059{
5060 struct nlmsghdr *nlh;
5061 int err;
5062
5063 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_POOL_SET,
5064 NLM_F_REQUEST | NLM_F_ACK);
5065
5066 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
5067 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
5068 if (err)
5069 return err;
5070
5071 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5072}
5073
5074static int cmd_sb_pool(struct dl *dl)
5075{
5076 if (dl_argv_match(dl, "help")) {
5077 cmd_sb_help();
5078 return 0;
5079 } else if (dl_argv_match(dl, "show") ||
5080 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5081 dl_arg_inc(dl);
5082 return cmd_sb_pool_show(dl);
5083 } else if (dl_argv_match(dl, "set")) {
5084 dl_arg_inc(dl);
5085 return cmd_sb_pool_set(dl);
5086 }
5087 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5088 return -ENOENT;
5089}
5090
5091static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
5092{
5093 pr_out_port_handle_start_arr(dl, tb, true);
5094 check_indent_newline(dl);
5095 print_uint(PRINT_ANY, "sb", "sb %u",
5096 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5097 print_uint(PRINT_ANY, "pool", " pool %u",
5098 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5099 print_uint(PRINT_ANY, "threshold", " threshold %u",
5100 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
5101 pr_out_port_handle_end(dl);
5102}
5103
5104static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
5105{
5106 struct dl *dl = data;
5107 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5108 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5109
5110 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5111 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5112 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5113 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
5114 return MNL_CB_ERROR;
5115 pr_out_sb_port_pool(dl, tb);
5116 return MNL_CB_OK;
5117}
5118
5119static int cmd_sb_port_pool_show(struct dl *dl)
5120{
5121 struct nlmsghdr *nlh;
5122 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5123 int err;
5124
5125 if (dl_argc(dl) == 0)
5126 flags |= NLM_F_DUMP;
5127
5128 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
5129
5130 if (dl_argc(dl) > 0) {
5131 err = dl_argv_parse_put(nlh, dl,
5132 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
5133 DL_OPT_SB);
5134 if (err)
5135 return err;
5136 }
5137
5138 pr_out_section_start(dl, "port_pool");
5139 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
5140 pr_out_section_end(dl);
5141 return 0;
5142}
5143
5144static int cmd_sb_port_pool_set(struct dl *dl)
5145{
5146 struct nlmsghdr *nlh;
5147 int err;
5148
5149 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
5150 NLM_F_REQUEST | NLM_F_ACK);
5151
5152 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
5153 DL_OPT_SB_TH, DL_OPT_SB);
5154 if (err)
5155 return err;
5156
5157 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5158}
5159
5160static int cmd_sb_port_pool(struct dl *dl)
5161{
5162 if (dl_argv_match(dl, "help")) {
5163 cmd_sb_help();
5164 return 0;
5165 } else if (dl_argv_match(dl, "show") ||
5166 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5167 dl_arg_inc(dl);
5168 return cmd_sb_port_pool_show(dl);
5169 } else if (dl_argv_match(dl, "set")) {
5170 dl_arg_inc(dl);
5171 return cmd_sb_port_pool_set(dl);
5172 }
5173 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5174 return -ENOENT;
5175}
5176
5177static int cmd_sb_port(struct dl *dl)
5178{
5179 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5180 cmd_sb_help();
5181 return 0;
5182 } else if (dl_argv_match(dl, "pool")) {
5183 dl_arg_inc(dl);
5184 return cmd_sb_port_pool(dl);
5185 }
5186 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5187 return -ENOENT;
5188}
5189
5190static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
5191{
5192 pr_out_port_handle_start_arr(dl, tb, true);
5193 check_indent_newline(dl);
5194 print_uint(PRINT_ANY, "sb", "sb %u",
5195 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
5196 print_uint(PRINT_ANY, "tc", " tc %u",
5197 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
5198 print_string(PRINT_ANY, "type", " type %s",
5199 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
5200 print_uint(PRINT_ANY, "pool", " pool %u",
5201 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
5202 print_uint(PRINT_ANY, "threshold", " threshold %u",
5203 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
5204 pr_out_port_handle_end(dl);
5205}
5206
5207static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
5208{
5209 struct dl *dl = data;
5210 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5211 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5212
5213 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5214 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5215 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
5216 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
5217 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
5218 return MNL_CB_ERROR;
5219 pr_out_sb_tc_bind(dl, tb);
5220 return MNL_CB_OK;
5221}
5222
5223static int cmd_sb_tc_bind_show(struct dl *dl)
5224{
5225 struct nlmsghdr *nlh;
5226 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
5227 int err;
5228
5229 if (dl_argc(dl) == 0)
5230 flags |= NLM_F_DUMP;
5231
5232 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
5233
5234 if (dl_argc(dl) > 0) {
5235 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
5236 DL_OPT_SB_TYPE, DL_OPT_SB);
5237 if (err)
5238 return err;
5239 }
5240
5241 pr_out_section_start(dl, "tc_bind");
5242 err = mnlu_gen_socket_sndrcv(&dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
5243 pr_out_section_end(dl);
5244 return err;
5245}
5246
5247static int cmd_sb_tc_bind_set(struct dl *dl)
5248{
5249 struct nlmsghdr *nlh;
5250 int err;
5251
5252 nlh = mnlu_gen_socket_cmd_prepare(&dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
5253 NLM_F_REQUEST | NLM_F_ACK);
5254
5255 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
5256 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
5257 DL_OPT_SB);
5258 if (err)
5259 return err;
5260
5261 return mnlu_gen_socket_sndrcv(&dl->nlg, nlh, NULL, NULL);
5262}
5263
5264static int cmd_sb_tc_bind(struct dl *dl)
5265{
5266 if (dl_argv_match(dl, "help")) {
5267 cmd_sb_help();
5268 return 0;
5269 } else if (dl_argv_match(dl, "show") ||
5270 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
5271 dl_arg_inc(dl);
5272 return cmd_sb_tc_bind_show(dl);
5273 } else if (dl_argv_match(dl, "set")) {
5274 dl_arg_inc(dl);
5275 return cmd_sb_tc_bind_set(dl);
5276 }
5277 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5278 return -ENOENT;
5279}
5280
5281static int cmd_sb_tc(struct dl *dl)
5282{
5283 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5284 cmd_sb_help();
5285 return 0;
5286 } else if (dl_argv_match(dl, "bind")) {
5287 dl_arg_inc(dl);
5288 return cmd_sb_tc_bind(dl);
5289 }
5290 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5291 return -ENOENT;
5292}
5293
5294struct occ_item {
5295 struct list_head list;
5296 uint32_t index;
5297 uint32_t cur;
5298 uint32_t max;
5299 uint32_t bound_pool_index;
5300};
5301
5302struct occ_port {
5303 struct list_head list;
5304 char *bus_name;
5305 char *dev_name;
5306 uint32_t port_index;
5307 uint32_t sb_index;
5308 struct list_head pool_list;
5309 struct list_head ing_tc_list;
5310 struct list_head eg_tc_list;
5311};
5312
5313struct occ_show {
5314 struct dl *dl;
5315 int err;
5316 struct list_head port_list;
5317};
5318
5319static struct occ_item *occ_item_alloc(void)
5320{
5321 return calloc(1, sizeof(struct occ_item));
5322}
5323
5324static void occ_item_free(struct occ_item *occ_item)
5325{
5326 free(occ_item);
5327}
5328
5329static struct occ_port *occ_port_alloc(uint32_t port_index)
5330{
5331 struct occ_port *occ_port;
5332
5333 occ_port = calloc(1, sizeof(*occ_port));
5334 if (!occ_port)
5335 return NULL;
5336 occ_port->port_index = port_index;
5337 INIT_LIST_HEAD(&occ_port->pool_list);
5338 INIT_LIST_HEAD(&occ_port->ing_tc_list);
5339 INIT_LIST_HEAD(&occ_port->eg_tc_list);
5340 return occ_port;
5341}
5342
5343static void occ_port_free(struct occ_port *occ_port)
5344{
5345 struct occ_item *occ_item, *tmp;
5346
5347 list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
5348 occ_item_free(occ_item);
5349 list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
5350 occ_item_free(occ_item);
5351 list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
5352 occ_item_free(occ_item);
5353}
5354
5355static struct occ_show *occ_show_alloc(struct dl *dl)
5356{
5357 struct occ_show *occ_show;
5358
5359 occ_show = calloc(1, sizeof(*occ_show));
5360 if (!occ_show)
5361 return NULL;
5362 occ_show->dl = dl;
5363 INIT_LIST_HEAD(&occ_show->port_list);
5364 return occ_show;
5365}
5366
5367static void occ_show_free(struct occ_show *occ_show)
5368{
5369 struct occ_port *occ_port, *tmp;
5370
5371 list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
5372 occ_port_free(occ_port);
5373}
5374
5375static struct occ_port *occ_port_get(struct occ_show *occ_show,
5376 struct nlattr **tb)
5377{
5378 struct occ_port *occ_port;
5379 uint32_t port_index;
5380
5381 port_index = mnl_attr_get_u32(