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