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