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