]> git.proxmox.com Git - mirror_iproute2.git/blob - devlink/devlink.c
devlink: Replace pr_#type_value wrapper functions with common functions
[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_bool(struct dl *dl, const char *name, bool val)
1880 {
1881 if (dl->json_output)
1882 print_bool(PRINT_JSON, name, NULL, val);
1883 else
1884 print_string_name_value(name, val ? "true" : "false");
1885 }
1886
1887 static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
1888 {
1889 __pr_out_indent_newline(dl);
1890 if (dl->json_output)
1891 print_uint(PRINT_JSON, name, NULL, val);
1892 else
1893 pr_out("%s %u", name, val);
1894 }
1895
1896 static void pr_out_u64(struct dl *dl, const char *name, uint64_t val)
1897 {
1898 __pr_out_indent_newline(dl);
1899 if (val == (uint64_t) -1)
1900 return print_string_name_value(name, "unlimited");
1901
1902 if (dl->json_output)
1903 print_u64(PRINT_JSON, name, NULL, val);
1904 else
1905 pr_out("%s %"PRIu64, name, val);
1906 }
1907
1908 static bool is_binary_eol(int i)
1909 {
1910 return !(i%16);
1911 }
1912
1913 static void pr_out_binary_value(struct dl *dl, uint8_t *data, uint32_t len)
1914 {
1915 int i = 0;
1916
1917 while (i < len) {
1918 if (dl->json_output)
1919 print_int(PRINT_JSON, NULL, NULL, data[i]);
1920 else
1921 pr_out("%02x ", data[i]);
1922 i++;
1923 if (!dl->json_output && is_binary_eol(i))
1924 __pr_out_newline();
1925 }
1926 if (!dl->json_output && !is_binary_eol(i))
1927 __pr_out_newline();
1928 }
1929
1930 static void pr_out_name(struct dl *dl, const char *name)
1931 {
1932 __pr_out_indent_newline(dl);
1933 if (dl->json_output)
1934 print_string(PRINT_JSON, name, NULL, NULL);
1935 else
1936 pr_out("%s:", name);
1937 }
1938
1939 static void pr_out_region_chunk_start(struct dl *dl, uint64_t addr)
1940 {
1941 if (dl->json_output) {
1942 print_uint(PRINT_JSON, "address", NULL, addr);
1943 open_json_array(PRINT_JSON, "data");
1944 }
1945 }
1946
1947 static void pr_out_region_chunk_end(struct dl *dl)
1948 {
1949 if (dl->json_output)
1950 close_json_array(PRINT_JSON, NULL);
1951 }
1952
1953 static void pr_out_region_chunk(struct dl *dl, uint8_t *data, uint32_t len,
1954 uint64_t addr)
1955 {
1956 static uint64_t align_val;
1957 uint32_t i = 0;
1958
1959 pr_out_region_chunk_start(dl, addr);
1960 while (i < len) {
1961 if (!dl->json_output)
1962 if (!(align_val % 16))
1963 pr_out("%s%016"PRIx64" ",
1964 align_val ? "\n" : "",
1965 addr);
1966
1967 align_val++;
1968
1969 if (dl->json_output)
1970 print_int(PRINT_JSON, NULL, NULL, data[i]);
1971 else
1972 pr_out("%02x ", data[i]);
1973
1974 addr++;
1975 i++;
1976 }
1977 pr_out_region_chunk_end(dl);
1978 }
1979
1980 static void pr_out_section_start(struct dl *dl, const char *name)
1981 {
1982 if (dl->json_output) {
1983 open_json_object(NULL);
1984 open_json_object(name);
1985 }
1986 }
1987
1988 static void pr_out_section_end(struct dl *dl)
1989 {
1990 if (dl->json_output) {
1991 if (dl->arr_last.present)
1992 close_json_array(PRINT_JSON, NULL);
1993 close_json_object();
1994 close_json_object();
1995 }
1996 }
1997
1998 static void pr_out_array_start(struct dl *dl, const char *name)
1999 {
2000 if (dl->json_output) {
2001 open_json_array(PRINT_JSON, name);
2002 } else {
2003 __pr_out_indent_inc();
2004 __pr_out_newline();
2005 pr_out("%s:", name);
2006 __pr_out_indent_inc();
2007 __pr_out_newline();
2008 }
2009 }
2010
2011 static void pr_out_array_end(struct dl *dl)
2012 {
2013 if (dl->json_output) {
2014 close_json_array(PRINT_JSON, NULL);
2015 } else {
2016 __pr_out_indent_dec();
2017 __pr_out_indent_dec();
2018 }
2019 }
2020
2021 static void pr_out_object_start(struct dl *dl, const char *name)
2022 {
2023 if (dl->json_output) {
2024 open_json_object(name);
2025 } else {
2026 __pr_out_indent_inc();
2027 __pr_out_newline();
2028 pr_out("%s:", name);
2029 __pr_out_indent_inc();
2030 __pr_out_newline();
2031 }
2032 }
2033
2034 static void pr_out_object_end(struct dl *dl)
2035 {
2036 if (dl->json_output) {
2037 close_json_object();
2038 } else {
2039 __pr_out_indent_dec();
2040 __pr_out_indent_dec();
2041 }
2042 }
2043
2044 static void pr_out_entry_start(struct dl *dl)
2045 {
2046 if (dl->json_output)
2047 open_json_object(NULL);
2048 }
2049
2050 static void pr_out_entry_end(struct dl *dl)
2051 {
2052 if (dl->json_output)
2053 close_json_object();
2054 else
2055 __pr_out_newline();
2056 }
2057
2058 static void pr_out_stats(struct dl *dl, struct nlattr *nla_stats)
2059 {
2060 struct nlattr *tb[DEVLINK_ATTR_STATS_MAX + 1] = {};
2061 int err;
2062
2063 if (!dl->stats)
2064 return;
2065
2066 err = mnl_attr_parse_nested(nla_stats, attr_stats_cb, tb);
2067 if (err != MNL_CB_OK)
2068 return;
2069
2070 pr_out_object_start(dl, "stats");
2071 pr_out_object_start(dl, "rx");
2072 if (tb[DEVLINK_ATTR_STATS_RX_BYTES])
2073 pr_out_u64(dl, "bytes",
2074 mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_BYTES]));
2075 if (tb[DEVLINK_ATTR_STATS_RX_PACKETS])
2076 pr_out_u64(dl, "packets",
2077 mnl_attr_get_u64(tb[DEVLINK_ATTR_STATS_RX_PACKETS]));
2078 pr_out_object_end(dl);
2079 pr_out_object_end(dl);
2080 }
2081
2082 static const char *param_cmode_name(uint8_t cmode)
2083 {
2084 switch (cmode) {
2085 case DEVLINK_PARAM_CMODE_RUNTIME:
2086 return PARAM_CMODE_RUNTIME_STR;
2087 case DEVLINK_PARAM_CMODE_DRIVERINIT:
2088 return PARAM_CMODE_DRIVERINIT_STR;
2089 case DEVLINK_PARAM_CMODE_PERMANENT:
2090 return PARAM_CMODE_PERMANENT_STR;
2091 default: return "<unknown type>";
2092 }
2093 }
2094
2095 static const char *eswitch_mode_name(uint32_t mode)
2096 {
2097 switch (mode) {
2098 case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY;
2099 case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV;
2100 default: return "<unknown mode>";
2101 }
2102 }
2103
2104 static const char *eswitch_inline_mode_name(uint32_t mode)
2105 {
2106 switch (mode) {
2107 case DEVLINK_ESWITCH_INLINE_MODE_NONE:
2108 return ESWITCH_INLINE_MODE_NONE;
2109 case DEVLINK_ESWITCH_INLINE_MODE_LINK:
2110 return ESWITCH_INLINE_MODE_LINK;
2111 case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
2112 return ESWITCH_INLINE_MODE_NETWORK;
2113 case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
2114 return ESWITCH_INLINE_MODE_TRANSPORT;
2115 default:
2116 return "<unknown mode>";
2117 }
2118 }
2119
2120 static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
2121 {
2122 __pr_out_handle_start(dl, tb, true, false);
2123
2124 if (tb[DEVLINK_ATTR_ESWITCH_MODE]) {
2125 check_indent_newline(dl);
2126 print_string(PRINT_ANY, "mode", "mode %s",
2127 eswitch_mode_name(mnl_attr_get_u16(
2128 tb[DEVLINK_ATTR_ESWITCH_MODE])));
2129 }
2130 if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE]) {
2131 check_indent_newline(dl);
2132 print_string(PRINT_ANY, "inline-mode", "inline-mode %s",
2133 eswitch_inline_mode_name(mnl_attr_get_u8(
2134 tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
2135 }
2136 if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
2137 bool encap_mode = !!mnl_attr_get_u8(tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
2138
2139 check_indent_newline(dl);
2140 print_string(PRINT_ANY, "encap", "encap %s",
2141 encap_mode ? "enable" : "disable");
2142 }
2143
2144 pr_out_handle_end(dl);
2145 }
2146
2147 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data)
2148 {
2149 struct dl *dl = data;
2150 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2151 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2152
2153 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2154 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2155 return MNL_CB_ERROR;
2156 pr_out_eswitch(dl, tb);
2157 return MNL_CB_OK;
2158 }
2159
2160 static int cmd_dev_eswitch_show(struct dl *dl)
2161 {
2162 struct nlmsghdr *nlh;
2163 int err;
2164
2165 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_GET,
2166 NLM_F_REQUEST | NLM_F_ACK);
2167
2168 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2169 if (err)
2170 return err;
2171
2172 pr_out_section_start(dl, "dev");
2173 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl);
2174 pr_out_section_end(dl);
2175 return err;
2176 }
2177
2178 static int cmd_dev_eswitch_set(struct dl *dl)
2179 {
2180 struct nlmsghdr *nlh;
2181 int err;
2182
2183 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_SET,
2184 NLM_F_REQUEST | NLM_F_ACK);
2185
2186 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
2187 DL_OPT_ESWITCH_MODE |
2188 DL_OPT_ESWITCH_INLINE_MODE |
2189 DL_OPT_ESWITCH_ENCAP_MODE);
2190
2191 if (err)
2192 return err;
2193
2194 if (dl->opts.present == 1) {
2195 pr_err("Need to set at least one option\n");
2196 return -ENOENT;
2197 }
2198
2199 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2200 }
2201
2202 static int cmd_dev_eswitch(struct dl *dl)
2203 {
2204 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2205 cmd_dev_help();
2206 return 0;
2207 } else if (dl_argv_match(dl, "set")) {
2208 dl_arg_inc(dl);
2209 return cmd_dev_eswitch_set(dl);
2210 } else if (dl_argv_match(dl, "show")) {
2211 dl_arg_inc(dl);
2212 return cmd_dev_eswitch_show(dl);
2213 }
2214 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2215 return -ENOENT;
2216 }
2217
2218 struct param_val_conv {
2219 const char *name;
2220 const char *vstr;
2221 uint32_t vuint;
2222 };
2223
2224 static bool param_val_conv_exists(const struct param_val_conv *param_val_conv,
2225 uint32_t len, const char *name)
2226 {
2227 uint32_t i;
2228
2229 for (i = 0; i < len; i++)
2230 if (!strcmp(param_val_conv[i].name, name))
2231 return true;
2232
2233 return false;
2234 }
2235
2236 static int
2237 param_val_conv_uint_get(const struct param_val_conv *param_val_conv,
2238 uint32_t len, const char *name, const char *vstr,
2239 uint32_t *vuint)
2240 {
2241 uint32_t i;
2242
2243 for (i = 0; i < len; i++)
2244 if (!strcmp(param_val_conv[i].name, name) &&
2245 !strcmp(param_val_conv[i].vstr, vstr)) {
2246 *vuint = param_val_conv[i].vuint;
2247 return 0;
2248 }
2249
2250 return -ENOENT;
2251 }
2252
2253 static int
2254 param_val_conv_str_get(const struct param_val_conv *param_val_conv,
2255 uint32_t len, const char *name, uint32_t vuint,
2256 const char **vstr)
2257 {
2258 uint32_t i;
2259
2260 for (i = 0; i < len; i++)
2261 if (!strcmp(param_val_conv[i].name, name) &&
2262 param_val_conv[i].vuint == vuint) {
2263 *vstr = param_val_conv[i].vstr;
2264 return 0;
2265 }
2266
2267 return -ENOENT;
2268 }
2269
2270 static const struct param_val_conv param_val_conv[] = {
2271 {
2272 .name = "fw_load_policy",
2273 .vstr = "driver",
2274 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_DRIVER,
2275 },
2276 {
2277 .name = "fw_load_policy",
2278 .vstr = "flash",
2279 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_FLASH,
2280 },
2281 {
2282 .name = "reset_dev_on_drv_probe",
2283 .vstr = "unknown",
2284 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_UNKNOWN,
2285 },
2286 {
2287 .name = "fw_load_policy",
2288 .vstr = "unknown",
2289 .vuint = DEVLINK_PARAM_FW_LOAD_POLICY_VALUE_UNKNOWN,
2290 },
2291 {
2292 .name = "reset_dev_on_drv_probe",
2293 .vstr = "always",
2294 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_ALWAYS,
2295 },
2296 {
2297 .name = "reset_dev_on_drv_probe",
2298 .vstr = "never",
2299 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_NEVER,
2300 },
2301 {
2302 .name = "reset_dev_on_drv_probe",
2303 .vstr = "disk",
2304 .vuint = DEVLINK_PARAM_RESET_DEV_ON_DRV_PROBE_VALUE_DISK,
2305 },
2306 };
2307
2308 #define PARAM_VAL_CONV_LEN ARRAY_SIZE(param_val_conv)
2309
2310 static void pr_out_param_value(struct dl *dl, const char *nla_name,
2311 int nla_type, struct nlattr *nl)
2312 {
2313 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2314 struct nlattr *val_attr;
2315 const char *vstr;
2316 bool conv_exists;
2317 int err;
2318
2319 err = mnl_attr_parse_nested(nl, attr_cb, nla_value);
2320 if (err != MNL_CB_OK)
2321 return;
2322
2323 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2324 (nla_type != MNL_TYPE_FLAG &&
2325 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2326 return;
2327
2328 check_indent_newline(dl);
2329 print_string(PRINT_ANY, "cmode", "cmode %s",
2330 param_cmode_name(mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE])));
2331
2332 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2333
2334 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2335 nla_name);
2336
2337 switch (nla_type) {
2338 case MNL_TYPE_U8:
2339 if (conv_exists) {
2340 err = param_val_conv_str_get(param_val_conv,
2341 PARAM_VAL_CONV_LEN,
2342 nla_name,
2343 mnl_attr_get_u8(val_attr),
2344 &vstr);
2345 if (err)
2346 return;
2347 print_string(PRINT_ANY, "value", " value %s", vstr);
2348 } else {
2349 pr_out_uint(dl, "value", mnl_attr_get_u8(val_attr));
2350 }
2351 break;
2352 case MNL_TYPE_U16:
2353 if (conv_exists) {
2354 err = param_val_conv_str_get(param_val_conv,
2355 PARAM_VAL_CONV_LEN,
2356 nla_name,
2357 mnl_attr_get_u16(val_attr),
2358 &vstr);
2359 if (err)
2360 return;
2361 print_string(PRINT_ANY, "value", " value %s", vstr);
2362 } else {
2363 pr_out_uint(dl, "value", mnl_attr_get_u16(val_attr));
2364 }
2365 break;
2366 case MNL_TYPE_U32:
2367 if (conv_exists) {
2368 err = param_val_conv_str_get(param_val_conv,
2369 PARAM_VAL_CONV_LEN,
2370 nla_name,
2371 mnl_attr_get_u32(val_attr),
2372 &vstr);
2373 if (err)
2374 return;
2375 print_string(PRINT_ANY, "value", " value %s", vstr);
2376 } else {
2377 pr_out_uint(dl, "value", mnl_attr_get_u32(val_attr));
2378 }
2379 break;
2380 case MNL_TYPE_STRING:
2381 print_string(PRINT_ANY, "value", " value %s",
2382 mnl_attr_get_str(val_attr));
2383 break;
2384 case MNL_TYPE_FLAG:
2385 pr_out_bool(dl, "value", val_attr ? true : false);
2386 break;
2387 }
2388 }
2389
2390 static void pr_out_param(struct dl *dl, struct nlattr **tb, bool array)
2391 {
2392 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2393 struct nlattr *param_value_attr;
2394 const char *nla_name;
2395 int nla_type;
2396 int err;
2397
2398 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2399 if (err != MNL_CB_OK)
2400 return;
2401 if (!nla_param[DEVLINK_ATTR_PARAM_NAME] ||
2402 !nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2403 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2404 return;
2405
2406 if (array)
2407 pr_out_handle_start_arr(dl, tb);
2408 else
2409 __pr_out_handle_start(dl, tb, true, false);
2410
2411 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2412
2413 nla_name = mnl_attr_get_str(nla_param[DEVLINK_ATTR_PARAM_NAME]);
2414 check_indent_newline(dl);
2415 print_string(PRINT_ANY, "name", "name %s ", nla_name);
2416 if (!nla_param[DEVLINK_ATTR_PARAM_GENERIC])
2417 print_string(PRINT_ANY, "type", "type %s", "driver-specific");
2418 else
2419 print_string(PRINT_ANY, "type", "type %s", "generic");
2420
2421 pr_out_array_start(dl, "values");
2422 mnl_attr_for_each_nested(param_value_attr,
2423 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2424 pr_out_entry_start(dl);
2425 pr_out_param_value(dl, nla_name, nla_type, param_value_attr);
2426 pr_out_entry_end(dl);
2427 }
2428 pr_out_array_end(dl);
2429 pr_out_handle_end(dl);
2430 }
2431
2432 static int cmd_dev_param_show_cb(const struct nlmsghdr *nlh, void *data)
2433 {
2434 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2435 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2436 struct dl *dl = data;
2437
2438 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2439 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2440 !tb[DEVLINK_ATTR_PARAM])
2441 return MNL_CB_ERROR;
2442 pr_out_param(dl, tb, true);
2443 return MNL_CB_OK;
2444 }
2445
2446 struct param_ctx {
2447 struct dl *dl;
2448 int nla_type;
2449 union {
2450 uint8_t vu8;
2451 uint16_t vu16;
2452 uint32_t vu32;
2453 const char *vstr;
2454 bool vbool;
2455 } value;
2456 };
2457
2458 static int cmd_dev_param_set_cb(const struct nlmsghdr *nlh, void *data)
2459 {
2460 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2461 struct nlattr *nla_param[DEVLINK_ATTR_MAX + 1] = {};
2462 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2463 struct nlattr *param_value_attr;
2464 enum devlink_param_cmode cmode;
2465 struct param_ctx *ctx = data;
2466 struct dl *dl = ctx->dl;
2467 int nla_type;
2468 int err;
2469
2470 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2471 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2472 !tb[DEVLINK_ATTR_PARAM])
2473 return MNL_CB_ERROR;
2474
2475 err = mnl_attr_parse_nested(tb[DEVLINK_ATTR_PARAM], attr_cb, nla_param);
2476 if (err != MNL_CB_OK)
2477 return MNL_CB_ERROR;
2478
2479 if (!nla_param[DEVLINK_ATTR_PARAM_TYPE] ||
2480 !nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST])
2481 return MNL_CB_ERROR;
2482
2483 nla_type = mnl_attr_get_u8(nla_param[DEVLINK_ATTR_PARAM_TYPE]);
2484 mnl_attr_for_each_nested(param_value_attr,
2485 nla_param[DEVLINK_ATTR_PARAM_VALUES_LIST]) {
2486 struct nlattr *nla_value[DEVLINK_ATTR_MAX + 1] = {};
2487 struct nlattr *val_attr;
2488
2489 err = mnl_attr_parse_nested(param_value_attr,
2490 attr_cb, nla_value);
2491 if (err != MNL_CB_OK)
2492 return MNL_CB_ERROR;
2493
2494 if (!nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE] ||
2495 (nla_type != MNL_TYPE_FLAG &&
2496 !nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA]))
2497 return MNL_CB_ERROR;
2498
2499 cmode = mnl_attr_get_u8(nla_value[DEVLINK_ATTR_PARAM_VALUE_CMODE]);
2500 if (cmode == dl->opts.cmode) {
2501 val_attr = nla_value[DEVLINK_ATTR_PARAM_VALUE_DATA];
2502 switch (nla_type) {
2503 case MNL_TYPE_U8:
2504 ctx->value.vu8 = mnl_attr_get_u8(val_attr);
2505 break;
2506 case MNL_TYPE_U16:
2507 ctx->value.vu16 = mnl_attr_get_u16(val_attr);
2508 break;
2509 case MNL_TYPE_U32:
2510 ctx->value.vu32 = mnl_attr_get_u32(val_attr);
2511 break;
2512 case MNL_TYPE_STRING:
2513 ctx->value.vstr = mnl_attr_get_str(val_attr);
2514 break;
2515 case MNL_TYPE_FLAG:
2516 ctx->value.vbool = val_attr ? true : false;
2517 break;
2518 }
2519 break;
2520 }
2521 }
2522 ctx->nla_type = nla_type;
2523 return MNL_CB_OK;
2524 }
2525
2526 static int cmd_dev_param_set(struct dl *dl)
2527 {
2528 struct param_ctx ctx = {};
2529 struct nlmsghdr *nlh;
2530 bool conv_exists;
2531 uint32_t val_u32;
2532 uint16_t val_u16;
2533 uint8_t val_u8;
2534 bool val_bool;
2535 int err;
2536
2537 err = dl_argv_parse(dl, DL_OPT_HANDLE |
2538 DL_OPT_PARAM_NAME |
2539 DL_OPT_PARAM_VALUE |
2540 DL_OPT_PARAM_CMODE, 0);
2541 if (err)
2542 return err;
2543
2544 /* Get value type */
2545 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET,
2546 NLM_F_REQUEST | NLM_F_ACK);
2547 dl_opts_put(nlh, dl);
2548
2549 ctx.dl = dl;
2550 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_set_cb, &ctx);
2551 if (err)
2552 return err;
2553
2554 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_SET,
2555 NLM_F_REQUEST | NLM_F_ACK);
2556 dl_opts_put(nlh, dl);
2557
2558 conv_exists = param_val_conv_exists(param_val_conv, PARAM_VAL_CONV_LEN,
2559 dl->opts.param_name);
2560
2561 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_TYPE, ctx.nla_type);
2562 switch (ctx.nla_type) {
2563 case MNL_TYPE_U8:
2564 if (conv_exists) {
2565 err = param_val_conv_uint_get(param_val_conv,
2566 PARAM_VAL_CONV_LEN,
2567 dl->opts.param_name,
2568 dl->opts.param_value,
2569 &val_u32);
2570 val_u8 = val_u32;
2571 } else {
2572 err = strtouint8_t(dl->opts.param_value, &val_u8);
2573 }
2574 if (err)
2575 goto err_param_value_parse;
2576 if (val_u8 == ctx.value.vu8)
2577 return 0;
2578 mnl_attr_put_u8(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u8);
2579 break;
2580 case MNL_TYPE_U16:
2581 if (conv_exists) {
2582 err = param_val_conv_uint_get(param_val_conv,
2583 PARAM_VAL_CONV_LEN,
2584 dl->opts.param_name,
2585 dl->opts.param_value,
2586 &val_u32);
2587 val_u16 = val_u32;
2588 } else {
2589 err = strtouint16_t(dl->opts.param_value, &val_u16);
2590 }
2591 if (err)
2592 goto err_param_value_parse;
2593 if (val_u16 == ctx.value.vu16)
2594 return 0;
2595 mnl_attr_put_u16(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u16);
2596 break;
2597 case MNL_TYPE_U32:
2598 if (conv_exists)
2599 err = param_val_conv_uint_get(param_val_conv,
2600 PARAM_VAL_CONV_LEN,
2601 dl->opts.param_name,
2602 dl->opts.param_value,
2603 &val_u32);
2604 else
2605 err = strtouint32_t(dl->opts.param_value, &val_u32);
2606 if (err)
2607 goto err_param_value_parse;
2608 if (val_u32 == ctx.value.vu32)
2609 return 0;
2610 mnl_attr_put_u32(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA, val_u32);
2611 break;
2612 case MNL_TYPE_FLAG:
2613 err = strtobool(dl->opts.param_value, &val_bool);
2614 if (err)
2615 goto err_param_value_parse;
2616 if (val_bool == ctx.value.vbool)
2617 return 0;
2618 if (val_bool)
2619 mnl_attr_put(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2620 0, NULL);
2621 break;
2622 case MNL_TYPE_STRING:
2623 mnl_attr_put_strz(nlh, DEVLINK_ATTR_PARAM_VALUE_DATA,
2624 dl->opts.param_value);
2625 if (!strcmp(dl->opts.param_value, ctx.value.vstr))
2626 return 0;
2627 break;
2628 default:
2629 printf("Value type not supported\n");
2630 return -ENOTSUP;
2631 }
2632 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2633
2634 err_param_value_parse:
2635 pr_err("Value \"%s\" is not a number or not within range\n",
2636 dl->opts.param_value);
2637 return err;
2638 }
2639
2640 static int cmd_dev_param_show(struct dl *dl)
2641 {
2642 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2643 struct nlmsghdr *nlh;
2644 int err;
2645
2646 if (dl_argc(dl) == 0)
2647 flags |= NLM_F_DUMP;
2648
2649 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PARAM_GET, flags);
2650
2651 if (dl_argc(dl) > 0) {
2652 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE |
2653 DL_OPT_PARAM_NAME, 0);
2654 if (err)
2655 return err;
2656 }
2657
2658 pr_out_section_start(dl, "param");
2659 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_param_show_cb, dl);
2660 pr_out_section_end(dl);
2661 return err;
2662 }
2663
2664 static int cmd_dev_param(struct dl *dl)
2665 {
2666 if (dl_argv_match(dl, "help")) {
2667 cmd_dev_help();
2668 return 0;
2669 } else if (dl_argv_match(dl, "show") ||
2670 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2671 dl_arg_inc(dl);
2672 return cmd_dev_param_show(dl);
2673 } else if (dl_argv_match(dl, "set")) {
2674 dl_arg_inc(dl);
2675 return cmd_dev_param_set(dl);
2676 }
2677 pr_err("Command \"%s\" not found\n", dl_argv(dl));
2678 return -ENOENT;
2679 }
2680 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
2681 {
2682 struct dl *dl = data;
2683 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2684 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2685 uint8_t reload_failed = 0;
2686
2687 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2688 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2689 return MNL_CB_ERROR;
2690
2691 if (tb[DEVLINK_ATTR_RELOAD_FAILED])
2692 reload_failed = mnl_attr_get_u8(tb[DEVLINK_ATTR_RELOAD_FAILED]);
2693
2694 if (reload_failed) {
2695 __pr_out_handle_start(dl, tb, true, false);
2696 pr_out_bool(dl, "reload_failed", true);
2697 pr_out_handle_end(dl);
2698 } else {
2699 pr_out_handle(dl, tb);
2700 }
2701
2702 return MNL_CB_OK;
2703 }
2704
2705 static int cmd_dev_show(struct dl *dl)
2706 {
2707 struct nlmsghdr *nlh;
2708 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2709 int err;
2710
2711 if (dl_argc(dl) == 0)
2712 flags |= NLM_F_DUMP;
2713
2714 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
2715
2716 if (dl_argc(dl) > 0) {
2717 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2718 if (err)
2719 return err;
2720 }
2721
2722 pr_out_section_start(dl, "dev");
2723 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl);
2724 pr_out_section_end(dl);
2725 return err;
2726 }
2727
2728 static void cmd_dev_reload_help(void)
2729 {
2730 pr_err("Usage: devlink dev reload DEV [ netns { PID | NAME | ID } ]\n");
2731 }
2732
2733 static int cmd_dev_reload(struct dl *dl)
2734 {
2735 struct nlmsghdr *nlh;
2736 int err;
2737
2738 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2739 cmd_dev_reload_help();
2740 return 0;
2741 }
2742
2743 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RELOAD,
2744 NLM_F_REQUEST | NLM_F_ACK);
2745
2746 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_NETNS);
2747 if (err)
2748 return err;
2749
2750 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2751 }
2752
2753 static void pr_out_versions_single(struct dl *dl, const struct nlmsghdr *nlh,
2754 const char *name, int type)
2755 {
2756 struct nlattr *version;
2757
2758 mnl_attr_for_each(version, nlh, sizeof(struct genlmsghdr)) {
2759 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2760 const char *ver_value;
2761 const char *ver_name;
2762 int err;
2763
2764 if (mnl_attr_get_type(version) != type)
2765 continue;
2766
2767 err = mnl_attr_parse_nested(version, attr_cb, tb);
2768 if (err != MNL_CB_OK)
2769 continue;
2770
2771 if (!tb[DEVLINK_ATTR_INFO_VERSION_NAME] ||
2772 !tb[DEVLINK_ATTR_INFO_VERSION_VALUE])
2773 continue;
2774
2775 if (name) {
2776 pr_out_object_start(dl, name);
2777 name = NULL;
2778 }
2779
2780 ver_name = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_NAME]);
2781 ver_value = mnl_attr_get_str(tb[DEVLINK_ATTR_INFO_VERSION_VALUE]);
2782
2783 check_indent_newline(dl);
2784 print_string_name_value(ver_name, ver_value);
2785 if (!dl->json_output)
2786 __pr_out_newline();
2787 }
2788
2789 if (!name)
2790 pr_out_object_end(dl);
2791 }
2792
2793 static void pr_out_info(struct dl *dl, const struct nlmsghdr *nlh,
2794 struct nlattr **tb, bool has_versions)
2795 {
2796 __pr_out_handle_start(dl, tb, true, false);
2797
2798 __pr_out_indent_inc();
2799 if (tb[DEVLINK_ATTR_INFO_DRIVER_NAME]) {
2800 struct nlattr *nla_drv = tb[DEVLINK_ATTR_INFO_DRIVER_NAME];
2801
2802 if (!dl->json_output)
2803 __pr_out_newline();
2804 check_indent_newline(dl);
2805 print_string(PRINT_ANY, "driver", "driver %s",
2806 mnl_attr_get_str(nla_drv));
2807 }
2808
2809 if (tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER]) {
2810 struct nlattr *nla_sn = tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER];
2811
2812 if (!dl->json_output)
2813 __pr_out_newline();
2814 check_indent_newline(dl);
2815 print_string(PRINT_ANY, "serial_number", "serial_number %s",
2816 mnl_attr_get_str(nla_sn));
2817 }
2818 __pr_out_indent_dec();
2819
2820 if (has_versions) {
2821 pr_out_object_start(dl, "versions");
2822
2823 pr_out_versions_single(dl, nlh, "fixed",
2824 DEVLINK_ATTR_INFO_VERSION_FIXED);
2825 pr_out_versions_single(dl, nlh, "running",
2826 DEVLINK_ATTR_INFO_VERSION_RUNNING);
2827 pr_out_versions_single(dl, nlh, "stored",
2828 DEVLINK_ATTR_INFO_VERSION_STORED);
2829
2830 pr_out_object_end(dl);
2831 }
2832
2833 pr_out_handle_end(dl);
2834 }
2835
2836 static int cmd_versions_show_cb(const struct nlmsghdr *nlh, void *data)
2837 {
2838 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2839 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2840 bool has_versions, has_info;
2841 struct dl *dl = data;
2842
2843 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2844
2845 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2846 return MNL_CB_ERROR;
2847
2848 has_versions = tb[DEVLINK_ATTR_INFO_VERSION_FIXED] ||
2849 tb[DEVLINK_ATTR_INFO_VERSION_RUNNING] ||
2850 tb[DEVLINK_ATTR_INFO_VERSION_STORED];
2851 has_info = tb[DEVLINK_ATTR_INFO_DRIVER_NAME] ||
2852 tb[DEVLINK_ATTR_INFO_SERIAL_NUMBER] ||
2853 has_versions;
2854
2855 if (has_info)
2856 pr_out_info(dl, nlh, tb, has_versions);
2857
2858 return MNL_CB_OK;
2859 }
2860
2861 static void cmd_dev_info_help(void)
2862 {
2863 pr_err("Usage: devlink dev info [ DEV ]\n");
2864 }
2865
2866 static int cmd_dev_info(struct dl *dl)
2867 {
2868 struct nlmsghdr *nlh;
2869 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2870 int err;
2871
2872 if (dl_argv_match(dl, "help")) {
2873 cmd_dev_info_help();
2874 return 0;
2875 }
2876
2877 if (dl_argc(dl) == 0)
2878 flags |= NLM_F_DUMP;
2879
2880 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_INFO_GET, flags);
2881
2882 if (dl_argc(dl) > 0) {
2883 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
2884 if (err)
2885 return err;
2886 }
2887
2888 pr_out_section_start(dl, "info");
2889 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_versions_show_cb, dl);
2890 pr_out_section_end(dl);
2891 return err;
2892 }
2893
2894 static void cmd_dev_flash_help(void)
2895 {
2896 pr_err("Usage: devlink dev flash DEV file PATH [ component NAME ]\n");
2897 }
2898
2899
2900 struct cmd_dev_flash_status_ctx {
2901 struct dl *dl;
2902 char *last_msg;
2903 char *last_component;
2904 uint8_t not_first:1,
2905 last_pc:1,
2906 received_end:1,
2907 flash_done:1;
2908 };
2909
2910 static int nullstrcmp(const char *str1, const char *str2)
2911 {
2912 if (str1 && str2)
2913 return strcmp(str1, str2);
2914 if (!str1 && !str2)
2915 return 0;
2916 return str1 ? 1 : -1;
2917 }
2918
2919 static int cmd_dev_flash_status_cb(const struct nlmsghdr *nlh, void *data)
2920 {
2921 struct cmd_dev_flash_status_ctx *ctx = data;
2922 struct dl_opts *opts = &ctx->dl->opts;
2923 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2924 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2925 const char *component = NULL;
2926 uint64_t done = 0, total = 0;
2927 const char *msg = NULL;
2928 const char *bus_name;
2929 const char *dev_name;
2930
2931 if (genl->cmd != DEVLINK_CMD_FLASH_UPDATE_STATUS &&
2932 genl->cmd != DEVLINK_CMD_FLASH_UPDATE_END)
2933 return MNL_CB_STOP;
2934
2935 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2936 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2937 return MNL_CB_ERROR;
2938 bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
2939 dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
2940 if (strcmp(bus_name, opts->bus_name) ||
2941 strcmp(dev_name, opts->dev_name))
2942 return MNL_CB_ERROR;
2943
2944 if (genl->cmd == DEVLINK_CMD_FLASH_UPDATE_END && ctx->not_first) {
2945 pr_out("\n");
2946 free(ctx->last_msg);
2947 free(ctx->last_component);
2948 ctx->received_end = 1;
2949 return MNL_CB_STOP;
2950 }
2951
2952 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG])
2953 msg = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]);
2954 if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT])
2955 component = mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]);
2956 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
2957 done = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]);
2958 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
2959 total = mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]);
2960
2961 if (!nullstrcmp(msg, ctx->last_msg) &&
2962 !nullstrcmp(component, ctx->last_component) &&
2963 ctx->last_pc && ctx->not_first) {
2964 pr_out_tty("\b\b\b\b\b"); /* clean percentage */
2965 } else {
2966 if (ctx->not_first)
2967 pr_out("\n");
2968 if (component) {
2969 pr_out("[%s] ", component);
2970 free(ctx->last_component);
2971 ctx->last_component = strdup(component);
2972 }
2973 if (msg) {
2974 pr_out("%s", msg);
2975 free(ctx->last_msg);
2976 ctx->last_msg = strdup(msg);
2977 }
2978 }
2979 if (total) {
2980 pr_out_tty(" %3lu%%", (done * 100) / total);
2981 ctx->last_pc = 1;
2982 } else {
2983 ctx->last_pc = 0;
2984 }
2985 fflush(stdout);
2986 ctx->not_first = 1;
2987
2988 return MNL_CB_STOP;
2989 }
2990
2991 static int cmd_dev_flash_fds_process(struct cmd_dev_flash_status_ctx *ctx,
2992 struct mnlg_socket *nlg_ntf,
2993 int pipe_r)
2994 {
2995 int nlfd = mnlg_socket_get_fd(nlg_ntf);
2996 fd_set fds[3];
2997 int fdmax;
2998 int i;
2999 int err;
3000 int err2;
3001
3002 for (i = 0; i < 3; i++)
3003 FD_ZERO(&fds[i]);
3004 FD_SET(pipe_r, &fds[0]);
3005 fdmax = pipe_r + 1;
3006 FD_SET(nlfd, &fds[0]);
3007 if (nlfd >= fdmax)
3008 fdmax = nlfd + 1;
3009
3010 while (select(fdmax, &fds[0], &fds[1], &fds[2], NULL) < 0) {
3011 if (errno == EINTR)
3012 continue;
3013 pr_err("select() failed\n");
3014 return -errno;
3015 }
3016 if (FD_ISSET(nlfd, &fds[0])) {
3017 err = _mnlg_socket_recv_run(nlg_ntf,
3018 cmd_dev_flash_status_cb, ctx);
3019 if (err)
3020 return err;
3021 }
3022 if (FD_ISSET(pipe_r, &fds[0])) {
3023 err = read(pipe_r, &err2, sizeof(err2));
3024 if (err == -1) {
3025 pr_err("Failed to read pipe\n");
3026 return -errno;
3027 }
3028 if (err2)
3029 return err2;
3030 ctx->flash_done = 1;
3031 }
3032 return 0;
3033 }
3034
3035
3036 static int cmd_dev_flash(struct dl *dl)
3037 {
3038 struct cmd_dev_flash_status_ctx ctx = {.dl = dl,};
3039 struct mnlg_socket *nlg_ntf;
3040 struct nlmsghdr *nlh;
3041 int pipe_r, pipe_w;
3042 int pipe_fds[2];
3043 pid_t pid;
3044 int err;
3045
3046 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3047 cmd_dev_flash_help();
3048 return 0;
3049 }
3050
3051 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_FLASH_UPDATE,
3052 NLM_F_REQUEST | NLM_F_ACK);
3053
3054 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_FLASH_FILE_NAME,
3055 DL_OPT_FLASH_COMPONENT);
3056 if (err)
3057 return err;
3058
3059 nlg_ntf = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
3060 if (!nlg_ntf)
3061 return err;
3062
3063 err = _mnlg_socket_group_add(nlg_ntf, DEVLINK_GENL_MCGRP_CONFIG_NAME);
3064 if (err)
3065 return err;
3066
3067 err = pipe(pipe_fds);
3068 if (err == -1)
3069 return -errno;
3070 pipe_r = pipe_fds[0];
3071 pipe_w = pipe_fds[1];
3072
3073 pid = fork();
3074 if (pid == -1) {
3075 close(pipe_r);
3076 close(pipe_w);
3077 return -errno;
3078 } else if (!pid) {
3079 /* In child, just execute the flash and pass returned
3080 * value through pipe once it is done.
3081 */
3082 close(pipe_r);
3083 err = _mnlg_socket_send(dl->nlg, nlh);
3084 write(pipe_w, &err, sizeof(err));
3085 close(pipe_w);
3086 exit(0);
3087 }
3088 close(pipe_w);
3089
3090 do {
3091 err = cmd_dev_flash_fds_process(&ctx, nlg_ntf, pipe_r);
3092 if (err)
3093 goto out;
3094 } while (!ctx.flash_done || (ctx.not_first && !ctx.received_end));
3095
3096 err = _mnlg_socket_recv_run(dl->nlg, NULL, NULL);
3097 out:
3098 close(pipe_r);
3099 mnlg_socket_close(nlg_ntf);
3100 return err;
3101 }
3102
3103 static int cmd_dev(struct dl *dl)
3104 {
3105 if (dl_argv_match(dl, "help")) {
3106 cmd_dev_help();
3107 return 0;
3108 } else if (dl_argv_match(dl, "show") ||
3109 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3110 dl_arg_inc(dl);
3111 return cmd_dev_show(dl);
3112 } else if (dl_argv_match(dl, "eswitch")) {
3113 dl_arg_inc(dl);
3114 return cmd_dev_eswitch(dl);
3115 } else if (dl_argv_match(dl, "reload")) {
3116 dl_arg_inc(dl);
3117 return cmd_dev_reload(dl);
3118 } else if (dl_argv_match(dl, "param")) {
3119 dl_arg_inc(dl);
3120 return cmd_dev_param(dl);
3121 } else if (dl_argv_match(dl, "info")) {
3122 dl_arg_inc(dl);
3123 return cmd_dev_info(dl);
3124 } else if (dl_argv_match(dl, "flash")) {
3125 dl_arg_inc(dl);
3126 return cmd_dev_flash(dl);
3127 }
3128 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3129 return -ENOENT;
3130 }
3131
3132 static void cmd_port_help(void)
3133 {
3134 pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
3135 pr_err(" devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
3136 pr_err(" devlink port split DEV/PORT_INDEX count COUNT\n");
3137 pr_err(" devlink port unsplit DEV/PORT_INDEX\n");
3138 }
3139
3140 static const char *port_type_name(uint32_t type)
3141 {
3142 switch (type) {
3143 case DEVLINK_PORT_TYPE_NOTSET: return "notset";
3144 case DEVLINK_PORT_TYPE_AUTO: return "auto";
3145 case DEVLINK_PORT_TYPE_ETH: return "eth";
3146 case DEVLINK_PORT_TYPE_IB: return "ib";
3147 default: return "<unknown type>";
3148 }
3149 }
3150
3151 static const char *port_flavour_name(uint16_t flavour)
3152 {
3153 switch (flavour) {
3154 case DEVLINK_PORT_FLAVOUR_PHYSICAL:
3155 return "physical";
3156 case DEVLINK_PORT_FLAVOUR_CPU:
3157 return "cpu";
3158 case DEVLINK_PORT_FLAVOUR_DSA:
3159 return "dsa";
3160 case DEVLINK_PORT_FLAVOUR_PCI_PF:
3161 return "pcipf";
3162 case DEVLINK_PORT_FLAVOUR_PCI_VF:
3163 return "pcivf";
3164 default:
3165 return "<unknown flavour>";
3166 }
3167 }
3168
3169 static void pr_out_port_pfvf_num(struct dl *dl, struct nlattr **tb)
3170 {
3171 uint16_t fn_num;
3172
3173 if (tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]) {
3174 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_PF_NUMBER]);
3175 pr_out_uint(dl, "pfnum", fn_num);
3176 }
3177 if (tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]) {
3178 fn_num = mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_PCI_VF_NUMBER]);
3179 pr_out_uint(dl, "vfnum", fn_num);
3180 }
3181 }
3182
3183 static void pr_out_port(struct dl *dl, struct nlattr **tb)
3184 {
3185 struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
3186 struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
3187
3188 pr_out_port_handle_start(dl, tb, false);
3189 check_indent_newline(dl);
3190 if (pt_attr) {
3191 uint16_t port_type = mnl_attr_get_u16(pt_attr);
3192
3193 print_string(PRINT_ANY, "type", "type %s",
3194 port_type_name(port_type));
3195 if (dpt_attr) {
3196 uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
3197
3198 if (port_type != des_port_type)
3199 print_string(PRINT_ANY, "des_type", " des_type %s",
3200 port_type_name(des_port_type));
3201 }
3202 }
3203 if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME]) {
3204 print_string(PRINT_ANY, "netdev", " netdev %s",
3205 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
3206 }
3207 if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME]) {
3208 print_string(PRINT_ANY, "ibdev", " ibdev %s",
3209 mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
3210 }
3211 if (tb[DEVLINK_ATTR_PORT_FLAVOUR]) {
3212 uint16_t port_flavour =
3213 mnl_attr_get_u16(tb[DEVLINK_ATTR_PORT_FLAVOUR]);
3214
3215 print_string(PRINT_ANY, "flavour", " flavour %s",
3216 port_flavour_name(port_flavour));
3217
3218 switch (port_flavour) {
3219 case DEVLINK_PORT_FLAVOUR_PCI_PF:
3220 case DEVLINK_PORT_FLAVOUR_PCI_VF:
3221 pr_out_port_pfvf_num(dl, tb);
3222 break;
3223 default:
3224 break;
3225 }
3226 }
3227 if (tb[DEVLINK_ATTR_PORT_NUMBER]) {
3228 uint32_t port_number;
3229
3230 port_number = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_NUMBER]);
3231 pr_out_uint(dl, "port", port_number);
3232 }
3233 if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
3234 pr_out_uint(dl, "split_group",
3235 mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
3236 pr_out_port_handle_end(dl);
3237 }
3238
3239 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
3240 {
3241 struct dl *dl = data;
3242 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3243 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3244
3245 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3246 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3247 !tb[DEVLINK_ATTR_PORT_INDEX])
3248 return MNL_CB_ERROR;
3249 pr_out_port(dl, tb);
3250 return MNL_CB_OK;
3251 }
3252
3253 static int cmd_port_show(struct dl *dl)
3254 {
3255 struct nlmsghdr *nlh;
3256 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3257 int err;
3258
3259 if (dl_argc(dl) == 0)
3260 flags |= NLM_F_DUMP;
3261
3262 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
3263
3264 if (dl_argc(dl) > 0) {
3265 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
3266 if (err)
3267 return err;
3268 }
3269
3270 pr_out_section_start(dl, "port");
3271 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
3272 pr_out_section_end(dl);
3273 return err;
3274 }
3275
3276 static int cmd_port_set(struct dl *dl)
3277 {
3278 struct nlmsghdr *nlh;
3279 int err;
3280
3281 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
3282 NLM_F_REQUEST | NLM_F_ACK);
3283
3284 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
3285 if (err)
3286 return err;
3287
3288 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3289 }
3290
3291 static int cmd_port_split(struct dl *dl)
3292 {
3293 struct nlmsghdr *nlh;
3294 int err;
3295
3296 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
3297 NLM_F_REQUEST | NLM_F_ACK);
3298
3299 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
3300 if (err)
3301 return err;
3302
3303 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3304 }
3305
3306 static int cmd_port_unsplit(struct dl *dl)
3307 {
3308 struct nlmsghdr *nlh;
3309 int err;
3310
3311 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
3312 NLM_F_REQUEST | NLM_F_ACK);
3313
3314 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
3315 if (err)
3316 return err;
3317
3318 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3319 }
3320
3321 static int cmd_port(struct dl *dl)
3322 {
3323 if (dl_argv_match(dl, "help")) {
3324 cmd_port_help();
3325 return 0;
3326 } else if (dl_argv_match(dl, "show") ||
3327 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3328 dl_arg_inc(dl);
3329 return cmd_port_show(dl);
3330 } else if (dl_argv_match(dl, "set")) {
3331 dl_arg_inc(dl);
3332 return cmd_port_set(dl);
3333 } else if (dl_argv_match(dl, "split")) {
3334 dl_arg_inc(dl);
3335 return cmd_port_split(dl);
3336 } else if (dl_argv_match(dl, "unsplit")) {
3337 dl_arg_inc(dl);
3338 return cmd_port_unsplit(dl);
3339 }
3340 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3341 return -ENOENT;
3342 }
3343
3344 static void cmd_sb_help(void)
3345 {
3346 pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
3347 pr_err(" devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
3348 pr_err(" devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
3349 pr_err(" size POOL_SIZE thtype { static | dynamic }\n");
3350 pr_err(" devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3351 pr_err(" pool POOL_INDEX ]\n");
3352 pr_err(" devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
3353 pr_err(" pool POOL_INDEX th THRESHOLD\n");
3354 pr_err(" devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3355 pr_err(" type { ingress | egress } ]\n");
3356 pr_err(" devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
3357 pr_err(" type { ingress | egress } pool POOL_INDEX\n");
3358 pr_err(" th THRESHOLD\n");
3359 pr_err(" devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
3360 pr_err(" devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
3361 pr_err(" devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
3362 }
3363
3364 static void pr_out_sb(struct dl *dl, struct nlattr **tb)
3365 {
3366 pr_out_handle_start_arr(dl, tb);
3367 check_indent_newline(dl);
3368 pr_out_uint(dl, "sb",
3369 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
3370 pr_out_uint(dl, "size",
3371 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
3372 pr_out_uint(dl, "ing_pools",
3373 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
3374 pr_out_uint(dl, "eg_pools",
3375 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
3376 pr_out_uint(dl, "ing_tcs",
3377 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
3378 pr_out_uint(dl, "eg_tcs",
3379 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
3380 pr_out_handle_end(dl);
3381 }
3382
3383 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
3384 {
3385 struct dl *dl = data;
3386 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3387 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3388
3389 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3390 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3391 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
3392 !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
3393 !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
3394 !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
3395 !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
3396 return MNL_CB_ERROR;
3397 pr_out_sb(dl, tb);
3398 return MNL_CB_OK;
3399 }
3400
3401 static int cmd_sb_show(struct dl *dl)
3402 {
3403 struct nlmsghdr *nlh;
3404 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3405 int err;
3406
3407 if (dl_argc(dl) == 0)
3408 flags |= NLM_F_DUMP;
3409
3410 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
3411
3412 if (dl_argc(dl) > 0) {
3413 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
3414 if (err)
3415 return err;
3416 }
3417
3418 pr_out_section_start(dl, "sb");
3419 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl);
3420 pr_out_section_end(dl);
3421 return err;
3422 }
3423
3424 static const char *pool_type_name(uint8_t type)
3425 {
3426 switch (type) {
3427 case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
3428 case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
3429 default: return "<unknown type>";
3430 }
3431 }
3432
3433 static const char *threshold_type_name(uint8_t type)
3434 {
3435 switch (type) {
3436 case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
3437 case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
3438 default: return "<unknown type>";
3439 }
3440 }
3441
3442 static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
3443 {
3444 pr_out_handle_start_arr(dl, tb);
3445 pr_out_uint(dl, "sb",
3446 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
3447 pr_out_uint(dl, "pool",
3448 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
3449 print_string(PRINT_ANY, "type", " type %s",
3450 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
3451 pr_out_uint(dl, "size",
3452 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
3453 print_string(PRINT_ANY, "thtype", " thtype %s",
3454 threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
3455 if (tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE])
3456 pr_out_uint(dl, "cell_size",
3457 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_CELL_SIZE]));
3458 pr_out_handle_end(dl);
3459 }
3460
3461 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
3462 {
3463 struct dl *dl = data;
3464 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3465 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3466
3467 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3468 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3469 !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
3470 !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
3471 !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
3472 return MNL_CB_ERROR;
3473 pr_out_sb_pool(dl, tb);
3474 return MNL_CB_OK;
3475 }
3476
3477 static int cmd_sb_pool_show(struct dl *dl)
3478 {
3479 struct nlmsghdr *nlh;
3480 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3481 int err;
3482
3483 if (dl_argc(dl) == 0)
3484 flags |= NLM_F_DUMP;
3485
3486 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
3487
3488 if (dl_argc(dl) > 0) {
3489 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
3490 DL_OPT_SB);
3491 if (err)
3492 return err;
3493 }
3494
3495 pr_out_section_start(dl, "pool");
3496 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
3497 pr_out_section_end(dl);
3498 return err;
3499 }
3500
3501 static int cmd_sb_pool_set(struct dl *dl)
3502 {
3503 struct nlmsghdr *nlh;
3504 int err;
3505
3506 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
3507 NLM_F_REQUEST | NLM_F_ACK);
3508
3509 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
3510 DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
3511 if (err)
3512 return err;
3513
3514 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3515 }
3516
3517 static int cmd_sb_pool(struct dl *dl)
3518 {
3519 if (dl_argv_match(dl, "help")) {
3520 cmd_sb_help();
3521 return 0;
3522 } else if (dl_argv_match(dl, "show") ||
3523 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3524 dl_arg_inc(dl);
3525 return cmd_sb_pool_show(dl);
3526 } else if (dl_argv_match(dl, "set")) {
3527 dl_arg_inc(dl);
3528 return cmd_sb_pool_set(dl);
3529 }
3530 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3531 return -ENOENT;
3532 }
3533
3534 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
3535 {
3536 pr_out_port_handle_start_arr(dl, tb, true);
3537 pr_out_uint(dl, "sb",
3538 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
3539 pr_out_uint(dl, "pool",
3540 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
3541 pr_out_uint(dl, "threshold",
3542 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
3543 pr_out_port_handle_end(dl);
3544 }
3545
3546 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
3547 {
3548 struct dl *dl = data;
3549 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3550 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3551
3552 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3553 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3554 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3555 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
3556 return MNL_CB_ERROR;
3557 pr_out_sb_port_pool(dl, tb);
3558 return MNL_CB_OK;
3559 }
3560
3561 static int cmd_sb_port_pool_show(struct dl *dl)
3562 {
3563 struct nlmsghdr *nlh;
3564 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3565 int err;
3566
3567 if (dl_argc(dl) == 0)
3568 flags |= NLM_F_DUMP;
3569
3570 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
3571
3572 if (dl_argc(dl) > 0) {
3573 err = dl_argv_parse_put(nlh, dl,
3574 DL_OPT_HANDLEP | DL_OPT_SB_POOL,
3575 DL_OPT_SB);
3576 if (err)
3577 return err;
3578 }
3579
3580 pr_out_section_start(dl, "port_pool");
3581 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
3582 pr_out_section_end(dl);
3583 return 0;
3584 }
3585
3586 static int cmd_sb_port_pool_set(struct dl *dl)
3587 {
3588 struct nlmsghdr *nlh;
3589 int err;
3590
3591 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
3592 NLM_F_REQUEST | NLM_F_ACK);
3593
3594 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
3595 DL_OPT_SB_TH, DL_OPT_SB);
3596 if (err)
3597 return err;
3598
3599 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3600 }
3601
3602 static int cmd_sb_port_pool(struct dl *dl)
3603 {
3604 if (dl_argv_match(dl, "help")) {
3605 cmd_sb_help();
3606 return 0;
3607 } else if (dl_argv_match(dl, "show") ||
3608 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3609 dl_arg_inc(dl);
3610 return cmd_sb_port_pool_show(dl);
3611 } else if (dl_argv_match(dl, "set")) {
3612 dl_arg_inc(dl);
3613 return cmd_sb_port_pool_set(dl);
3614 }
3615 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3616 return -ENOENT;
3617 }
3618
3619 static int cmd_sb_port(struct dl *dl)
3620 {
3621 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3622 cmd_sb_help();
3623 return 0;
3624 } else if (dl_argv_match(dl, "pool")) {
3625 dl_arg_inc(dl);
3626 return cmd_sb_port_pool(dl);
3627 }
3628 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3629 return -ENOENT;
3630 }
3631
3632 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
3633 {
3634 pr_out_port_handle_start_arr(dl, tb, true);
3635 pr_out_uint(dl, "sb",
3636 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
3637 pr_out_uint(dl, "tc",
3638 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
3639 print_string(PRINT_ANY, "type", " type %s",
3640 pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
3641 pr_out_uint(dl, "pool",
3642 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
3643 pr_out_uint(dl, "threshold",
3644 mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
3645 pr_out_port_handle_end(dl);
3646 }
3647
3648 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
3649 {
3650 struct dl *dl = data;
3651 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3652 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3653
3654 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3655 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3656 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3657 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
3658 !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
3659 return MNL_CB_ERROR;
3660 pr_out_sb_tc_bind(dl, tb);
3661 return MNL_CB_OK;
3662 }
3663
3664 static int cmd_sb_tc_bind_show(struct dl *dl)
3665 {
3666 struct nlmsghdr *nlh;
3667 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3668 int err;
3669
3670 if (dl_argc(dl) == 0)
3671 flags |= NLM_F_DUMP;
3672
3673 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
3674
3675 if (dl_argc(dl) > 0) {
3676 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
3677 DL_OPT_SB_TYPE, DL_OPT_SB);
3678 if (err)
3679 return err;
3680 }
3681
3682 pr_out_section_start(dl, "tc_bind");
3683 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
3684 pr_out_section_end(dl);
3685 return err;
3686 }
3687
3688 static int cmd_sb_tc_bind_set(struct dl *dl)
3689 {
3690 struct nlmsghdr *nlh;
3691 int err;
3692
3693 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
3694 NLM_F_REQUEST | NLM_F_ACK);
3695
3696 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
3697 DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
3698 DL_OPT_SB);
3699 if (err)
3700 return err;
3701
3702 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3703 }
3704
3705 static int cmd_sb_tc_bind(struct dl *dl)
3706 {
3707 if (dl_argv_match(dl, "help")) {
3708 cmd_sb_help();
3709 return 0;
3710 } else if (dl_argv_match(dl, "show") ||
3711 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
3712 dl_arg_inc(dl);
3713 return cmd_sb_tc_bind_show(dl);
3714 } else if (dl_argv_match(dl, "set")) {
3715 dl_arg_inc(dl);
3716 return cmd_sb_tc_bind_set(dl);
3717 }
3718 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3719 return -ENOENT;
3720 }
3721
3722 static int cmd_sb_tc(struct dl *dl)
3723 {
3724 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3725 cmd_sb_help();
3726 return 0;
3727 } else if (dl_argv_match(dl, "bind")) {
3728 dl_arg_inc(dl);
3729 return cmd_sb_tc_bind(dl);
3730 }
3731 pr_err("Command \"%s\" not found\n", dl_argv(dl));
3732 return -ENOENT;
3733 }
3734
3735 struct occ_item {
3736 struct list_head list;
3737 uint32_t index;
3738 uint32_t cur;
3739 uint32_t max;
3740 uint32_t bound_pool_index;
3741 };
3742
3743 struct occ_port {
3744 struct list_head list;
3745 char *bus_name;
3746 char *dev_name;
3747 uint32_t port_index;
3748 uint32_t sb_index;
3749 struct list_head pool_list;
3750 struct list_head ing_tc_list;
3751 struct list_head eg_tc_list;
3752 };
3753
3754 struct occ_show {
3755 struct dl *dl;
3756 int err;
3757 struct list_head port_list;
3758 };
3759
3760 static struct occ_item *occ_item_alloc(void)
3761 {
3762 return calloc(1, sizeof(struct occ_item));
3763 }
3764
3765 static void occ_item_free(struct occ_item *occ_item)
3766 {
3767 free(occ_item);
3768 }
3769
3770 static struct occ_port *occ_port_alloc(uint32_t port_index)
3771 {
3772 struct occ_port *occ_port;
3773
3774 occ_port = calloc(1, sizeof(*occ_port));
3775 if (!occ_port)
3776 return NULL;
3777 occ_port->port_index = port_index;
3778 INIT_LIST_HEAD(&occ_port->pool_list);
3779 INIT_LIST_HEAD(&occ_port->ing_tc_list);
3780 INIT_LIST_HEAD(&occ_port->eg_tc_list);
3781 return occ_port;
3782 }
3783
3784 static void occ_port_free(struct occ_port *occ_port)
3785 {
3786 struct occ_item *occ_item, *tmp;
3787
3788 list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
3789 occ_item_free(occ_item);
3790 list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
3791 occ_item_free(occ_item);
3792 list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
3793 occ_item_free(occ_item);
3794 }
3795
3796 static struct occ_show *occ_show_alloc(struct dl *dl)
3797 {
3798 struct occ_show *occ_show;
3799
3800 occ_show = calloc(1, sizeof(*occ_show));
3801 if (!occ_show)
3802 return NULL;
3803 occ_show->dl = dl;
3804 INIT_LIST_HEAD(&occ_show->port_list);
3805 return occ_show;
3806 }
3807
3808 static void occ_show_free(struct occ_show *occ_show)
3809 {
3810 struct occ_port *occ_port, *tmp;
3811
3812 list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
3813 occ_port_free(occ_port);
3814 }
3815
3816 static struct occ_port *occ_port_get(struct occ_show *occ_show,
3817 struct nlattr **tb)
3818 {
3819 struct occ_port *occ_port;
3820 uint32_t port_index;
3821
3822 port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
3823
3824 list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
3825 if (occ_port->port_index == port_index)
3826 return occ_port;
3827 }
3828 occ_port = occ_port_alloc(port_index);
3829 if (!occ_port)
3830 return NULL;
3831 list_add_tail(&occ_port->list, &occ_show->port_list);
3832 return occ_port;
3833 }
3834
3835 static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
3836 bool bound_pool)
3837 {
3838 struct occ_item *occ_item;
3839 int i = 1;
3840
3841 pr_out_sp(7, " %s:", label);
3842 list_for_each_entry(occ_item, list, list) {
3843 if ((i - 1) % 4 == 0 && i != 1)
3844 pr_out_sp(7, " ");
3845 if (bound_pool)
3846 pr_out_sp(7, "%2u(%u):", occ_item->index,
3847 occ_item->bound_pool_index);
3848 else
3849 pr_out_sp(7, "%2u:", occ_item->index);
3850 pr_out_sp(21, "%10u/%u", occ_item->cur, occ_item->max);
3851 if (i++ % 4 == 0)
3852 pr_out("\n");
3853 }
3854 if ((i - 1) % 4 != 0)
3855 pr_out("\n");
3856 }
3857
3858 static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
3859 struct list_head *list,
3860 bool bound_pool)
3861 {
3862 struct occ_item *occ_item;
3863 char buf[32];
3864
3865 open_json_object(label);
3866 list_for_each_entry(occ_item, list, list) {
3867 sprintf(buf, "%u", occ_item->index);
3868 open_json_object(buf);
3869 if (bound_pool)
3870 print_uint(PRINT_JSON, "bound_pool", NULL,
3871 occ_item->bound_pool_index);
3872 print_uint(PRINT_JSON, "current", NULL, occ_item->cur);
3873 print_uint(PRINT_JSON, "max", NULL, occ_item->max);
3874 close_json_object();
3875 }
3876 close_json_object();
3877 }
3878
3879 static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
3880 {
3881 if (dl->json_output) {
3882 pr_out_json_occ_show_item_list(dl, "pool",
3883 &occ_port->pool_list, false);
3884 pr_out_json_occ_show_item_list(dl, "itc",
3885 &occ_port->ing_tc_list, true);
3886 pr_out_json_occ_show_item_list(dl, "etc",
3887 &occ_port->eg_tc_list, true);
3888 } else {
3889 pr_out("\n");
3890 pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
3891 pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
3892 pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
3893 }
3894 }
3895
3896 static void pr_out_occ_show(struct occ_show *occ_show)
3897 {
3898 struct dl *dl = occ_show->dl;
3899 struct dl_opts *opts = &dl->opts;
3900 struct occ_port *occ_port;
3901
3902 list_for_each_entry(occ_port, &occ_show->port_list, list) {
3903 __pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
3904 occ_port->port_index, true, false);
3905 pr_out_occ_show_port(dl, occ_port);
3906 pr_out_port_handle_end(dl);
3907 }
3908 }
3909
3910 static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
3911 struct nlattr **tb)
3912 {
3913 struct occ_port *occ_port;
3914 struct occ_item *occ_item;
3915
3916 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
3917 return;
3918
3919 occ_port = occ_port_get(occ_show, tb);
3920 if (!occ_port) {
3921 occ_show->err = -ENOMEM;
3922 return;
3923 }
3924
3925 occ_item = occ_item_alloc();
3926 if (!occ_item) {
3927 occ_show->err = -ENOMEM;
3928 return;
3929 }
3930 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
3931 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
3932 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
3933 list_add_tail(&occ_item->list, &occ_port->pool_list);
3934 }
3935
3936 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
3937 {
3938 struct occ_show *occ_show = data;
3939 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3940 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3941
3942 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3943 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3944 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3945 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
3946 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
3947 return MNL_CB_ERROR;
3948 cmd_sb_occ_port_pool_process(occ_show, tb);
3949 return MNL_CB_OK;
3950 }
3951
3952 static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
3953 struct nlattr **tb)
3954 {
3955 struct occ_port *occ_port;
3956 struct occ_item *occ_item;
3957 uint8_t pool_type;
3958
3959 if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
3960 return;
3961
3962 occ_port = occ_port_get(occ_show, tb);
3963 if (!occ_port) {
3964 occ_show->err = -ENOMEM;
3965 return;
3966 }
3967
3968 occ_item = occ_item_alloc();
3969 if (!occ_item) {
3970 occ_show->err = -ENOMEM;
3971 return;
3972 }
3973 occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
3974 occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
3975 occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
3976 occ_item->bound_pool_index =
3977 mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
3978 pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
3979 if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
3980 list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
3981 else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
3982 list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
3983 else
3984 occ_item_free(occ_item);
3985 }
3986
3987 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
3988 {
3989 struct occ_show *occ_show = data;
3990 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3991 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3992
3993 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3994 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3995 !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
3996 !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
3997 !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
3998 !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
3999 return MNL_CB_ERROR;
4000 cmd_sb_occ_tc_pool_process(occ_show, tb);
4001 return MNL_CB_OK;
4002 }
4003
4004 static int cmd_sb_occ_show(struct dl *dl)
4005 {
4006 struct nlmsghdr *nlh;
4007 struct occ_show *occ_show;
4008 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
4009 int err;
4010
4011 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
4012 if (err)
4013 return err;
4014
4015 occ_show = occ_show_alloc(dl);
4016 if (!occ_show)
4017 return -ENOMEM;
4018
4019 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
4020
4021 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
4022 cmd_sb_occ_port_pool_process_cb, occ_show);
4023 if (err)
4024 goto out;
4025
4026 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
4027
4028 err = _mnlg_socket_sndrcv(dl->nlg, nlh,
4029 cmd_sb_occ_tc_pool_process_cb, occ_show);
4030 if (err)
4031 goto out;
4032
4033 pr_out_section_start(dl, "occupancy");
4034 pr_out_occ_show(occ_show);
4035 pr_out_section_end(dl);
4036
4037 out:
4038 occ_show_free(occ_show);
4039 return err;
4040 }
4041
4042 static int cmd_sb_occ_snapshot(struct dl *dl)
4043 {
4044 struct nlmsghdr *nlh;
4045 int err;
4046
4047 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
4048 NLM_F_REQUEST | NLM_F_ACK);
4049
4050 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4051 if (err)
4052 return err;
4053
4054 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4055 }
4056
4057 static int cmd_sb_occ_clearmax(struct dl *dl)
4058 {
4059 struct nlmsghdr *nlh;
4060 int err;
4061
4062 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
4063 NLM_F_REQUEST | NLM_F_ACK);
4064
4065 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
4066 if (err)
4067 return err;
4068
4069 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
4070 }
4071
4072 static int cmd_sb_occ(struct dl *dl)
4073 {
4074 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4075 cmd_sb_help();
4076 return 0;
4077 } else if (dl_argv_match(dl, "show") ||
4078 dl_argv_match(dl, "list")) {
4079 dl_arg_inc(dl);
4080 return cmd_sb_occ_show(dl);
4081 } else if (dl_argv_match(dl, "snapshot")) {
4082 dl_arg_inc(dl);
4083 return cmd_sb_occ_snapshot(dl);
4084 } else if (dl_argv_match(dl, "clearmax")) {
4085 dl_arg_inc(dl);
4086 return cmd_sb_occ_clearmax(dl);
4087 }
4088 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4089 return -ENOENT;
4090 }
4091
4092 static int cmd_sb(struct dl *dl)
4093 {
4094 if (dl_argv_match(dl, "help")) {
4095 cmd_sb_help();
4096 return 0;
4097 } else if (dl_argv_match(dl, "show") ||
4098 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
4099 dl_arg_inc(dl);
4100 return cmd_sb_show(dl);
4101 } else if (dl_argv_match(dl, "pool")) {
4102 dl_arg_inc(dl);
4103 return cmd_sb_pool(dl);
4104 } else if (dl_argv_match(dl, "port")) {
4105 dl_arg_inc(dl);
4106 return cmd_sb_port(dl);
4107 } else if (dl_argv_match(dl, "tc")) {
4108 dl_arg_inc(dl);
4109 return cmd_sb_tc(dl);
4110 } else if (dl_argv_match(dl, "occupancy")) {
4111 dl_arg_inc(dl);
4112 return cmd_sb_occ(dl);
4113 }
4114 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4115 return -ENOENT;
4116 }
4117
4118 static const char *cmd_name(uint8_t cmd)
4119 {
4120 switch (cmd) {
4121 case DEVLINK_CMD_UNSPEC: return "unspec";
4122 case DEVLINK_CMD_GET: return "get";
4123 case DEVLINK_CMD_SET: return "set";
4124 case DEVLINK_CMD_NEW: return "new";
4125 case DEVLINK_CMD_DEL: return "del";
4126 case DEVLINK_CMD_PORT_GET: return "get";
4127 case DEVLINK_CMD_PORT_SET: return "set";
4128 case DEVLINK_CMD_PORT_NEW: return "new";
4129 case DEVLINK_CMD_PORT_DEL: return "del";
4130 case DEVLINK_CMD_PARAM_GET: return "get";
4131 case DEVLINK_CMD_PARAM_SET: return "set";
4132 case DEVLINK_CMD_PARAM_NEW: return "new";
4133 case DEVLINK_CMD_PARAM_DEL: return "del";
4134 case DEVLINK_CMD_REGION_GET: return "get";
4135 case DEVLINK_CMD_REGION_SET: return "set";
4136 case DEVLINK_CMD_REGION_NEW: return "new";
4137 case DEVLINK_CMD_REGION_DEL: return "del";
4138 case DEVLINK_CMD_FLASH_UPDATE: return "begin";
4139 case DEVLINK_CMD_FLASH_UPDATE_END: return "end";
4140 case DEVLINK_CMD_FLASH_UPDATE_STATUS: return "status";
4141 case DEVLINK_CMD_TRAP_GET: return "get";
4142 case DEVLINK_CMD_TRAP_SET: return "set";
4143 case DEVLINK_CMD_TRAP_NEW: return "new";
4144 case DEVLINK_CMD_TRAP_DEL: return "del";
4145 case DEVLINK_CMD_TRAP_GROUP_GET: return "get";
4146 case DEVLINK_CMD_TRAP_GROUP_SET: return "set";
4147 case DEVLINK_CMD_TRAP_GROUP_NEW: return "new";
4148 case DEVLINK_CMD_TRAP_GROUP_DEL: return "del";
4149 default: return "<unknown cmd>";
4150 }
4151 }
4152
4153 static const char *cmd_obj(uint8_t cmd)
4154 {
4155 switch (cmd) {
4156 case DEVLINK_CMD_UNSPEC: return "unspec";
4157 case DEVLINK_CMD_GET:
4158 case DEVLINK_CMD_SET:
4159 case DEVLINK_CMD_NEW:
4160 case DEVLINK_CMD_DEL:
4161 return "dev";
4162 case DEVLINK_CMD_PORT_GET:
4163 case DEVLINK_CMD_PORT_SET:
4164 case DEVLINK_CMD_PORT_NEW:
4165 case DEVLINK_CMD_PORT_DEL:
4166 return "port";
4167 case DEVLINK_CMD_PARAM_GET:
4168 case DEVLINK_CMD_PARAM_SET:
4169 case DEVLINK_CMD_PARAM_NEW:
4170 case DEVLINK_CMD_PARAM_DEL:
4171 return "param";
4172 case DEVLINK_CMD_REGION_GET:
4173 case DEVLINK_CMD_REGION_SET:
4174 case DEVLINK_CMD_REGION_NEW:
4175 case DEVLINK_CMD_REGION_DEL:
4176 return "region";
4177 case DEVLINK_CMD_FLASH_UPDATE:
4178 case DEVLINK_CMD_FLASH_UPDATE_END:
4179 case DEVLINK_CMD_FLASH_UPDATE_STATUS:
4180 return "flash";
4181 case DEVLINK_CMD_TRAP_GET:
4182 case DEVLINK_CMD_TRAP_SET:
4183 case DEVLINK_CMD_TRAP_NEW:
4184 case DEVLINK_CMD_TRAP_DEL:
4185 return "trap";
4186 case DEVLINK_CMD_TRAP_GROUP_GET:
4187 case DEVLINK_CMD_TRAP_GROUP_SET:
4188 case DEVLINK_CMD_TRAP_GROUP_NEW:
4189 case DEVLINK_CMD_TRAP_GROUP_DEL:
4190 return "trap-group";
4191 default: return "<unknown obj>";
4192 }
4193 }
4194
4195 static void pr_out_mon_header(uint8_t cmd)
4196 {
4197 pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
4198 }
4199
4200 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
4201 {
4202 const char *obj = cmd_obj(cmd);
4203 unsigned int index = 0;
4204 const char *cur_obj;
4205
4206 if (dl_no_arg(dl))
4207 return true;
4208 while ((cur_obj = dl_argv_index(dl, index++))) {
4209 if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
4210 return true;
4211 }
4212 return false;
4213 }
4214
4215 static void pr_out_flash_update(struct dl *dl, struct nlattr **tb)
4216 {
4217 __pr_out_handle_start(dl, tb, true, false);
4218
4219 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]) {
4220 check_indent_newline(dl);
4221 print_string(PRINT_ANY, "msg", "msg %s",
4222 mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_MSG]));
4223 }
4224 if (tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]) {
4225 check_indent_newline(dl);
4226 print_string(PRINT_ANY, "component", "component %s",
4227 mnl_attr_get_str(tb[DEVLINK_ATTR_FLASH_UPDATE_COMPONENT]));
4228 }
4229
4230 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE])
4231 pr_out_u64(dl, "done",
4232 mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_DONE]));
4233
4234 if (tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL])
4235 pr_out_u64(dl, "total",
4236 mnl_attr_get_u64(tb[DEVLINK_ATTR_FLASH_UPDATE_STATUS_TOTAL]));
4237
4238 pr_out_handle_end(dl);
4239 }
4240
4241 static void pr_out_region(struct dl *dl, struct nlattr **tb);
4242 static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array);
4243 static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array);
4244
4245 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
4246 {
4247 struct dl *dl = data;
4248 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4249 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4250 uint8_t cmd = genl->cmd;
4251
4252 if (!cmd_filter_check(dl, cmd))
4253 return MNL_CB_OK;
4254
4255 switch (cmd) {
4256 case DEVLINK_CMD_GET: /* fall through */
4257 case DEVLINK_CMD_SET: /* fall through */
4258 case DEVLINK_CMD_NEW: /* fall through */
4259 case DEVLINK_CMD_DEL:
4260 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4261 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
4262 return MNL_CB_ERROR;
4263 pr_out_mon_header(genl->cmd);
4264 pr_out_handle(dl, tb);
4265 break;
4266 case DEVLINK_CMD_PORT_GET: /* fall through */
4267 case DEVLINK_CMD_PORT_SET: /* fall through */
4268 case DEVLINK_CMD_PORT_NEW: /* fall through */
4269 case DEVLINK_CMD_PORT_DEL:
4270 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4271 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4272 !tb[DEVLINK_ATTR_PORT_INDEX])
4273 return MNL_CB_ERROR;
4274 pr_out_mon_header(genl->cmd);
4275 pr_out_port(dl, tb);
4276 break;
4277 case DEVLINK_CMD_PARAM_GET: /* fall through */
4278 case DEVLINK_CMD_PARAM_SET: /* fall through */
4279 case DEVLINK_CMD_PARAM_NEW: /* fall through */
4280 case DEVLINK_CMD_PARAM_DEL:
4281 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4282 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4283 !tb[DEVLINK_ATTR_PARAM])
4284 return MNL_CB_ERROR;
4285 pr_out_mon_header(genl->cmd);
4286 pr_out_param(dl, tb, false);
4287 break;
4288 case DEVLINK_CMD_REGION_GET: /* fall through */
4289 case DEVLINK_CMD_REGION_SET: /* fall through */
4290 case DEVLINK_CMD_REGION_NEW: /* fall through */
4291 case DEVLINK_CMD_REGION_DEL:
4292 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4293 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4294 !tb[DEVLINK_ATTR_REGION_NAME])
4295 return MNL_CB_ERROR;
4296 pr_out_mon_header(genl->cmd);
4297 pr_out_region(dl, tb);
4298 break;
4299 case DEVLINK_CMD_FLASH_UPDATE: /* fall through */
4300 case DEVLINK_CMD_FLASH_UPDATE_END: /* fall through */
4301 case DEVLINK_CMD_FLASH_UPDATE_STATUS:
4302 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4303 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
4304 return MNL_CB_ERROR;
4305 pr_out_mon_header(genl->cmd);
4306 pr_out_flash_update(dl, tb);
4307 break;
4308 case DEVLINK_CMD_TRAP_GET: /* fall through */
4309 case DEVLINK_CMD_TRAP_SET: /* fall through */
4310 case DEVLINK_CMD_TRAP_NEW: /* fall through */
4311 case DEVLINK_CMD_TRAP_DEL:
4312 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4313 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4314 !tb[DEVLINK_ATTR_TRAP_NAME] ||
4315 !tb[DEVLINK_ATTR_TRAP_TYPE] ||
4316 !tb[DEVLINK_ATTR_TRAP_ACTION] ||
4317 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
4318 !tb[DEVLINK_ATTR_TRAP_METADATA] ||
4319 !tb[DEVLINK_ATTR_STATS])
4320 return MNL_CB_ERROR;
4321 pr_out_mon_header(genl->cmd);
4322 pr_out_trap(dl, tb, false);
4323 break;
4324 case DEVLINK_CMD_TRAP_GROUP_GET: /* fall through */
4325 case DEVLINK_CMD_TRAP_GROUP_SET: /* fall through */
4326 case DEVLINK_CMD_TRAP_GROUP_NEW: /* fall through */
4327 case DEVLINK_CMD_TRAP_GROUP_DEL:
4328 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4329 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4330 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
4331 !tb[DEVLINK_ATTR_STATS])
4332 return MNL_CB_ERROR;
4333 pr_out_mon_header(genl->cmd);
4334 pr_out_trap_group(dl, tb, false);
4335 break;
4336 }
4337 return MNL_CB_OK;
4338 }
4339
4340 static int cmd_mon_show(struct dl *dl)
4341 {
4342 int err;
4343 unsigned int index = 0;
4344 const char *cur_obj;
4345
4346 while ((cur_obj = dl_argv_index(dl, index++))) {
4347 if (strcmp(cur_obj, "all") != 0 &&
4348 strcmp(cur_obj, "dev") != 0 &&
4349 strcmp(cur_obj, "port") != 0 &&
4350 strcmp(cur_obj, "trap") != 0 &&
4351 strcmp(cur_obj, "trap-group") != 0) {
4352 pr_err("Unknown object \"%s\"\n", cur_obj);
4353 return -EINVAL;
4354 }
4355 }
4356 err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
4357 if (err)
4358 return err;
4359 err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
4360 if (err)
4361 return err;
4362 return 0;
4363 }
4364
4365 static void cmd_mon_help(void)
4366 {
4367 pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
4368 "where OBJECT-LIST := { dev | port | trap | trap-group }\n");
4369 }
4370
4371 static int cmd_mon(struct dl *dl)
4372 {
4373 if (dl_argv_match(dl, "help")) {
4374 cmd_mon_help();
4375 return 0;
4376 }
4377 return cmd_mon_show(dl);
4378 }
4379
4380 struct dpipe_field {
4381 char *name;
4382 unsigned int id;
4383 unsigned int bitwidth;
4384 enum devlink_dpipe_field_mapping_type mapping_type;
4385 };
4386
4387 struct dpipe_header {
4388 struct list_head list;
4389 char *name;
4390 unsigned int id;
4391 struct dpipe_field *fields;
4392 unsigned int fields_count;
4393 };
4394
4395 struct dpipe_table {
4396 struct list_head list;
4397 char *name;
4398 unsigned int resource_id;
4399 bool resource_valid;
4400 };
4401
4402 struct dpipe_tables {
4403 struct list_head table_list;
4404 };
4405
4406 struct resource {
4407 char *name;
4408 uint64_t size;
4409 uint64_t size_new;
4410 uint64_t size_min;
4411 uint64_t size_max;
4412 uint64_t size_gran;
4413 enum devlink_resource_unit unit;
4414 bool size_valid;
4415 uint64_t size_occ;
4416 bool occ_valid;
4417 uint64_t id;
4418 struct list_head list;
4419 struct list_head resource_list;
4420 struct resource *parent;
4421 };
4422
4423 struct resources {
4424 struct list_head resource_list;
4425 };
4426
4427 struct resource_ctx {
4428 struct dl *dl;
4429 int err;
4430 struct resources *resources;
4431 struct dpipe_tables *tables;
4432 bool print_resources;
4433 bool pending_change;
4434 };
4435
4436 static struct resource *resource_alloc(void)
4437 {
4438 struct resource *resource;
4439
4440 resource = calloc(1, sizeof(struct resource));
4441 if (!resource)
4442 return NULL;
4443 INIT_LIST_HEAD(&resource->resource_list);
4444 return resource;
4445 }
4446
4447 static void resource_free(struct resource *resource)
4448 {
4449 struct resource *child_resource, *tmp;
4450
4451 list_for_each_entry_safe(child_resource, tmp, &resource->resource_list,
4452 list) {
4453 free(child_resource->name);
4454 resource_free(child_resource);
4455 }
4456 free(resource);
4457 }
4458
4459 static struct resources *resources_alloc(void)
4460 {
4461 struct resources *resources;
4462
4463 resources = calloc(1, sizeof(struct resources));
4464 if (!resources)
4465 return NULL;
4466 INIT_LIST_HEAD(&resources->resource_list);
4467 return resources;
4468 }
4469
4470 static void resources_free(struct resources *resources)
4471 {
4472 struct resource *resource, *tmp;
4473
4474 list_for_each_entry_safe(resource, tmp, &resources->resource_list, list)
4475 resource_free(resource);
4476 }
4477
4478 static int resource_ctx_init(struct resource_ctx *ctx, struct dl *dl)
4479 {
4480 ctx->resources = resources_alloc();
4481 if (!ctx->resources)
4482 return -ENOMEM;
4483 ctx->dl = dl;
4484 return 0;
4485 }
4486
4487 static void resource_ctx_fini(struct resource_ctx *ctx)
4488 {
4489 resources_free(ctx->resources);
4490 }
4491
4492 struct dpipe_ctx {
4493 struct dl *dl;
4494 int err;
4495 struct list_head global_headers;
4496 struct list_head local_headers;
4497 struct dpipe_tables *tables;
4498 struct resources *resources;
4499 bool print_headers;
4500 bool print_tables;
4501 };
4502
4503 static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
4504 {
4505 struct dpipe_header *header;
4506
4507 header = calloc(1, sizeof(struct dpipe_header));
4508 if (!header)
4509 return NULL;
4510 header->fields = calloc(fields_count, sizeof(struct dpipe_field));
4511 if (!header->fields)
4512 goto err_fields_alloc;
4513 header->fields_count = fields_count;
4514 return header;
4515
4516 err_fields_alloc:
4517 free(header);
4518 return NULL;
4519 }
4520
4521 static void dpipe_header_free(struct dpipe_header *header)
4522 {
4523 free(header->fields);
4524 free(header);
4525 }
4526
4527 static void dpipe_header_clear(struct dpipe_header *header)
4528 {
4529 struct dpipe_field *field;
4530 int i;
4531
4532 for (i = 0; i < header->fields_count; i++) {
4533 field = &header->fields[i];
4534 free(field->name);
4535 }
4536 free(header->name);
4537 }
4538
4539 static void dpipe_header_add(struct dpipe_ctx *ctx,
4540 struct dpipe_header *header, bool global)
4541 {
4542 if (global)
4543 list_add(&header->list, &ctx->global_headers);
4544 else
4545 list_add(&header->list, &ctx->local_headers);
4546 }
4547
4548 static void dpipe_header_del(struct dpipe_header *header)
4549 {
4550 list_del(&header->list);
4551 }
4552
4553 static struct dpipe_table *dpipe_table_alloc(void)
4554 {
4555 return calloc(1, sizeof(struct dpipe_table));
4556 }
4557
4558 static void dpipe_table_free(struct dpipe_table *table)
4559 {
4560 free(table);
4561 }
4562
4563 static struct dpipe_tables *dpipe_tables_alloc(void)
4564 {
4565 struct dpipe_tables *tables;
4566
4567 tables = calloc(1, sizeof(struct dpipe_tables));
4568 if (!tables)
4569 return NULL;
4570 INIT_LIST_HEAD(&tables->table_list);
4571 return tables;
4572 }
4573
4574 static void dpipe_tables_free(struct dpipe_tables *tables)
4575 {
4576 struct dpipe_table *table, *tmp;
4577
4578 list_for_each_entry_safe(table, tmp, &tables->table_list, list)
4579 dpipe_table_free(table);
4580 free(tables);
4581 }
4582
4583 static int dpipe_ctx_init(struct dpipe_ctx *ctx, struct dl *dl)
4584 {
4585 ctx->tables = dpipe_tables_alloc();
4586 if (!ctx->tables)
4587 return -ENOMEM;
4588
4589 ctx->dl = dl;
4590 INIT_LIST_HEAD(&ctx->global_headers);
4591 INIT_LIST_HEAD(&ctx->local_headers);
4592 return 0;
4593 }
4594
4595 static void dpipe_ctx_fini(struct dpipe_ctx *ctx)
4596 {
4597 struct dpipe_header *header, *tmp;
4598
4599 list_for_each_entry_safe(header, tmp, &ctx->global_headers,
4600 list) {
4601 dpipe_header_del(header);
4602 dpipe_header_clear(header);
4603 dpipe_header_free(header);
4604 }
4605 list_for_each_entry_safe(header, tmp, &ctx->local_headers,
4606 list) {
4607 dpipe_header_del(header);
4608 dpipe_header_clear(header);
4609 dpipe_header_free(header);
4610 }
4611 dpipe_tables_free(ctx->tables);
4612 }
4613
4614 static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
4615 uint32_t header_id, bool global)
4616 {
4617 struct list_head *header_list;
4618 struct dpipe_header *header;
4619
4620 if (global)
4621 header_list = &ctx->global_headers;
4622 else
4623 header_list = &ctx->local_headers;
4624 list_for_each_entry(header, header_list, list) {
4625 if (header->id != header_id)
4626 continue;
4627 return header->name;
4628 }
4629 return NULL;
4630 }
4631
4632 static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
4633 uint32_t header_id,
4634 uint32_t field_id, bool global)
4635 {
4636 struct list_head *header_list;
4637 struct dpipe_header *header;
4638
4639 if (global)
4640 header_list = &ctx->global_headers;
4641 else
4642 header_list = &ctx->local_headers;
4643 list_for_each_entry(header, header_list, list) {
4644 if (header->id != header_id)
4645 continue;
4646 return header->fields[field_id].name;
4647 }
4648 return NULL;
4649 }
4650
4651 static const char *
4652 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
4653 {
4654 switch (mapping_type) {
4655 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
4656 return NULL;
4657 case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
4658 return "ifindex";
4659 default:
4660 return "<unknown>";
4661 }
4662 }
4663
4664 static const char *
4665 dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
4666 uint32_t field_id, bool global)
4667 {
4668 enum devlink_dpipe_field_mapping_type mapping_type;
4669 struct list_head *header_list;
4670 struct dpipe_header *header;
4671
4672 if (global)
4673 header_list = &ctx->global_headers;
4674 else
4675 header_list = &ctx->local_headers;
4676 list_for_each_entry(header, header_list, list) {
4677 if (header->id != header_id)
4678 continue;
4679 mapping_type = header->fields[field_id].mapping_type;
4680 return dpipe_field_mapping_e2s(mapping_type);
4681 }
4682 return NULL;
4683 }
4684
4685 static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
4686 struct dpipe_field *fields,
4687 unsigned int field_count)
4688 {
4689 struct dpipe_field *field;
4690 int i;
4691
4692 for (i = 0; i < field_count; i++) {
4693 field = &fields[i];
4694 pr_out_entry_start(ctx->dl);
4695 check_indent_newline(ctx->dl);
4696 print_string(PRINT_ANY, "name", "name %s", field->name);
4697 if (ctx->dl->verbose)
4698 pr_out_uint(ctx->dl, "id", field->id);
4699 pr_out_uint(ctx->dl, "bitwidth", field->bitwidth);
4700 if (field->mapping_type) {
4701 print_string(PRINT_ANY, "mapping_type", " mapping_type %s",
4702 dpipe_field_mapping_e2s(field->mapping_type));
4703 }
4704 pr_out_entry_end(ctx->dl);
4705 }
4706 }
4707
4708 static void
4709 pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
4710 struct dpipe_header *header, bool global)
4711 {
4712 pr_out_handle_start_arr(ctx->dl, tb);
4713 check_indent_newline(ctx->dl);
4714 print_string(PRINT_ANY, "name", "name %s", header->name);
4715 if (ctx->dl->verbose) {
4716 pr_out_uint(ctx->dl, "id", header->id);
4717 print_bool(PRINT_ANY, "global", " global %s", global);
4718 }
4719 pr_out_array_start(ctx->dl, "field");
4720 pr_out_dpipe_fields(ctx, header->fields,
4721 header->fields_count);
4722 pr_out_array_end(ctx->dl);
4723 pr_out_handle_end(ctx->dl);
4724 }
4725
4726 static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
4727 struct nlattr **tb)
4728 {
4729 struct dpipe_header *header;
4730
4731 list_for_each_entry(header, &ctx->local_headers, list)
4732 pr_out_dpipe_header(ctx, tb, header, false);
4733
4734 list_for_each_entry(header, &ctx->global_headers, list)
4735 pr_out_dpipe_header(ctx, tb, header, true);
4736 }
4737
4738 static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
4739 {
4740 struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
4741 const char *name;
4742 int err;
4743
4744 err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
4745 if (err != MNL_CB_OK)
4746 return -EINVAL;
4747 if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
4748 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
4749 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
4750 !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
4751 return -EINVAL;
4752
4753 name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
4754 field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
4755 field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
4756 field->name = strdup(name);
4757 if (!field->name)
4758 return -ENOMEM;
4759 field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
4760 return 0;
4761 }
4762
4763 static int dpipe_header_fields_get(struct nlattr *nla_fields,
4764 struct dpipe_field *fields)
4765 {
4766 struct nlattr *nla_field;
4767 int count = 0;
4768 int err;
4769
4770 mnl_attr_for_each_nested(nla_field, nla_fields) {
4771 err = dpipe_header_field_get(nla_field, &fields[count]);
4772 if (err)
4773 return err;
4774 count++;
4775 }
4776 return 0;
4777 }
4778
4779 static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
4780 {
4781 struct nlattr *nla_field;
4782 unsigned int count = 0;
4783
4784 mnl_attr_for_each_nested(nla_field, nla_fields)
4785 count++;
4786 return count;
4787 }
4788
4789 static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
4790 {
4791 struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
4792 struct dpipe_header *header;
4793 unsigned int fields_count;
4794 const char *header_name;
4795 bool global;
4796 int err;
4797
4798 err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
4799 if (err != MNL_CB_OK)
4800 return -EINVAL;
4801
4802 if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
4803 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
4804 !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
4805 return -EINVAL;
4806
4807 fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
4808 header = dpipe_header_alloc(fields_count);
4809 if (!header)
4810 return -ENOMEM;
4811
4812 header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
4813 header->name = strdup(header_name);
4814 header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
4815 header->fields_count = fields_count;
4816 global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
4817
4818 err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
4819 header->fields);
4820 if (err)
4821 goto err_field_get;
4822 dpipe_header_add(ctx, header, global);
4823 return 0;
4824
4825 err_field_get:
4826 dpipe_header_free(header);
4827 return err;
4828 }
4829
4830 static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
4831 {
4832 struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
4833 struct nlattr *nla_header;
4834 int err;
4835
4836 mnl_attr_for_each_nested(nla_header, nla_headers) {
4837 err = dpipe_header_get(ctx, nla_header);
4838 if (err)
4839 return err;
4840 }
4841 return 0;
4842 }
4843
4844 static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
4845 {
4846 struct dpipe_ctx *ctx = data;
4847 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
4848 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
4849 int err;
4850
4851 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
4852 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
4853 !tb[DEVLINK_ATTR_DPIPE_HEADERS])
4854 return MNL_CB_ERROR;
4855 err = dpipe_headers_get(ctx, tb);
4856 if (err) {
4857 ctx->err = err;
4858 return MNL_CB_ERROR;
4859 }
4860
4861 if (ctx->print_headers)
4862 pr_out_dpipe_headers(ctx, tb);
4863 return MNL_CB_OK;
4864 }
4865
4866 static int cmd_dpipe_headers_show(struct dl *dl)
4867 {
4868 struct nlmsghdr *nlh;
4869 struct dpipe_ctx ctx = {};
4870 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
4871 int err;
4872
4873 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
4874
4875 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
4876 if (err)
4877 return err;
4878
4879 err = dpipe_ctx_init(&ctx, dl);
4880 if (err)
4881 return err;
4882
4883 ctx.print_headers = true;
4884
4885 pr_out_section_start(dl, "header");
4886 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
4887 if (err)
4888 pr_err("error get headers %s\n", strerror(ctx.err));
4889 pr_out_section_end(dl);
4890
4891 dpipe_ctx_fini(&ctx);
4892 return err;
4893 }
4894
4895 static void cmd_dpipe_header_help(void)
4896 {
4897 pr_err("Usage: devlink dpipe headers show DEV\n");
4898 }
4899
4900 static int cmd_dpipe_header(struct dl *dl)
4901 {
4902 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
4903 cmd_dpipe_header_help();
4904 return 0;
4905 } else if (dl_argv_match(dl, "show")) {
4906 dl_arg_inc(dl);
4907 return cmd_dpipe_headers_show(dl);
4908 }
4909 pr_err("Command \"%s\" not found\n", dl_argv(dl));
4910 return -ENOENT;
4911 }
4912
4913 static const char
4914 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
4915 {
4916 switch (action_type) {
4917 case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
4918 return "field_modify";
4919 default:
4920 return "<unknown>";
4921 }
4922 }
4923
4924 struct dpipe_op_info {
4925 uint32_t header_id;
4926 uint32_t field_id;
4927 bool header_global;
4928 };
4929
4930 struct dpipe_action {
4931 struct dpipe_op_info info;
4932 uint32_t type;
4933 };
4934
4935 static void pr_out_dpipe_action(struct dpipe_action *action,
4936 struct dpipe_ctx *ctx)
4937 {
4938 struct dpipe_op_info *op_info = &action->info;
4939 const char *mapping;
4940
4941 check_indent_newline(ctx->dl);
4942 print_string(PRINT_ANY, "type", "type %s",
4943 dpipe_action_type_e2s(action->type));
4944 print_string(PRINT_ANY, "header", " header %s",
4945 dpipe_header_id2s(ctx, op_info->header_id,
4946 op_info->header_global));
4947 print_string(PRINT_ANY, "field", " field %s",
4948 dpipe_field_id2s(ctx, op_info->header_id,
4949 op_info->field_id,
4950 op_info->header_global));
4951 mapping = dpipe_mapping_get(ctx, op_info->header_id,
4952 op_info->field_id,
4953 op_info->header_global);
4954 if (mapping)
4955 print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
4956 }
4957
4958 static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
4959 {
4960 struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
4961 int err;
4962
4963 err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
4964 if (err != MNL_CB_OK)
4965 return -EINVAL;
4966
4967 if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
4968 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
4969 !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
4970 !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
4971 return -EINVAL;
4972 }
4973
4974 action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
4975 action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
4976 action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
4977 action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
4978
4979 return 0;
4980 }
4981
4982 static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
4983 struct nlattr *nla_actions)
4984 {
4985 struct nlattr *nla_action;
4986 struct dpipe_action action;
4987
4988 mnl_attr_for_each_nested(nla_action, nla_actions) {
4989 pr_out_entry_start(ctx->dl);
4990 if (dpipe_action_parse(&action, nla_action))
4991 goto err_action_parse;
4992 pr_out_dpipe_action(&action, ctx);
4993 pr_out_entry_end(ctx->dl);
4994 }
4995 return 0;
4996
4997 err_action_parse:
4998 pr_out_entry_end(ctx->dl);
4999 return -EINVAL;
5000 }
5001
5002 static const char *
5003 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
5004 {
5005 switch (match_type) {
5006 case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
5007 return "field_exact";
5008 default:
5009 return "<unknown>";
5010 }
5011 }
5012
5013 struct dpipe_match {
5014 struct dpipe_op_info info;
5015 uint32_t type;
5016 };
5017
5018 static void pr_out_dpipe_match(struct dpipe_match *match,
5019 struct dpipe_ctx *ctx)
5020 {
5021 struct dpipe_op_info *op_info = &match->info;
5022 const char *mapping;
5023
5024 check_indent_newline(ctx->dl);
5025 print_string(PRINT_ANY, "type", "type %s",
5026 dpipe_match_type_e2s(match->type));
5027 print_string(PRINT_ANY, "header", " header %s",
5028 dpipe_header_id2s(ctx, op_info->header_id,
5029 op_info->header_global));
5030 print_string(PRINT_ANY, "field", " field %s",
5031 dpipe_field_id2s(ctx, op_info->header_id,
5032 op_info->field_id,
5033 op_info->header_global));
5034 mapping = dpipe_mapping_get(ctx, op_info->header_id,
5035 op_info->field_id,
5036 op_info->header_global);
5037 if (mapping)
5038 print_string(PRINT_ANY, "mapping", " mapping %s", mapping);
5039 }
5040
5041 static int dpipe_match_parse(struct dpipe_match *match,
5042 struct nlattr *nl)
5043
5044 {
5045 struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
5046 int err;
5047
5048 err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
5049 if (err != MNL_CB_OK)
5050 return -EINVAL;
5051
5052 if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
5053 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
5054 !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
5055 !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
5056 return -EINVAL;
5057 }
5058
5059 match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
5060 match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
5061 match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
5062 match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
5063
5064 return 0;
5065 }
5066
5067 static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
5068 struct nlattr *nla_matches)
5069 {
5070 struct nlattr *nla_match;
5071 struct dpipe_match match;
5072
5073 mnl_attr_for_each_nested(nla_match, nla_matches) {
5074 pr_out_entry_start(ctx->dl);
5075 if (dpipe_match_parse(&match, nla_match))
5076 goto err_match_parse;
5077 pr_out_dpipe_match(&match, ctx);
5078 pr_out_entry_end(ctx->dl);
5079 }
5080 return 0;
5081
5082 err_match_parse:
5083 pr_out_entry_end(ctx->dl);
5084 return -EINVAL;
5085 }
5086
5087 static struct resource *
5088 resource_find(struct resources *resources, struct resource *resource,
5089 uint64_t resource_id)
5090 {
5091 struct list_head *list_head;
5092
5093 if (!resource)
5094 list_head = &resources->resource_list;
5095 else
5096 list_head = &resource->resource_list;
5097
5098 list_for_each_entry(resource, list_head, list) {
5099 struct resource *child_resource;
5100
5101 if (resource->id == resource_id)
5102 return resource;
5103
5104 child_resource = resource_find(resources, resource,
5105 resource_id);
5106 if (child_resource)
5107 return child_resource;
5108 }
5109 return NULL;
5110 }
5111
5112 static void
5113 resource_path_print(struct dl *dl, struct resources *resources,
5114 uint64_t resource_id)
5115 {
5116 struct resource *resource, *parent_resource;
5117 const char del[] = "/";
5118 int path_len = 0;
5119 char *path;
5120
5121 resource = resource_find(resources, NULL, resource_id);
5122 if (!resource)
5123 return;
5124
5125 for (parent_resource = resource; parent_resource;
5126 parent_resource = parent_resource->parent)
5127 path_len += strlen(parent_resource->name) + 1;
5128
5129 path_len++;
5130 path = calloc(1, path_len);
5131 if (!path)
5132 return;
5133
5134 path += path_len - 1;
5135 for (parent_resource = resource; parent_resource;
5136 parent_resource = parent_resource->parent) {
5137 path -= strlen(parent_resource->name);
5138 memcpy(path, parent_resource->name,
5139 strlen(parent_resource->name));
5140 path -= strlen(del);
5141 memcpy(path, del, strlen(del));
5142 }
5143 check_indent_newline(dl);
5144 print_string(PRINT_ANY, "resource_path", "resource_path %s", path);
5145 free(path);
5146 }
5147
5148 static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
5149 {
5150 struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
5151 struct dpipe_table *table;
5152 uint32_t resource_units;
5153 bool counters_enabled;
5154 bool resource_valid;
5155 uint32_t size;
5156 int err;
5157
5158 err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
5159 if (err != MNL_CB_OK)
5160 return -EINVAL;
5161
5162 if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
5163 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
5164 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
5165 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
5166 !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
5167 return -EINVAL;
5168 }
5169
5170 table = dpipe_table_alloc();
5171 if (!table)
5172 return -ENOMEM;
5173
5174 table->name = strdup(mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]));
5175 size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
5176 counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
5177
5178 resource_valid = nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID] &&
5179 ctx->resources;
5180 if (resource_valid) {
5181 table->resource_id = mnl_attr_get_u64(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_ID]);
5182 table->resource_valid = true;
5183 }
5184
5185 list_add_tail(&table->list, &ctx->tables->table_list);
5186 if (!ctx->print_tables)
5187 return 0;
5188
5189 check_indent_newline(ctx->dl);
5190 print_string(PRINT_ANY, "name", "name %s", table->name);
5191 pr_out_uint(ctx->dl, "size", size);
5192 print_bool(PRINT_ANY, "counters_enabled", " counters_enabled %s", counters_enabled);
5193
5194 if (resource_valid) {
5195 resource_units = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_RESOURCE_UNITS]);
5196 resource_path_print(ctx->dl, ctx->resources,
5197 table->resource_id);
5198 pr_out_uint(ctx->dl, "resource_units", resource_units);
5199 }
5200
5201 pr_out_array_start(ctx->dl, "match");
5202 if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
5203 goto err_matches_show;
5204 pr_out_array_end(ctx->dl);
5205
5206 pr_out_array_start(ctx->dl, "action");
5207 if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
5208 goto err_actions_show;
5209 pr_out_array_end(ctx->dl);
5210
5211 return 0;
5212
5213 err_actions_show:
5214 err_matches_show:
5215 pr_out_array_end(ctx->dl);
5216 return -EINVAL;
5217 }
5218
5219 static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
5220 {
5221 struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
5222 struct nlattr *nla_table;
5223
5224 mnl_attr_for_each_nested(nla_table, nla_tables) {
5225 if (ctx->print_tables)
5226 pr_out_handle_start_arr(ctx->dl, tb);
5227 if (dpipe_table_show(ctx, nla_table))
5228 goto err_table_show;
5229 if (ctx->print_tables)
5230 pr_out_handle_end(ctx->dl);
5231 }
5232 return 0;
5233
5234 err_table_show:
5235 if (ctx->print_tables)
5236 pr_out_handle_end(ctx->dl);
5237 return -EINVAL;
5238 }
5239
5240 static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
5241 {
5242 struct dpipe_ctx *ctx = data;
5243 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5244 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5245
5246 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5247 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5248 !tb[DEVLINK_ATTR_DPIPE_TABLES])
5249 return MNL_CB_ERROR;
5250
5251 if (dpipe_tables_show(ctx, tb))
5252 return MNL_CB_ERROR;
5253 return MNL_CB_OK;
5254 }
5255
5256 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data);
5257
5258 static int cmd_dpipe_table_show(struct dl *dl)
5259 {
5260 struct nlmsghdr *nlh;
5261 struct dpipe_ctx dpipe_ctx = {};
5262 struct resource_ctx resource_ctx = {};
5263 uint16_t flags = NLM_F_REQUEST;
5264 int err;
5265
5266 err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
5267 if (err)
5268 return err;
5269
5270 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
5271
5272 err = dpipe_ctx_init(&dpipe_ctx, dl);
5273 if (err)
5274 return err;
5275
5276 dpipe_ctx.print_tables = true;
5277
5278 dl_opts_put(nlh, dl);
5279 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb,
5280 &dpipe_ctx);
5281 if (err) {
5282 pr_err("error get headers %s\n", strerror(dpipe_ctx.err));
5283 goto err_headers_get;
5284 }
5285
5286 err = resource_ctx_init(&resource_ctx, dl);
5287 if (err)
5288 goto err_resource_ctx_init;
5289
5290 resource_ctx.print_resources = false;
5291 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP, flags);
5292 dl_opts_put(nlh, dl);
5293 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
5294 &resource_ctx);
5295 if (!err)
5296 dpipe_ctx.resources = resource_ctx.resources;
5297
5298 flags = NLM_F_REQUEST | NLM_F_ACK;
5299 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
5300 dl_opts_put(nlh, dl);
5301
5302 pr_out_section_start(dl, "table");
5303 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, &dpipe_ctx);
5304 pr_out_section_end(dl);
5305
5306 resource_ctx_fini(&resource_ctx);
5307 dpipe_ctx_fini(&dpipe_ctx);
5308 return 0;
5309
5310 err_resource_ctx_init:
5311 err_headers_get:
5312 dpipe_ctx_fini(&dpipe_ctx);
5313 return err;
5314 }
5315
5316 static int cmd_dpipe_table_set(struct dl *dl)
5317 {
5318 struct nlmsghdr *nlh;
5319 int err;
5320
5321 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
5322 NLM_F_REQUEST | NLM_F_ACK);
5323
5324 err = dl_argv_parse_put(nlh, dl,
5325 DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
5326 DL_OPT_DPIPE_TABLE_COUNTERS, 0);
5327 if (err)
5328 return err;
5329
5330 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
5331 }
5332
5333 enum dpipe_value_type {
5334 DPIPE_VALUE_TYPE_VALUE,
5335 DPIPE_VALUE_TYPE_MASK,
5336 };
5337
5338 static const char *
5339 dpipe_value_type_e2s(enum dpipe_value_type type)
5340 {
5341 switch (type) {
5342 case DPIPE_VALUE_TYPE_VALUE:
5343 return "value";
5344 case DPIPE_VALUE_TYPE_MASK:
5345 return "value_mask";
5346 default:
5347 return "<unknown>";
5348 }
5349 }
5350
5351 struct dpipe_field_printer {
5352 unsigned int field_id;
5353 void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
5354 };
5355
5356 struct dpipe_header_printer {
5357 struct dpipe_field_printer *printers;
5358 unsigned int printers_count;
5359 unsigned int header_id;
5360 };
5361
5362 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
5363 enum dpipe_value_type type,
5364 void *value)
5365 {
5366 struct in_addr ip_addr;
5367
5368 ip_addr.s_addr = htonl(*(uint32_t *)value);
5369 check_indent_newline(ctx->dl);
5370 print_string_name_value(dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
5371 }
5372
5373 static void
5374 dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
5375 enum dpipe_value_type type,
5376 void *value)
5377 {
5378 check_indent_newline(ctx->dl);
5379 print_string_name_value(dpipe_value_type_e2s(type),
5380 ether_ntoa((struct ether_addr *)value));
5381 }
5382
5383 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
5384 enum dpipe_value_type type,
5385 void *value)
5386 {
5387 char str[INET6_ADDRSTRLEN];
5388
5389 inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
5390 check_indent_newline(ctx->dl);
5391 print_string_name_value(dpipe_value_type_e2s(type), str);
5392 }
5393
5394 static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
5395 {
5396 .printer = dpipe_field_printer_ipv4_addr,
5397 .field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
5398 }
5399 };
5400
5401 static struct dpipe_header_printer dpipe_header_printer_ipv4 = {
5402 .printers = dpipe_field_printers_ipv4,
5403 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
5404 .header_id = DEVLINK_DPIPE_HEADER_IPV4,
5405 };
5406
5407 static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
5408 {
5409 .printer = dpipe_field_printer_ethernet_addr,
5410 .field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
5411 },
5412 };
5413
5414 static struct dpipe_header_printer dpipe_header_printer_ethernet = {
5415 .printers = dpipe_field_printers_ethernet,
5416 .printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
5417 .header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
5418 };
5419
5420 static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
5421 {
5422 .printer = dpipe_field_printer_ipv6_addr,
5423 .field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
5424 }
5425 };
5426
5427 static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
5428 .printers = dpipe_field_printers_ipv6,
5429 .printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
5430 .header_id = DEVLINK_DPIPE_HEADER_IPV6,
5431 };
5432
5433 static struct dpipe_header_printer *dpipe_header_printers[] = {
5434 &dpipe_header_printer_ipv4,
5435 &dpipe_header_printer_ethernet,
5436 &dpipe_header_printer_ipv6,
5437 };
5438
5439 static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
5440 struct dpipe_op_info *info,
5441 enum dpipe_value_type type,
5442 void *value)
5443 {
5444 unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
5445 struct dpipe_header_printer *header_printer;
5446 struct dpipe_field_printer *field_printer;
5447 unsigned int field_printers_count;
5448 int j;
5449 int i;
5450
5451 for (i = 0; i < header_printers_count; i++) {
5452 header_printer = dpipe_header_printers[i];
5453 if (header_printer->header_id != info->header_id)
5454 continue;
5455 field_printers_count = header_printer->printers_count;
5456 for (j = 0; j < field_printers_count; j++) {
5457 field_printer = &header_printer->printers[j];
5458 if (field_printer->field_id != info->field_id)
5459 continue;
5460 field_printer->printer(ctx, type, value);
5461 return 0;
5462 }
5463 }
5464
5465 return -EINVAL;
5466 }
5467
5468 static void __pr_out_entry_value(struct dpipe_ctx *ctx,
5469 void *value,
5470 unsigned int value_len,
5471 struct dpipe_op_info *info,
5472 enum dpipe_value_type type)
5473 {
5474 if (info->header_global &&
5475 !dpipe_print_prot_header(ctx, info, type, value))
5476 return;
5477
5478 if (value_len == sizeof(uint32_t)) {
5479 uint32_t *value_32 = value;
5480
5481 pr_out_uint(ctx->dl, dpipe_value_type_e2s(type), *value_32);
5482 }
5483 }
5484
5485 static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
5486 struct nlattr **nla_match_value,
5487 struct dpipe_op_info *info)
5488 {
5489 void *value, *value_mask;
5490 uint32_t value_mapping;
5491 uint16_t value_len;
5492 bool mask, mapping;
5493
5494 mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
5495 mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
5496
5497 value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
5498 value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
5499
5500 if (mapping) {
5501 value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
5502 pr_out_uint(ctx->dl, "mapping_value", value_mapping);
5503 }
5504
5505 if (mask) {
5506 value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
5507 __pr_out_entry_value(ctx, value_mask, value_len, info,
5508 DPIPE_VALUE_TYPE_MASK);
5509 }
5510
5511 __pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
5512 }
5513
5514 static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
5515 struct nlattr *nl)
5516 {
5517 struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
5518 struct dpipe_match match;
5519 int err;
5520
5521 err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
5522 if (err != MNL_CB_OK)
5523 return -EINVAL;
5524
5525 if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
5526 !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
5527 return -EINVAL;
5528 }
5529
5530 pr_out_entry_start(ctx->dl);
5531 if (dpipe_match_parse(&match,
5532 nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
5533 goto err_match_parse;
5534 pr_out_dpipe_match(&match, ctx);
5535 pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
5536 pr_out_entry_end(ctx->dl);
5537
5538 return 0;
5539
5540 err_match_parse:
5541 pr_out_entry_end(ctx->dl);
5542 return -EINVAL;
5543 }
5544
5545 static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
5546 struct nlattr *nl)
5547 {
5548 struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
5549 struct dpipe_action action;
5550 int err;
5551
5552 err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
5553 if (err != MNL_CB_OK)
5554 return -EINVAL;
5555
5556 if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
5557 !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
5558 return -EINVAL;
5559 }
5560
5561 pr_out_entry_start(ctx->dl);
5562 if (dpipe_action_parse(&action,
5563 nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
5564 goto err_action_parse;
5565 pr_out_dpipe_action(&action, ctx);
5566 pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
5567 pr_out_entry_end(ctx->dl);
5568
5569 return 0;
5570
5571 err_action_parse:
5572 pr_out_entry_end(ctx->dl);
5573 return -EINVAL;
5574 }
5575
5576 static int
5577 dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
5578 struct nlattr *nla_action_values)
5579 {
5580 struct nlattr *nla_action_value;
5581
5582 mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
5583 if (dpipe_entry_action_value_show(ctx, nla_action_value))
5584 return -EINVAL;
5585 }
5586 return 0;
5587 }
5588
5589 static int
5590 dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
5591 struct nlattr *nla_match_values)
5592 {
5593 struct nlattr *nla_match_value;
5594
5595 mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
5596 if (dpipe_entry_match_value_show(ctx, nla_match_value))
5597 return -EINVAL;
5598 }
5599 return 0;
5600 }
5601
5602 static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
5603 {
5604 struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
5605 uint32_t entry_index;
5606 uint64_t counter;
5607 int err;
5608
5609 err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
5610 if (err != MNL_CB_OK)
5611 return -EINVAL;
5612
5613 if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
5614 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
5615 !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
5616 return -EINVAL;
5617 }
5618
5619 entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
5620 pr_out_uint(ctx->dl, "index", entry_index);
5621
5622 if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
5623 counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
5624 pr_out_uint(ctx->dl, "counter", counter);
5625 }
5626
5627 pr_out_array_start(ctx->dl, "match_value");
5628 if (dpipe_tables_match_values_show(ctx,
5629 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
5630 goto err_match_values_show;
5631 pr_out_array_end(ctx->dl);
5632
5633 pr_out_array_start(ctx->dl, "action_value");
5634 if (dpipe_tables_action_values_show(ctx,
5635 nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
5636 goto err_action_values_show;
5637 pr_out_array_end(ctx->dl);
5638 return 0;
5639
5640 err_action_values_show:
5641 err_match_values_show:
5642 pr_out_array_end(ctx->dl);
5643 return -EINVAL;
5644 }
5645
5646 static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
5647 {
5648 struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
5649 struct nlattr *nla_entry;
5650
5651 mnl_attr_for_each_nested(nla_entry, nla_entries) {
5652 pr_out_handle_start_arr(ctx->dl, tb);
5653 if (dpipe_entry_show(ctx, nla_entry))
5654 goto err_entry_show;
5655 pr_out_handle_end(ctx->dl);
5656 }
5657 return 0;
5658
5659 err_entry_show:
5660 pr_out_handle_end(ctx->dl);
5661 return -EINVAL;
5662 }
5663
5664 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
5665 {
5666 struct dpipe_ctx *ctx = data;
5667 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5668 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5669
5670 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5671 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5672 !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
5673 return MNL_CB_ERROR;
5674
5675 if (dpipe_table_entries_show(ctx, tb))
5676 return MNL_CB_ERROR;
5677 return MNL_CB_OK;
5678 }
5679
5680 static int cmd_dpipe_table_dump(struct dl *dl)
5681 {
5682 struct nlmsghdr *nlh;
5683 struct dpipe_ctx ctx = {};
5684 uint16_t flags = NLM_F_REQUEST;
5685 int err;
5686
5687 err = dpipe_ctx_init(&ctx, dl);
5688 if (err)
5689 return err;
5690
5691 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
5692 if (err)
5693 goto out;
5694
5695 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
5696 dl_opts_put(nlh, dl);
5697 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, &ctx);
5698 if (err) {
5699 pr_err("error get headers %s\n", strerror(ctx.err));
5700 goto out;
5701 }
5702
5703 flags = NLM_F_REQUEST | NLM_F_ACK;
5704 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
5705 dl_opts_put(nlh, dl);
5706
5707 pr_out_section_start(dl, "table_entry");
5708 _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, &ctx);
5709 pr_out_section_end(dl);
5710 out:
5711 dpipe_ctx_fini(&ctx);
5712 return err;
5713 }
5714
5715 static void cmd_dpipe_table_help(void)
5716 {
5717 pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
5718 "where OBJECT-LIST := { show | set | dump }\n");
5719 }
5720
5721 static int cmd_dpipe_table(struct dl *dl)
5722 {
5723 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5724 cmd_dpipe_table_help();
5725 return 0;
5726 } else if (dl_argv_match(dl, "show")) {
5727 dl_arg_inc(dl);
5728 return cmd_dpipe_table_show(dl);
5729 } else if (dl_argv_match(dl, "set")) {
5730 dl_arg_inc(dl);
5731 return cmd_dpipe_table_set(dl);
5732 } else if (dl_argv_match(dl, "dump")) {
5733 dl_arg_inc(dl);
5734 return cmd_dpipe_table_dump(dl);
5735 }
5736 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5737 return -ENOENT;
5738 }
5739
5740 static void cmd_dpipe_help(void)
5741 {
5742 pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
5743 "where OBJECT-LIST := { header | table }\n");
5744 }
5745
5746 static int cmd_dpipe(struct dl *dl)
5747 {
5748 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
5749 cmd_dpipe_help();
5750 return 0;
5751 } else if (dl_argv_match(dl, "header")) {
5752 dl_arg_inc(dl);
5753 return cmd_dpipe_header(dl);
5754 } else if (dl_argv_match(dl, "table")) {
5755 dl_arg_inc(dl);
5756 return cmd_dpipe_table(dl);
5757 }
5758 pr_err("Command \"%s\" not found\n", dl_argv(dl));
5759 return -ENOENT;
5760 }
5761
5762 static int
5763 resource_parse(struct resource_ctx *ctx, struct resource *resource,
5764 struct nlattr **nla_resource)
5765 {
5766 if (!nla_resource[DEVLINK_ATTR_RESOURCE_NAME] ||
5767 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE] ||
5768 !nla_resource[DEVLINK_ATTR_RESOURCE_ID] ||
5769 !nla_resource[DEVLINK_ATTR_RESOURCE_UNIT] ||
5770 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN] ||
5771 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX] ||
5772 !nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]) {
5773 return -EINVAL;
5774 }
5775
5776 resource->name = strdup(mnl_attr_get_str(nla_resource[DEVLINK_ATTR_RESOURCE_NAME]));
5777 resource->size = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE]);
5778 resource->id = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_ID]);
5779 resource->unit = mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_UNIT]);
5780 resource->size_min = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MIN]);
5781 resource->size_max = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_MAX]);
5782 resource->size_gran = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_GRAN]);
5783
5784 if (nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW])
5785 resource->size_new = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_NEW]);
5786 else
5787 resource->size_new = resource->size;
5788
5789 if (nla_resource[DEVLINK_ATTR_RESOURCE_OCC]) {
5790 resource->size_occ = mnl_attr_get_u64(nla_resource[DEVLINK_ATTR_RESOURCE_OCC]);
5791 resource->occ_valid = true;
5792 }
5793
5794 if (resource->size_new != resource->size)
5795 ctx->pending_change = true;
5796
5797 return 0;
5798 }
5799
5800 static int
5801 resource_get(struct resource_ctx *ctx, struct resource *resource,
5802 struct resource *parent_resource, struct nlattr *nl)
5803 {
5804 struct nlattr *nla_resource[DEVLINK_ATTR_MAX + 1] = {};
5805 struct nlattr *nla_child_resource;
5806 struct nlattr *nla_resources;
5807 bool top = false;
5808 int err;
5809
5810 if (!resource) {
5811 nla_resources = nl;
5812 top = true;
5813 goto out;
5814 }
5815
5816 err = mnl_attr_parse_nested(nl, attr_cb, nla_resource);
5817 if (err != MNL_CB_OK)
5818 return -EINVAL;
5819
5820 err = resource_parse(ctx, resource, nla_resource);
5821 if (err)
5822 return err;
5823
5824 resource->parent = parent_resource;
5825 if (!nla_resource[DEVLINK_ATTR_RESOURCE_LIST])
5826 return 0;
5827
5828 resource->size_valid = !!mnl_attr_get_u8(nla_resource[DEVLINK_ATTR_RESOURCE_SIZE_VALID]);
5829 nla_resources = nla_resource[DEVLINK_ATTR_RESOURCE_LIST];
5830 out:
5831 mnl_attr_for_each_nested(nla_child_resource, nla_resources) {
5832 struct resource *child_resource;
5833 struct list_head *list;
5834
5835 child_resource = resource_alloc();
5836 if (!child_resource)
5837 return -ENOMEM;
5838
5839 if (top)
5840 list = &ctx->resources->resource_list;
5841 else
5842 list = &resource->resource_list;
5843
5844 list_add_tail(&child_resource->list, list);
5845 err = resource_get(ctx, child_resource, resource,
5846 nla_child_resource);
5847 if (err)
5848 return err;
5849 }
5850
5851 return 0;
5852 }
5853
5854 static const char *resource_unit_str_get(enum devlink_resource_unit unit)
5855 {
5856 switch (unit) {
5857 case DEVLINK_RESOURCE_UNIT_ENTRY: return "entry";
5858 default: return "<unknown unit>";
5859 }
5860 }
5861
5862 static void resource_show(struct resource *resource,
5863 struct resource_ctx *ctx)
5864 {
5865 struct resource *child_resource;
5866 struct dpipe_table *table;
5867 struct dl *dl = ctx->dl;
5868 bool array = false;
5869
5870 check_indent_newline(dl);
5871 print_string(PRINT_ANY, "name", "name %s", resource->name);
5872 if (dl->verbose)
5873 resource_path_print(dl, ctx->resources, resource->id);
5874 pr_out_u64(dl, "size", resource->size);
5875 if (resource->size != resource->size_new)
5876 pr_out_u64(dl, "size_new", resource->size_new);
5877 if (resource->occ_valid)
5878 pr_out_uint(dl, "occ", resource->size_occ);
5879 print_string(PRINT_ANY, "unit", " unit %s",
5880 resource_unit_str_get(resource->unit));
5881
5882 if (resource->size_min != resource->size_max) {
5883 pr_out_uint(dl, "size_min", resource->size_min);
5884 pr_out_u64(dl, "size_max", resource->size_max);
5885 pr_out_uint(dl, "size_gran", resource->size_gran);
5886 }
5887
5888 list_for_each_entry(table, &ctx->tables->table_list, list)
5889 if (table->resource_id == resource->id &&
5890 table->resource_valid)
5891 array = true;
5892
5893 if (array)
5894 pr_out_array_start(dl, "dpipe_tables");
5895 else
5896 print_string(PRINT_ANY, "dpipe_tables", " dpipe_tables none",
5897 "none");
5898
5899 list_for_each_entry(table, &ctx->tables->table_list, list) {
5900 if (table->resource_id != resource->id ||
5901 !table->resource_valid)
5902 continue;
5903 pr_out_entry_start(dl);
5904 check_indent_newline(dl);
5905 print_string(PRINT_ANY, "table_name", "table_name %s",
5906 table->name);
5907 pr_out_entry_end(dl);
5908 }
5909 if (array)
5910 pr_out_array_end(dl);
5911
5912 if (list_empty(&resource->resource_list))
5913 return;
5914
5915 if (ctx->pending_change) {
5916 check_indent_newline(dl);
5917 print_string(PRINT_ANY, "size_valid", "size_valid %s",
5918 resource->size_valid ? "true" : "false");
5919 }
5920 pr_out_array_start(dl, "resources");
5921 list_for_each_entry(child_resource, &resource->resource_list, list) {
5922 pr_out_entry_start(dl);
5923 resource_show(child_resource, ctx);
5924 pr_out_entry_end(dl);
5925 }
5926 pr_out_array_end(dl);
5927 }
5928
5929 static void
5930 resources_show(struct resource_ctx *ctx, struct nlattr **tb)
5931 {
5932 struct resources *resources = ctx->resources;
5933 struct resource *resource;
5934
5935 list_for_each_entry(resource, &resources->resource_list, list) {
5936 pr_out_handle_start_arr(ctx->dl, tb);
5937 resource_show(resource, ctx);
5938 pr_out_handle_end(ctx->dl);
5939 }
5940 }
5941
5942 static int resources_get(struct resource_ctx *ctx, struct nlattr **tb)
5943 {
5944 return resource_get(ctx, NULL, NULL, tb[DEVLINK_ATTR_RESOURCE_LIST]);
5945 }
5946
5947 static int cmd_resource_dump_cb(const struct nlmsghdr *nlh, void *data)
5948 {
5949 struct resource_ctx *ctx = data;
5950 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
5951 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
5952 int err;
5953
5954 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
5955 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
5956 !tb[DEVLINK_ATTR_RESOURCE_LIST])
5957 return MNL_CB_ERROR;
5958
5959 err = resources_get(ctx, tb);
5960 if (err) {
5961 ctx->err = err;
5962 return MNL_CB_ERROR;
5963 }
5964
5965 if (ctx->print_resources)
5966 resources_show(ctx, tb);
5967
5968 return MNL_CB_OK;
5969 }
5970
5971 static int cmd_resource_show(struct dl *dl)
5972 {
5973 struct nlmsghdr *nlh;
5974 struct dpipe_ctx dpipe_ctx = {};
5975 struct resource_ctx resource_ctx = {};
5976 int err;
5977
5978 err = dl_argv_parse(dl, DL_OPT_HANDLE, 0);
5979 if (err)
5980 return err;
5981
5982 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET,
5983 NLM_F_REQUEST);
5984 dl_opts_put(nlh, dl);
5985
5986 err = dpipe_ctx_init(&dpipe_ctx, dl);
5987 if (err)
5988 return err;
5989
5990 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb,
5991 &dpipe_ctx);
5992 if (err) {
5993 pr_err("error get tables %s\n", strerror(dpipe_ctx.err));
5994 goto out;
5995 }
5996
5997 err = resource_ctx_init(&resource_ctx, dl);
5998 if (err)
5999 goto out;
6000
6001 resource_ctx.print_resources = true;
6002 resource_ctx.tables = dpipe_ctx.tables;
6003 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6004 NLM_F_REQUEST | NLM_F_ACK);
6005 dl_opts_put(nlh, dl);
6006 pr_out_section_start(dl, "resources");
6007 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb,
6008 &resource_ctx);
6009 pr_out_section_end(dl);
6010 resource_ctx_fini(&resource_ctx);
6011 out:
6012 dpipe_ctx_fini(&dpipe_ctx);
6013 return err;
6014 }
6015
6016 static void cmd_resource_help(void)
6017 {
6018 pr_err("Usage: devlink resource show DEV\n"
6019 " devlink resource set DEV path PATH size SIZE\n");
6020 }
6021
6022 static struct resource *
6023 resource_find_by_name(struct list_head *list, char *name)
6024 {
6025 struct resource *resource;
6026
6027 list_for_each_entry(resource, list, list) {
6028 if (!strcmp(resource->name, name))
6029 return resource;
6030 }
6031 return NULL;
6032 }
6033
6034 static int
6035 resource_path_parse(struct resource_ctx *ctx, const char *resource_path,
6036 uint32_t *p_resource_id, bool *p_resource_valid)
6037 {
6038 struct resource *resource;
6039 uint32_t resource_id = 0;
6040 char *resource_path_dup;
6041 struct list_head *list;
6042 const char del[] = "/";
6043 char *resource_name;
6044
6045 resource_path_dup = strdup(resource_path);
6046 list = &ctx->resources->resource_list;
6047 resource_name = strtok(resource_path_dup, del);
6048 while (resource_name != NULL) {
6049 resource = resource_find_by_name(list, resource_name);
6050 if (!resource)
6051 goto err_resource_lookup;
6052
6053 list = &resource->resource_list;
6054 resource_name = strtok(NULL, del);
6055 resource_id = resource->id;
6056 }
6057 free(resource_path_dup);
6058 *p_resource_valid = true;
6059 *p_resource_id = resource_id;
6060 return 0;
6061
6062 err_resource_lookup:
6063 free(resource_path_dup);
6064 return -EINVAL;
6065 }
6066
6067 static int cmd_resource_set(struct dl *dl)
6068 {
6069 struct nlmsghdr *nlh;
6070 struct resource_ctx ctx = {};
6071 int err;
6072
6073 err = resource_ctx_init(&ctx, dl);
6074 if (err)
6075 return err;
6076
6077 ctx.print_resources = false;
6078 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_RESOURCE_PATH |
6079 DL_OPT_RESOURCE_SIZE, 0);
6080 if (err)
6081 goto out;
6082
6083 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_DUMP,
6084 NLM_F_REQUEST);
6085 dl_opts_put(nlh, dl);
6086 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_resource_dump_cb, &ctx);
6087 if (err) {
6088 pr_err("error getting resources %s\n", strerror(ctx.err));
6089 goto out;
6090 }
6091
6092 err = resource_path_parse(&ctx, dl->opts.resource_path,
6093 &dl->opts.resource_id,
6094 &dl->opts.resource_id_valid);
6095 if (err) {
6096 pr_err("error parsing resource path %s\n", strerror(-err));
6097 goto out;
6098 }
6099
6100 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_RESOURCE_SET,
6101 NLM_F_REQUEST | NLM_F_ACK);
6102
6103 dl_opts_put(nlh, dl);
6104 err = _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6105 out:
6106 resource_ctx_fini(&ctx);
6107 return err;
6108 }
6109
6110 static int cmd_resource(struct dl *dl)
6111 {
6112 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
6113 cmd_resource_help();
6114 return 0;
6115 } else if (dl_argv_match(dl, "show")) {
6116 dl_arg_inc(dl);
6117 return cmd_resource_show(dl);
6118 } else if (dl_argv_match(dl, "set")) {
6119 dl_arg_inc(dl);
6120 return cmd_resource_set(dl);
6121 }
6122 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6123 return -ENOENT;
6124 }
6125
6126 static void pr_out_region_handle_start(struct dl *dl, struct nlattr **tb)
6127 {
6128 const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
6129 const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
6130 const char *region_name = mnl_attr_get_str(tb[DEVLINK_ATTR_REGION_NAME]);
6131 char buf[256];
6132
6133 sprintf(buf, "%s/%s/%s", bus_name, dev_name, region_name);
6134 if (dl->json_output)
6135 open_json_object(buf);
6136 else
6137 pr_out("%s:", buf);
6138 }
6139
6140 static void pr_out_region_handle_end(struct dl *dl)
6141 {
6142 if (dl->json_output)
6143 close_json_object();
6144 else
6145 pr_out("\n");
6146 }
6147
6148 static void pr_out_region_snapshots_start(struct dl *dl, bool array)
6149 {
6150 __pr_out_indent_newline(dl);
6151 if (dl->json_output)
6152 open_json_array(PRINT_JSON, "snapshot");
6153 else
6154 pr_out("snapshot %s", array ? "[" : "");
6155 }
6156
6157 static void pr_out_region_snapshots_end(struct dl *dl, bool array)
6158 {
6159 if (dl->json_output)
6160 close_json_array(PRINT_JSON, NULL);
6161 else if (array)
6162 pr_out("]");
6163 }
6164
6165 static void pr_out_region_snapshots_id(struct dl *dl, struct nlattr **tb, int index)
6166 {
6167 uint32_t snapshot_id;
6168
6169 if (!tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6170 return;
6171
6172 snapshot_id = mnl_attr_get_u32(tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID]);
6173
6174 if (dl->json_output)
6175 print_uint(PRINT_JSON, NULL, NULL, snapshot_id);
6176 else
6177 pr_out("%s%u", index ? " " : "", snapshot_id);
6178 }
6179
6180 static void pr_out_snapshots(struct dl *dl, struct nlattr **tb)
6181 {
6182 struct nlattr *tb_snapshot[DEVLINK_ATTR_MAX + 1] = {};
6183 struct nlattr *nla_sanpshot;
6184 int err, index = 0;
6185
6186 pr_out_region_snapshots_start(dl, true);
6187 mnl_attr_for_each_nested(nla_sanpshot, tb[DEVLINK_ATTR_REGION_SNAPSHOTS]) {
6188 err = mnl_attr_parse_nested(nla_sanpshot, attr_cb, tb_snapshot);
6189 if (err != MNL_CB_OK)
6190 return;
6191 pr_out_region_snapshots_id(dl, tb_snapshot, index++);
6192 }
6193 pr_out_region_snapshots_end(dl, true);
6194 }
6195
6196 static void pr_out_snapshot(struct dl *dl, struct nlattr **tb)
6197 {
6198 pr_out_region_snapshots_start(dl, false);
6199 pr_out_region_snapshots_id(dl, tb, 0);
6200 pr_out_region_snapshots_end(dl, false);
6201 }
6202
6203 static void pr_out_region(struct dl *dl, struct nlattr **tb)
6204 {
6205 pr_out_region_handle_start(dl, tb);
6206
6207 if (tb[DEVLINK_ATTR_REGION_SIZE])
6208 pr_out_u64(dl, "size",
6209 mnl_attr_get_u64(tb[DEVLINK_ATTR_REGION_SIZE]));
6210
6211 if (tb[DEVLINK_ATTR_REGION_SNAPSHOTS])
6212 pr_out_snapshots(dl, tb);
6213
6214 if (tb[DEVLINK_ATTR_REGION_SNAPSHOT_ID])
6215 pr_out_snapshot(dl, tb);
6216
6217 pr_out_region_handle_end(dl);
6218 }
6219
6220 static int cmd_region_show_cb(const struct nlmsghdr *nlh, void *data)
6221 {
6222 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6223 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6224 struct dl *dl = data;
6225
6226 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6227 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6228 !tb[DEVLINK_ATTR_REGION_NAME] || !tb[DEVLINK_ATTR_REGION_SIZE])
6229 return MNL_CB_ERROR;
6230
6231 pr_out_region(dl, tb);
6232
6233 return MNL_CB_OK;
6234 }
6235
6236 static int cmd_region_show(struct dl *dl)
6237 {
6238 struct nlmsghdr *nlh;
6239 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6240 int err;
6241
6242 if (dl_argc(dl) == 0)
6243 flags |= NLM_F_DUMP;
6244
6245 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_GET, flags);
6246
6247 if (dl_argc(dl) > 0) {
6248 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION, 0);
6249 if (err)
6250 return err;
6251 }
6252
6253 pr_out_section_start(dl, "regions");
6254 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_show_cb, dl);
6255 pr_out_section_end(dl);
6256 return err;
6257 }
6258
6259 static int cmd_region_snapshot_del(struct dl *dl)
6260 {
6261 struct nlmsghdr *nlh;
6262 int err;
6263
6264 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_DEL,
6265 NLM_F_REQUEST | NLM_F_ACK);
6266
6267 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6268 DL_OPT_REGION_SNAPSHOT_ID, 0);
6269 if (err)
6270 return err;
6271
6272 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6273 }
6274
6275 static int cmd_region_read_cb(const struct nlmsghdr *nlh, void *data)
6276 {
6277 struct nlattr *nla_entry, *nla_chunk_data, *nla_chunk_addr;
6278 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6279 struct nlattr *tb_field[DEVLINK_ATTR_MAX + 1] = {};
6280 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6281 struct dl *dl = data;
6282 int err;
6283
6284 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6285 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6286 !tb[DEVLINK_ATTR_REGION_CHUNKS])
6287 return MNL_CB_ERROR;
6288
6289 mnl_attr_for_each_nested(nla_entry, tb[DEVLINK_ATTR_REGION_CHUNKS]) {
6290 err = mnl_attr_parse_nested(nla_entry, attr_cb, tb_field);
6291 if (err != MNL_CB_OK)
6292 return MNL_CB_ERROR;
6293
6294 nla_chunk_data = tb_field[DEVLINK_ATTR_REGION_CHUNK_DATA];
6295 if (!nla_chunk_data)
6296 continue;
6297
6298 nla_chunk_addr = tb_field[DEVLINK_ATTR_REGION_CHUNK_ADDR];
6299 if (!nla_chunk_addr)
6300 continue;
6301
6302 pr_out_region_chunk(dl, mnl_attr_get_payload(nla_chunk_data),
6303 mnl_attr_get_payload_len(nla_chunk_data),
6304 mnl_attr_get_u64(nla_chunk_addr));
6305 }
6306 return MNL_CB_OK;
6307 }
6308
6309 static int cmd_region_dump(struct dl *dl)
6310 {
6311 struct nlmsghdr *nlh;
6312 int err;
6313
6314 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
6315 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
6316
6317 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6318 DL_OPT_REGION_SNAPSHOT_ID, 0);
6319 if (err)
6320 return err;
6321
6322 pr_out_section_start(dl, "dump");
6323 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
6324 pr_out_section_end(dl);
6325 if (!dl->json_output)
6326 pr_out("\n");
6327 return err;
6328 }
6329
6330 static int cmd_region_read(struct dl *dl)
6331 {
6332 struct nlmsghdr *nlh;
6333 int err;
6334
6335 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_REGION_READ,
6336 NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
6337
6338 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE_REGION |
6339 DL_OPT_REGION_ADDRESS | DL_OPT_REGION_LENGTH |
6340 DL_OPT_REGION_SNAPSHOT_ID, 0);
6341 if (err)
6342 return err;
6343
6344 pr_out_section_start(dl, "read");
6345 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_region_read_cb, dl);
6346 pr_out_section_end(dl);
6347 if (!dl->json_output)
6348 pr_out("\n");
6349 return err;
6350 }
6351
6352 static void cmd_region_help(void)
6353 {
6354 pr_err("Usage: devlink region show [ DEV/REGION ]\n");
6355 pr_err(" devlink region del DEV/REGION snapshot SNAPSHOT_ID\n");
6356 pr_err(" devlink region dump DEV/REGION [ snapshot SNAPSHOT_ID ]\n");
6357 pr_err(" devlink region read DEV/REGION [ snapshot SNAPSHOT_ID ] address ADDRESS length LENGTH\n");
6358 }
6359
6360 static int cmd_region(struct dl *dl)
6361 {
6362 if (dl_no_arg(dl)) {
6363 return cmd_region_show(dl);
6364 } else if (dl_argv_match(dl, "help")) {
6365 cmd_region_help();
6366 return 0;
6367 } else if (dl_argv_match(dl, "show")) {
6368 dl_arg_inc(dl);
6369 return cmd_region_show(dl);
6370 } else if (dl_argv_match(dl, "del")) {
6371 dl_arg_inc(dl);
6372 return cmd_region_snapshot_del(dl);
6373 } else if (dl_argv_match(dl, "dump")) {
6374 dl_arg_inc(dl);
6375 return cmd_region_dump(dl);
6376 } else if (dl_argv_match(dl, "read")) {
6377 dl_arg_inc(dl);
6378 return cmd_region_read(dl);
6379 }
6380 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6381 return -ENOENT;
6382 }
6383
6384 static int cmd_health_set_params(struct dl *dl)
6385 {
6386 struct nlmsghdr *nlh;
6387 int err;
6388
6389 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_SET,
6390 NLM_F_REQUEST | NLM_F_ACK);
6391 err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME,
6392 DL_OPT_HEALTH_REPORTER_GRACEFUL_PERIOD |
6393 DL_OPT_HEALTH_REPORTER_AUTO_RECOVER);
6394 if (err)
6395 return err;
6396
6397 dl_opts_put(nlh, dl);
6398 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6399 }
6400
6401 static int cmd_health_dump_clear(struct dl *dl)
6402 {
6403 struct nlmsghdr *nlh;
6404 int err;
6405
6406 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_DUMP_CLEAR,
6407 NLM_F_REQUEST | NLM_F_ACK);
6408
6409 err = dl_argv_parse_put(nlh, dl,
6410 DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
6411 if (err)
6412 return err;
6413
6414 dl_opts_put(nlh, dl);
6415 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6416 }
6417
6418 static int fmsg_value_show(struct dl *dl, int type, struct nlattr *nl_data)
6419 {
6420 uint8_t *data;
6421 uint32_t len;
6422
6423 check_indent_newline(dl);
6424 switch (type) {
6425 case MNL_TYPE_FLAG:
6426 print_bool(PRINT_ANY, NULL, "%s", mnl_attr_get_u8(nl_data));
6427 break;
6428 case MNL_TYPE_U8:
6429 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u8(nl_data));
6430 break;
6431 case MNL_TYPE_U16:
6432 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u16(nl_data));
6433 break;
6434 case MNL_TYPE_U32:
6435 print_uint(PRINT_ANY, NULL, "%u", mnl_attr_get_u32(nl_data));
6436 break;
6437 case MNL_TYPE_U64:
6438 print_u64(PRINT_ANY, NULL, "%"PRIu64, mnl_attr_get_u64(nl_data));
6439 break;
6440 case MNL_TYPE_NUL_STRING:
6441 print_string(PRINT_ANY, NULL, "%s", mnl_attr_get_str(nl_data));
6442 break;
6443 case MNL_TYPE_BINARY:
6444 len = mnl_attr_get_payload_len(nl_data);
6445 data = mnl_attr_get_payload(nl_data);
6446 pr_out_binary_value(dl, data, len);
6447 break;
6448 default:
6449 return -EINVAL;
6450 }
6451 return MNL_CB_OK;
6452 }
6453
6454 static void pr_out_fmsg_name(struct dl *dl, char **name)
6455 {
6456 if (!*name)
6457 return;
6458
6459 pr_out_name(dl, *name);
6460 free(*name);
6461 *name = NULL;
6462 }
6463
6464 struct nest_entry {
6465 int attr_type;
6466 struct list_head list;
6467 };
6468
6469 struct fmsg_cb_data {
6470 char *name;
6471 struct dl *dl;
6472 uint8_t value_type;
6473 struct list_head entry_list;
6474 };
6475
6476 static int cmd_fmsg_nest_queue(struct fmsg_cb_data *fmsg_data,
6477 uint8_t *attr_value, bool insert)
6478 {
6479 struct nest_entry *entry;
6480
6481 if (insert) {
6482 entry = malloc(sizeof(struct nest_entry));
6483 if (!entry)
6484 return -ENOMEM;
6485
6486 entry->attr_type = *attr_value;
6487 list_add(&entry->list, &fmsg_data->entry_list);
6488 } else {
6489 if (list_empty(&fmsg_data->entry_list))
6490 return MNL_CB_ERROR;
6491 entry = list_first_entry(&fmsg_data->entry_list,
6492 struct nest_entry, list);
6493 *attr_value = entry->attr_type;
6494 list_del(&entry->list);
6495 free(entry);
6496 }
6497 return MNL_CB_OK;
6498 }
6499
6500 static void pr_out_fmsg_group_start(struct dl *dl, char **name)
6501 {
6502 __pr_out_newline();
6503 pr_out_fmsg_name(dl, name);
6504 __pr_out_newline();
6505 __pr_out_indent_inc();
6506 }
6507
6508 static void pr_out_fmsg_group_end(struct dl *dl)
6509 {
6510 __pr_out_newline();
6511 __pr_out_indent_dec();
6512 }
6513
6514 static void pr_out_fmsg_start_object(struct dl *dl, char **name)
6515 {
6516 if (dl->json_output) {
6517 pr_out_fmsg_name(dl, name);
6518 open_json_object(NULL);
6519 } else {
6520 pr_out_fmsg_group_start(dl, name);
6521 }
6522 }
6523
6524 static void pr_out_fmsg_end_object(struct dl *dl)
6525 {
6526 if (dl->json_output)
6527 close_json_object();
6528 else
6529 pr_out_fmsg_group_end(dl);
6530 }
6531
6532 static void pr_out_fmsg_start_array(struct dl *dl, char **name)
6533 {
6534 if (dl->json_output) {
6535 pr_out_fmsg_name(dl, name);
6536 open_json_array(PRINT_JSON, NULL);
6537 } else {
6538 pr_out_fmsg_group_start(dl, name);
6539 }
6540 }
6541
6542 static void pr_out_fmsg_end_array(struct dl *dl)
6543 {
6544 if (dl->json_output)
6545 close_json_array(PRINT_JSON, NULL);
6546 else
6547 pr_out_fmsg_group_end(dl);
6548 }
6549
6550 static int cmd_fmsg_nest(struct fmsg_cb_data *fmsg_data, uint8_t nest_value,
6551 bool start)
6552 {
6553 struct dl *dl = fmsg_data->dl;
6554 uint8_t value = nest_value;
6555 int err;
6556
6557 err = cmd_fmsg_nest_queue(fmsg_data, &value, start);
6558 if (err != MNL_CB_OK)
6559 return err;
6560
6561 switch (value) {
6562 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
6563 if (start)
6564 pr_out_fmsg_start_object(dl, &fmsg_data->name);
6565 else
6566 pr_out_fmsg_end_object(dl);
6567 break;
6568 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
6569 break;
6570 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
6571 if (start)
6572 pr_out_fmsg_start_array(dl, &fmsg_data->name);
6573 else
6574 pr_out_fmsg_end_array(dl);
6575 break;
6576 default:
6577 return -EINVAL;
6578 }
6579 return MNL_CB_OK;
6580 }
6581
6582 static int cmd_fmsg_object_cb(const struct nlmsghdr *nlh, void *data)
6583 {
6584 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6585 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6586 struct fmsg_cb_data *fmsg_data = data;
6587 struct dl *dl = fmsg_data->dl;
6588 struct nlattr *nla_object;
6589 int attr_type;
6590 int err;
6591
6592 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6593 if (!tb[DEVLINK_ATTR_FMSG])
6594 return MNL_CB_ERROR;
6595
6596 mnl_attr_for_each_nested(nla_object, tb[DEVLINK_ATTR_FMSG]) {
6597 attr_type = mnl_attr_get_type(nla_object);
6598 switch (attr_type) {
6599 case DEVLINK_ATTR_FMSG_OBJ_NEST_START:
6600 case DEVLINK_ATTR_FMSG_PAIR_NEST_START:
6601 case DEVLINK_ATTR_FMSG_ARR_NEST_START:
6602 err = cmd_fmsg_nest(fmsg_data, attr_type, true);
6603 if (err != MNL_CB_OK)
6604 return err;
6605 break;
6606 case DEVLINK_ATTR_FMSG_NEST_END:
6607 err = cmd_fmsg_nest(fmsg_data, attr_type, false);
6608 if (err != MNL_CB_OK)
6609 return err;
6610 break;
6611 case DEVLINK_ATTR_FMSG_OBJ_NAME:
6612 free(fmsg_data->name);
6613 fmsg_data->name = strdup(mnl_attr_get_str(nla_object));
6614 if (!fmsg_data->name)
6615 return -ENOMEM;
6616 break;
6617 case DEVLINK_ATTR_FMSG_OBJ_VALUE_TYPE:
6618 fmsg_data->value_type = mnl_attr_get_u8(nla_object);
6619 break;
6620 case DEVLINK_ATTR_FMSG_OBJ_VALUE_DATA:
6621 pr_out_fmsg_name(dl, &fmsg_data->name);
6622 err = fmsg_value_show(dl, fmsg_data->value_type,
6623 nla_object);
6624 if (err != MNL_CB_OK)
6625 return err;
6626 break;
6627 default:
6628 return -EINVAL;
6629 }
6630 }
6631 return MNL_CB_OK;
6632 }
6633
6634 static void cmd_fmsg_init(struct dl *dl, struct fmsg_cb_data *data)
6635 {
6636 /* FMSG is dynamic: opening of an object or array causes a
6637 * newline. JSON starts with an { or [, but plain text should
6638 * not start with a new line. Ensure this by setting
6639 * g_new_line_count to 1: avoiding newline before the first
6640 * print.
6641 */
6642 g_new_line_count = 1;
6643 data->name = NULL;
6644 data->dl = dl;
6645 INIT_LIST_HEAD(&data->entry_list);
6646 }
6647
6648 static int cmd_health_object_common(struct dl *dl, uint8_t cmd, uint16_t flags)
6649 {
6650 struct fmsg_cb_data data;
6651 struct nlmsghdr *nlh;
6652 int err;
6653
6654 nlh = mnlg_msg_prepare(dl->nlg, cmd, flags | NLM_F_REQUEST | NLM_F_ACK);
6655
6656 err = dl_argv_parse_put(nlh, dl,
6657 DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
6658 if (err)
6659 return err;
6660
6661 cmd_fmsg_init(dl, &data);
6662 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_fmsg_object_cb, &data);
6663 free(data.name);
6664 return err;
6665 }
6666
6667 static int cmd_health_dump_show(struct dl *dl)
6668 {
6669 return cmd_health_object_common(dl,
6670 DEVLINK_CMD_HEALTH_REPORTER_DUMP_GET,
6671 NLM_F_DUMP);
6672 }
6673
6674 static int cmd_health_diagnose(struct dl *dl)
6675 {
6676 return cmd_health_object_common(dl,
6677 DEVLINK_CMD_HEALTH_REPORTER_DIAGNOSE,
6678 0);
6679 }
6680
6681 static int cmd_health_recover(struct dl *dl)
6682 {
6683 struct nlmsghdr *nlh;
6684 int err;
6685
6686 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_RECOVER,
6687 NLM_F_REQUEST | NLM_F_ACK);
6688
6689 err = dl_argv_parse_put(nlh, dl,
6690 DL_OPT_HANDLE | DL_OPT_HEALTH_REPORTER_NAME, 0);
6691 if (err)
6692 return err;
6693
6694 dl_opts_put(nlh, dl);
6695 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
6696 }
6697
6698 enum devlink_health_reporter_state {
6699 DEVLINK_HEALTH_REPORTER_STATE_HEALTHY,
6700 DEVLINK_HEALTH_REPORTER_STATE_ERROR,
6701 };
6702
6703 static const char *health_state_name(uint8_t state)
6704 {
6705 switch (state) {
6706 case DEVLINK_HEALTH_REPORTER_STATE_HEALTHY:
6707 return HEALTH_REPORTER_STATE_HEALTHY_STR;
6708 case DEVLINK_HEALTH_REPORTER_STATE_ERROR:
6709 return HEALTH_REPORTER_STATE_ERROR_STR;
6710 default:
6711 return "<unknown state>";
6712 }
6713 }
6714
6715 static void pr_out_dump_reporter_format_logtime(struct dl *dl, const struct nlattr *attr)
6716 {
6717 char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
6718 char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
6719 uint64_t time_ms = mnl_attr_get_u64(attr);
6720 struct sysinfo s_info;
6721 struct tm *info;
6722 time_t now, sec;
6723 int err;
6724
6725 time(&now);
6726 info = localtime(&now);
6727 err = sysinfo(&s_info);
6728 if (err)
6729 goto out;
6730 /* Subtract uptime in sec from now yields the time of system
6731 * uptime. To this, add time_ms which is the amount of
6732 * milliseconds elapsed between uptime and the dump taken.
6733 */
6734 sec = now - s_info.uptime + time_ms / 1000;
6735 info = localtime(&sec);
6736 out:
6737 strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", info);
6738 strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", info);
6739 check_indent_newline(dl);
6740 print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
6741 print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
6742 }
6743
6744 static void pr_out_dump_report_timestamp(struct dl *dl, const struct nlattr *attr)
6745 {
6746 char dump_date[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
6747 char dump_time[HEALTH_REPORTER_TIMESTAMP_FMT_LEN];
6748 time_t tv_sec;
6749 struct tm *tm;
6750 uint64_t ts;
6751
6752 ts = mnl_attr_get_u64(attr);
6753 tv_sec = ts / 1000000000;
6754 tm = localtime(&tv_sec);
6755
6756 strftime(dump_date, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%Y-%m-%d", tm);
6757 strftime(dump_time, HEALTH_REPORTER_TIMESTAMP_FMT_LEN, "%H:%M:%S", tm);
6758
6759 check_indent_newline(dl);
6760 print_string(PRINT_ANY, "last_dump_date", "last_dump_date %s", dump_date);
6761 print_string(PRINT_ANY, "last_dump_time", " last_dump_time %s", dump_time);
6762 }
6763
6764 static void pr_out_health(struct dl *dl, struct nlattr **tb_health)
6765 {
6766 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6767 enum devlink_health_reporter_state state;
6768 int err;
6769
6770 err = mnl_attr_parse_nested(tb_health[DEVLINK_ATTR_HEALTH_REPORTER],
6771 attr_cb, tb);
6772 if (err != MNL_CB_OK)
6773 return;
6774
6775 if (!tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME] ||
6776 !tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT] ||
6777 !tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT] ||
6778 !tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE])
6779 return;
6780
6781 pr_out_handle_start_arr(dl, tb_health);
6782
6783 check_indent_newline(dl);
6784 print_string(PRINT_ANY, "reporter", "reporter %s",
6785 mnl_attr_get_str(tb[DEVLINK_ATTR_HEALTH_REPORTER_NAME]));
6786 if (!dl->json_output) {
6787 __pr_out_newline();
6788 __pr_out_indent_inc();
6789 }
6790 state = mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_STATE]);
6791 check_indent_newline(dl);
6792 print_string(PRINT_ANY, "state", "state %s", health_state_name(state));
6793 pr_out_u64(dl, "error",
6794 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_ERR_COUNT]));
6795 pr_out_u64(dl, "recover",
6796 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_RECOVER_COUNT]));
6797 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS])
6798 pr_out_dump_report_timestamp(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS_NS]);
6799 else if (tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS])
6800 pr_out_dump_reporter_format_logtime(dl, tb[DEVLINK_ATTR_HEALTH_REPORTER_DUMP_TS]);
6801 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD])
6802 pr_out_u64(dl, "grace_period",
6803 mnl_attr_get_u64(tb[DEVLINK_ATTR_HEALTH_REPORTER_GRACEFUL_PERIOD]));
6804 if (tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER])
6805 pr_out_bool(dl, "auto_recover",
6806 mnl_attr_get_u8(tb[DEVLINK_ATTR_HEALTH_REPORTER_AUTO_RECOVER]));
6807
6808 __pr_out_indent_dec();
6809 pr_out_handle_end(dl);
6810 }
6811
6812 static int cmd_health_show_cb(const struct nlmsghdr *nlh, void *data)
6813 {
6814 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6815 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6816 struct dl *dl = data;
6817
6818 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6819 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6820 !tb[DEVLINK_ATTR_HEALTH_REPORTER])
6821 return MNL_CB_ERROR;
6822
6823 pr_out_health(dl, tb);
6824
6825 return MNL_CB_OK;
6826 }
6827
6828 static int cmd_health_show(struct dl *dl)
6829 {
6830 struct nlmsghdr *nlh;
6831 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6832 int err;
6833
6834 if (dl_argc(dl) == 0)
6835 flags |= NLM_F_DUMP;
6836 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_HEALTH_REPORTER_GET,
6837 flags);
6838
6839 if (dl_argc(dl) > 0) {
6840 err = dl_argv_parse_put(nlh, dl,
6841 DL_OPT_HANDLE |
6842 DL_OPT_HEALTH_REPORTER_NAME, 0);
6843 if (err)
6844 return err;
6845 }
6846 pr_out_section_start(dl, "health");
6847
6848 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_health_show_cb, dl);
6849 pr_out_section_end(dl);
6850 return err;
6851 }
6852
6853 static void cmd_health_help(void)
6854 {
6855 pr_err("Usage: devlink health show [ dev DEV reporter REPORTER_NAME ]\n");
6856 pr_err(" devlink health recover DEV reporter REPORTER_NAME\n");
6857 pr_err(" devlink health diagnose DEV reporter REPORTER_NAME\n");
6858 pr_err(" devlink health dump show DEV reporter REPORTER_NAME\n");
6859 pr_err(" devlink health dump clear DEV reporter REPORTER_NAME\n");
6860 pr_err(" devlink health set DEV reporter REPORTER_NAME { grace_period | auto_recover } { msec | boolean }\n");
6861 }
6862
6863 static int cmd_health(struct dl *dl)
6864 {
6865 if (dl_argv_match(dl, "help")) {
6866 cmd_health_help();
6867 return 0;
6868 } else if (dl_argv_match(dl, "show") ||
6869 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
6870 dl_arg_inc(dl);
6871 return cmd_health_show(dl);
6872 } else if (dl_argv_match(dl, "recover")) {
6873 dl_arg_inc(dl);
6874 return cmd_health_recover(dl);
6875 } else if (dl_argv_match(dl, "diagnose")) {
6876 dl_arg_inc(dl);
6877 return cmd_health_diagnose(dl);
6878 } else if (dl_argv_match(dl, "dump")) {
6879 dl_arg_inc(dl);
6880 if (dl_argv_match(dl, "show")) {
6881 dl_arg_inc(dl);
6882 return cmd_health_dump_show(dl);
6883 } else if (dl_argv_match(dl, "clear")) {
6884 dl_arg_inc(dl);
6885 return cmd_health_dump_clear(dl);
6886 }
6887 } else if (dl_argv_match(dl, "set")) {
6888 dl_arg_inc(dl);
6889 return cmd_health_set_params(dl);
6890 }
6891 pr_err("Command \"%s\" not found\n", dl_argv(dl));
6892 return -ENOENT;
6893 }
6894
6895 static const char *trap_type_name(uint8_t type)
6896 {
6897 switch (type) {
6898 case DEVLINK_TRAP_TYPE_DROP:
6899 return "drop";
6900 case DEVLINK_TRAP_TYPE_EXCEPTION:
6901 return "exception";
6902 default:
6903 return "<unknown type>";
6904 }
6905 }
6906
6907 static const char *trap_action_name(uint8_t action)
6908 {
6909 switch (action) {
6910 case DEVLINK_TRAP_ACTION_DROP:
6911 return "drop";
6912 case DEVLINK_TRAP_ACTION_TRAP:
6913 return "trap";
6914 default:
6915 return "<unknown action>";
6916 }
6917 }
6918
6919 static const char *trap_metadata_name(const struct nlattr *attr)
6920 {
6921 switch (attr->nla_type) {
6922 case DEVLINK_ATTR_TRAP_METADATA_TYPE_IN_PORT:
6923 return "input_port";
6924 default:
6925 return "<unknown metadata type>";
6926 }
6927 }
6928 static void pr_out_trap_metadata(struct dl *dl, struct nlattr *attr)
6929 {
6930 struct nlattr *attr_metadata;
6931
6932 pr_out_array_start(dl, "metadata");
6933 mnl_attr_for_each_nested(attr_metadata, attr) {
6934 check_indent_newline(dl);
6935 print_string(PRINT_ANY, NULL, "%s",
6936 trap_metadata_name(attr_metadata));
6937 }
6938 pr_out_array_end(dl);
6939 }
6940
6941 static void pr_out_trap(struct dl *dl, struct nlattr **tb, bool array)
6942 {
6943 uint8_t action = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_ACTION]);
6944 uint8_t type = mnl_attr_get_u8(tb[DEVLINK_ATTR_TRAP_TYPE]);
6945
6946 if (array)
6947 pr_out_handle_start_arr(dl, tb);
6948 else
6949 __pr_out_handle_start(dl, tb, true, false);
6950
6951 check_indent_newline(dl);
6952 print_string(PRINT_ANY, "name", "name %s",
6953 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_NAME]));
6954 print_string(PRINT_ANY, "type", " type %s", trap_type_name(type));
6955 pr_out_bool(dl, "generic", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
6956 print_string(PRINT_ANY, "action", " action %s", trap_action_name(action));
6957 print_string(PRINT_ANY, "group", " group %s",
6958 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
6959 if (dl->verbose)
6960 pr_out_trap_metadata(dl, tb[DEVLINK_ATTR_TRAP_METADATA]);
6961 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
6962 pr_out_handle_end(dl);
6963 }
6964
6965 static int cmd_trap_show_cb(const struct nlmsghdr *nlh, void *data)
6966 {
6967 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
6968 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
6969 struct dl *dl = data;
6970
6971 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
6972 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
6973 !tb[DEVLINK_ATTR_TRAP_NAME] || !tb[DEVLINK_ATTR_TRAP_TYPE] ||
6974 !tb[DEVLINK_ATTR_TRAP_ACTION] ||
6975 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] ||
6976 !tb[DEVLINK_ATTR_TRAP_METADATA] || !tb[DEVLINK_ATTR_STATS])
6977 return MNL_CB_ERROR;
6978
6979 pr_out_trap(dl, tb, true);
6980
6981 return MNL_CB_OK;
6982 }
6983
6984 static void cmd_trap_help(void)
6985 {
6986 pr_err("Usage: devlink trap set DEV trap TRAP [ action { trap | drop } ]\n");
6987 pr_err(" devlink trap show [ DEV trap TRAP ]\n");
6988 pr_err(" devlink trap group set DEV group GROUP [ action { trap | drop } ]\n");
6989 pr_err(" devlink trap group show [ DEV group GROUP ]\n");
6990 }
6991
6992 static int cmd_trap_show(struct dl *dl)
6993 {
6994 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
6995 struct nlmsghdr *nlh;
6996 int err;
6997
6998 if (dl_argc(dl) == 0)
6999 flags |= NLM_F_DUMP;
7000
7001 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GET, flags);
7002
7003 if (dl_argc(dl) > 0) {
7004 err = dl_argv_parse_put(nlh, dl,
7005 DL_OPT_HANDLE | DL_OPT_TRAP_NAME, 0);
7006 if (err)
7007 return err;
7008 }
7009
7010 pr_out_section_start(dl, "trap");
7011 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_show_cb, dl);
7012 pr_out_section_end(dl);
7013
7014 return err;
7015 }
7016
7017 static int cmd_trap_set(struct dl *dl)
7018 {
7019 struct nlmsghdr *nlh;
7020 int err;
7021
7022 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_SET,
7023 NLM_F_REQUEST | NLM_F_ACK);
7024
7025 err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_TRAP_NAME,
7026 DL_OPT_TRAP_ACTION);
7027 if (err)
7028 return err;
7029
7030 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7031 }
7032
7033 static void pr_out_trap_group(struct dl *dl, struct nlattr **tb, bool array)
7034 {
7035 if (array)
7036 pr_out_handle_start_arr(dl, tb);
7037 else
7038 __pr_out_handle_start(dl, tb, true, false);
7039
7040 check_indent_newline(dl);
7041 print_string(PRINT_ANY, "name", "name %s",
7042 mnl_attr_get_str(tb[DEVLINK_ATTR_TRAP_GROUP_NAME]));
7043 pr_out_bool(dl, "generic", !!tb[DEVLINK_ATTR_TRAP_GENERIC]);
7044 pr_out_stats(dl, tb[DEVLINK_ATTR_STATS]);
7045 pr_out_handle_end(dl);
7046 }
7047
7048 static int cmd_trap_group_show_cb(const struct nlmsghdr *nlh, void *data)
7049 {
7050 struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
7051 struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
7052 struct dl *dl = data;
7053
7054 mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
7055 if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
7056 !tb[DEVLINK_ATTR_TRAP_GROUP_NAME] || !tb[DEVLINK_ATTR_STATS])
7057 return MNL_CB_ERROR;
7058
7059 pr_out_trap_group(dl, tb, true);
7060
7061 return MNL_CB_OK;
7062 }
7063
7064 static int cmd_trap_group_show(struct dl *dl)
7065 {
7066 uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
7067 struct nlmsghdr *nlh;
7068 int err;
7069
7070 if (dl_argc(dl) == 0)
7071 flags |= NLM_F_DUMP;
7072
7073 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_GET, flags);
7074
7075 if (dl_argc(dl) > 0) {
7076 err = dl_argv_parse_put(nlh, dl,
7077 DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
7078 0);
7079 if (err)
7080 return err;
7081 }
7082
7083 pr_out_section_start(dl, "trap_group");
7084 err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_trap_group_show_cb, dl);
7085 pr_out_section_end(dl);
7086
7087 return err;
7088 }
7089
7090 static int cmd_trap_group_set(struct dl *dl)
7091 {
7092 struct nlmsghdr *nlh;
7093 int err;
7094
7095 nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_TRAP_GROUP_SET,
7096 NLM_F_REQUEST | NLM_F_ACK);
7097
7098 err = dl_argv_parse_put(nlh, dl,
7099 DL_OPT_HANDLE | DL_OPT_TRAP_GROUP_NAME,
7100 DL_OPT_TRAP_ACTION);
7101 if (err)
7102 return err;
7103
7104 return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
7105 }
7106
7107 static int cmd_trap_group(struct dl *dl)
7108 {
7109 if (dl_argv_match(dl, "help")) {
7110 cmd_trap_help();
7111 return 0;
7112 } else if (dl_argv_match(dl, "show") ||
7113 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7114 dl_arg_inc(dl);
7115 return cmd_trap_group_show(dl);
7116 } else if (dl_argv_match(dl, "set")) {
7117 dl_arg_inc(dl);
7118 return cmd_trap_group_set(dl);
7119 }
7120 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7121 return -ENOENT;
7122 }
7123
7124 static int cmd_trap(struct dl *dl)
7125 {
7126 if (dl_argv_match(dl, "help")) {
7127 cmd_trap_help();
7128 return 0;
7129 } else if (dl_argv_match(dl, "show") ||
7130 dl_argv_match(dl, "list") || dl_no_arg(dl)) {
7131 dl_arg_inc(dl);
7132 return cmd_trap_show(dl);
7133 } else if (dl_argv_match(dl, "set")) {
7134 dl_arg_inc(dl);
7135 return cmd_trap_set(dl);
7136 } else if (dl_argv_match(dl, "group")) {
7137 dl_arg_inc(dl);
7138 return cmd_trap_group(dl);
7139 }
7140 pr_err("Command \"%s\" not found\n", dl_argv(dl));
7141 return -ENOENT;
7142 }
7143
7144 static void help(void)
7145 {
7146 pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
7147 " devlink [ -f[orce] ] -b[atch] filename -N[etns] netnsname\n"
7148 "where OBJECT := { dev | port | sb | monitor | dpipe | resource | region | health | trap }\n"
7149 " OPTIONS := { -V[ersion] | -n[o-nice-names] | -j[son] | -p[retty] | -v[erbose] -s[tatistics] }\n");
7150 }
7151
7152 static int dl_cmd(struct dl *dl, int argc, char **argv)
7153 {
7154 dl->argc = argc;
7155 dl->argv = argv;
7156
7157 if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
7158 help();
7159 return 0;
7160 } else if (dl_argv_match(dl, "dev")) {
7161 dl_arg_inc(dl);
7162 return cmd_dev(dl);
7163 } else if (dl_argv_match(dl, "port")) {
7164 dl_arg_inc(dl);
7165 return cmd_port(dl);
7166 } else if (dl_argv_match(dl, "sb")) {
7167 dl_arg_inc(dl);
7168 return cmd_sb(dl);
7169 } else if (dl_argv_match(dl, "monitor")) {
7170 dl_arg_inc(dl);
7171 return cmd_mon(dl);
7172 } else if (dl_argv_match(dl, "dpipe")) {
7173 dl_arg_inc(dl);
7174 return cmd_dpipe(dl);
7175 } else if (dl_argv_match(dl, "resource")) {
7176 dl_arg_inc(dl);
7177 return cmd_resource(dl);
7178 } else if (dl_argv_match(dl, "region")) {
7179 dl_arg_inc(dl);
7180 return cmd_region(dl);
7181 } else if (dl_argv_match(dl, "health")) {
7182 dl_arg_inc(dl);
7183 return cmd_health(dl);
7184 } else if (dl_argv_match(dl, "trap")) {
7185 dl_arg_inc(dl);
7186 return cmd_trap(dl);
7187 }
7188 pr_err("Object \"%s\" not found\n", dl_argv(dl));
7189 return -ENOENT;
7190 }
7191
7192 static int dl_init(struct dl *dl)
7193 {
7194 int err;
7195
7196 dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
7197 if (!dl->nlg) {
7198 pr_err("Failed to connect to devlink Netlink\n");
7199 return -errno;
7200 }
7201
7202 err = ifname_map_init(dl);
7203 if (err) {
7204 pr_err("Failed to create index map\n");
7205 goto err_ifname_map_create;
7206 }
7207 new_json_obj_plain(dl->json_output);
7208 return 0;
7209
7210 err_ifname_map_create:
7211 mnlg_socket_close(dl->nlg);
7212 return err;
7213 }
7214
7215 static void dl_fini(struct dl *dl)
7216 {
7217 delete_json_obj_plain();
7218 ifname_map_fini(dl);
7219 mnlg_socket_close(dl->nlg);
7220 }
7221
7222 static struct dl *dl_alloc(void)
7223 {
7224 struct dl *dl;
7225
7226 dl = calloc(1, sizeof(*dl));
7227 if (!dl)
7228 return NULL;
7229 return dl;
7230 }
7231
7232 static void dl_free(struct dl *dl)
7233 {
7234 free(dl);
7235 }
7236
7237 static int dl_batch(struct dl *dl, const char *name, bool force)
7238 {
7239 char *line = NULL;
7240 size_t len = 0;
7241 int ret = EXIT_SUCCESS;
7242
7243 if (name && strcmp(name, "-") != 0) {
7244 if (freopen(name, "r", stdin) == NULL) {
7245 fprintf(stderr,
7246 "Cannot open file \"%s\" for reading: %s\n",
7247 name, strerror(errno));
7248 return EXIT_FAILURE;
7249 }
7250 }
7251
7252 cmdlineno = 0;
7253 while (getcmdline(&line, &len, stdin) != -1) {
7254 char *largv[100];
7255 int largc;
7256
7257 largc = makeargs(line, largv, 100);
7258 if (!largc)
7259 continue; /* blank line */
7260
7261 if (dl_cmd(dl, largc, largv)) {
7262 fprintf(stderr, "Command failed %s:%d\n",
7263 name, cmdlineno);
7264 ret = EXIT_FAILURE;
7265 if (!force)
7266 break;
7267 }
7268 }
7269
7270 if (line)
7271 free(line);
7272
7273 return ret;
7274 }
7275
7276 int main(int argc, char **argv)
7277 {
7278 static const struct option long_options[] = {
7279 { "Version", no_argument, NULL, 'V' },
7280 { "force", no_argument, NULL, 'f' },
7281 { "batch", required_argument, NULL, 'b' },
7282 { "no-nice-names", no_argument, NULL, 'n' },
7283 { "json", no_argument, NULL, 'j' },
7284 { "pretty", no_argument, NULL, 'p' },
7285 { "verbose", no_argument, NULL, 'v' },
7286 { "statistics", no_argument, NULL, 's' },
7287 { "Netns", required_argument, NULL, 'N' },
7288 { NULL, 0, NULL, 0 }
7289 };
7290 const char *batch_file = NULL;
7291 bool force = false;
7292 struct dl *dl;
7293 int opt;
7294 int err;
7295 int ret;
7296
7297 dl = dl_alloc();
7298 if (!dl) {
7299 pr_err("Failed to allocate memory for devlink\n");
7300 return EXIT_FAILURE;
7301 }
7302
7303 while ((opt = getopt_long(argc, argv, "Vfb:njpvsN:",
7304 long_options, NULL)) >= 0) {
7305
7306 switch (opt) {
7307 case 'V':
7308 printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
7309 ret = EXIT_SUCCESS;
7310 goto dl_free;
7311 case 'f':
7312 force = true;
7313 break;
7314 case 'b':
7315 batch_file = optarg;
7316 break;
7317 case 'n':
7318 dl->no_nice_names = true;
7319 break;
7320 case 'j':
7321 dl->json_output = true;
7322 break;
7323 case 'p':
7324 pretty = true;
7325 break;
7326 case 'v':
7327 dl->verbose = true;
7328 break;
7329 case 's':
7330 dl->stats = true;
7331 break;
7332 case 'N':
7333 if (netns_switch(optarg)) {
7334 ret = EXIT_FAILURE;
7335 goto dl_free;
7336 }
7337 break;
7338 default:
7339 pr_err("Unknown option.\n");
7340 help();
7341 ret = EXIT_FAILURE;
7342 goto dl_free;
7343 }
7344 }
7345
7346 argc -= optind;
7347 argv += optind;
7348
7349 err = dl_init(dl);
7350 if (err) {
7351 ret = EXIT_FAILURE;
7352 goto dl_free;
7353 }
7354
7355 if (batch_file)
7356 err = dl_batch(dl, batch_file, force);
7357 else
7358 err = dl_cmd(dl, argc, argv);
7359
7360 if (err) {
7361 ret = EXIT_FAILURE;
7362 goto dl_fini;
7363 }
7364
7365 ret = EXIT_SUCCESS;
7366
7367 dl_fini:
7368 dl_fini(dl);
7369 dl_free:
7370 dl_free(dl);
7371
7372 return ret;
7373 }