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