1 /*
2  * devlink.c	Devlink tool
3  *
4  *              This program is free software; you can redistribute it and/or
5  *              modify it under the terms of the GNU General Public License
6  *              as published by the Free Software Foundation; either version
7  *              2 of the License, or (at your option) any later version.
8  *
9  * Authors:     Jiri Pirko <jiri@mellanox.com>
10  */
11 
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <stdbool.h>
16 #include <unistd.h>
17 #include <getopt.h>
18 #include <limits.h>
19 #include <errno.h>
20 #include <linux/genetlink.h>
21 #include <linux/devlink.h>
22 #include <libmnl/libmnl.h>
23 #include <netinet/ether.h>
24 
25 #include "SNAPSHOT.h"
26 #include "list.h"
27 #include "mnlg.h"
28 #include "json_writer.h"
29 #include "utils.h"
30 
31 #define ESWITCH_MODE_LEGACY "legacy"
32 #define ESWITCH_MODE_SWITCHDEV "switchdev"
33 #define ESWITCH_INLINE_MODE_NONE "none"
34 #define ESWITCH_INLINE_MODE_LINK "link"
35 #define ESWITCH_INLINE_MODE_NETWORK "network"
36 #define ESWITCH_INLINE_MODE_TRANSPORT "transport"
37 
38 #define pr_err(args...) fprintf(stderr, ##args)
39 #define pr_out(args...)						\
40 	do {							\
41 		if (g_indent_newline) {				\
42 			fprintf(stdout, "%s", g_indent_str);	\
43 			g_indent_newline = false;		\
44 		}						\
45 		fprintf(stdout, ##args);			\
46 	} while (0)
47 
48 #define pr_out_sp(num, args...)					\
49 	do {							\
50 		int ret = fprintf(stdout, ##args);		\
51 		if (ret < num)					\
52 			fprintf(stdout, "%*s", num - ret, "");	\
53 	} while (0)
54 
55 static int g_indent_level;
56 static bool g_indent_newline;
57 #define INDENT_STR_STEP 2
58 #define INDENT_STR_MAXLEN 32
59 static char g_indent_str[INDENT_STR_MAXLEN + 1] = "";
60 
__pr_out_indent_inc(void)61 static void __pr_out_indent_inc(void)
62 {
63 	if (g_indent_level + INDENT_STR_STEP > INDENT_STR_MAXLEN)
64 		return;
65 	g_indent_level += INDENT_STR_STEP;
66 	memset(g_indent_str, ' ', sizeof(g_indent_str));
67 	g_indent_str[g_indent_level] = '\0';
68 }
69 
__pr_out_indent_dec(void)70 static void __pr_out_indent_dec(void)
71 {
72 	if (g_indent_level - INDENT_STR_STEP < 0)
73 		return;
74 	g_indent_level -= INDENT_STR_STEP;
75 	g_indent_str[g_indent_level] = '\0';
76 }
77 
__pr_out_newline(void)78 static void __pr_out_newline(void)
79 {
80 	pr_out("\n");
81 	g_indent_newline = true;
82 }
83 
_mnlg_socket_recv_run(struct mnlg_socket * nlg,mnl_cb_t data_cb,void * data)84 static int _mnlg_socket_recv_run(struct mnlg_socket *nlg,
85 				 mnl_cb_t data_cb, void *data)
86 {
87 	int err;
88 
89 	err = mnlg_socket_recv_run(nlg, data_cb, data);
90 	if (err < 0) {
91 		pr_err("devlink answers: %s\n", strerror(errno));
92 		return -errno;
93 	}
94 	return 0;
95 }
96 
_mnlg_socket_sndrcv(struct mnlg_socket * nlg,const struct nlmsghdr * nlh,mnl_cb_t data_cb,void * data)97 static int _mnlg_socket_sndrcv(struct mnlg_socket *nlg,
98 			       const struct nlmsghdr *nlh,
99 			       mnl_cb_t data_cb, void *data)
100 {
101 	int err;
102 
103 	err = mnlg_socket_send(nlg, nlh);
104 	if (err < 0) {
105 		pr_err("Failed to call mnlg_socket_send\n");
106 		return -errno;
107 	}
108 	return _mnlg_socket_recv_run(nlg, data_cb, data);
109 }
110 
_mnlg_socket_group_add(struct mnlg_socket * nlg,const char * group_name)111 static int _mnlg_socket_group_add(struct mnlg_socket *nlg,
112 				  const char *group_name)
113 {
114 	int err;
115 
116 	err = mnlg_socket_group_add(nlg, group_name);
117 	if (err < 0) {
118 		pr_err("Failed to call mnlg_socket_group_add\n");
119 		return -errno;
120 	}
121 	return 0;
122 }
123 
124 struct ifname_map {
125 	struct list_head list;
126 	char *bus_name;
127 	char *dev_name;
128 	uint32_t port_index;
129 	char *ifname;
130 };
131 
ifname_map_alloc(const char * bus_name,const char * dev_name,uint32_t port_index,const char * ifname)132 static struct ifname_map *ifname_map_alloc(const char *bus_name,
133 					   const char *dev_name,
134 					   uint32_t port_index,
135 					   const char *ifname)
136 {
137 	struct ifname_map *ifname_map;
138 
139 	ifname_map = calloc(1, sizeof(*ifname_map));
140 	if (!ifname_map)
141 		return NULL;
142 	ifname_map->bus_name = strdup(bus_name);
143 	ifname_map->dev_name = strdup(dev_name);
144 	ifname_map->port_index = port_index;
145 	ifname_map->ifname = strdup(ifname);
146 	if (!ifname_map->bus_name || !ifname_map->dev_name ||
147 	    !ifname_map->ifname) {
148 		free(ifname_map->ifname);
149 		free(ifname_map->dev_name);
150 		free(ifname_map->bus_name);
151 		free(ifname_map);
152 		return NULL;
153 	}
154 	return ifname_map;
155 }
156 
ifname_map_free(struct ifname_map * ifname_map)157 static void ifname_map_free(struct ifname_map *ifname_map)
158 {
159 	free(ifname_map->ifname);
160 	free(ifname_map->dev_name);
161 	free(ifname_map->bus_name);
162 	free(ifname_map);
163 }
164 
165 #define DL_OPT_HANDLE		BIT(0)
166 #define DL_OPT_HANDLEP		BIT(1)
167 #define DL_OPT_PORT_TYPE	BIT(2)
168 #define DL_OPT_PORT_COUNT	BIT(3)
169 #define DL_OPT_SB		BIT(4)
170 #define DL_OPT_SB_POOL		BIT(5)
171 #define DL_OPT_SB_SIZE		BIT(6)
172 #define DL_OPT_SB_TYPE		BIT(7)
173 #define DL_OPT_SB_THTYPE	BIT(8)
174 #define DL_OPT_SB_TH		BIT(9)
175 #define DL_OPT_SB_TC		BIT(10)
176 #define DL_OPT_ESWITCH_MODE	BIT(11)
177 #define DL_OPT_ESWITCH_INLINE_MODE	BIT(12)
178 #define DL_OPT_DPIPE_TABLE_NAME	BIT(13)
179 #define DL_OPT_DPIPE_TABLE_COUNTERS	BIT(14)
180 #define DL_OPT_ESWITCH_ENCAP_MODE	BIT(15)
181 
182 struct dl_opts {
183 	uint32_t present; /* flags of present items */
184 	char *bus_name;
185 	char *dev_name;
186 	uint32_t port_index;
187 	enum devlink_port_type port_type;
188 	uint32_t port_count;
189 	uint32_t sb_index;
190 	uint16_t sb_pool_index;
191 	uint32_t sb_pool_size;
192 	enum devlink_sb_pool_type sb_pool_type;
193 	enum devlink_sb_threshold_type sb_pool_thtype;
194 	uint32_t sb_threshold;
195 	uint16_t sb_tc_index;
196 	enum devlink_eswitch_mode eswitch_mode;
197 	enum devlink_eswitch_inline_mode eswitch_inline_mode;
198 	const char *dpipe_table_name;
199 	bool dpipe_counters_enable;
200 	bool eswitch_encap_mode;
201 };
202 
203 struct dl {
204 	struct mnlg_socket *nlg;
205 	struct list_head ifname_map_list;
206 	int argc;
207 	char **argv;
208 	bool no_nice_names;
209 	struct dl_opts opts;
210 	json_writer_t *jw;
211 	bool json_output;
212 	bool pretty_output;
213 	bool verbose;
214 	struct {
215 		bool present;
216 		char *bus_name;
217 		char *dev_name;
218 		uint32_t port_index;
219 	} arr_last;
220 };
221 
dl_argc(struct dl * dl)222 static int dl_argc(struct dl *dl)
223 {
224 	return dl->argc;
225 }
226 
dl_argv(struct dl * dl)227 static char *dl_argv(struct dl *dl)
228 {
229 	if (dl_argc(dl) == 0)
230 		return NULL;
231 	return *dl->argv;
232 }
233 
dl_arg_inc(struct dl * dl)234 static void dl_arg_inc(struct dl *dl)
235 {
236 	if (dl_argc(dl) == 0)
237 		return;
238 	dl->argc--;
239 	dl->argv++;
240 }
241 
dl_argv_next(struct dl * dl)242 static char *dl_argv_next(struct dl *dl)
243 {
244 	char *ret;
245 
246 	if (dl_argc(dl) == 0)
247 		return NULL;
248 
249 	ret = *dl->argv;
250 	dl_arg_inc(dl);
251 	return ret;
252 }
253 
dl_argv_index(struct dl * dl,unsigned int index)254 static char *dl_argv_index(struct dl *dl, unsigned int index)
255 {
256 	if (index >= dl_argc(dl))
257 		return NULL;
258 	return dl->argv[index];
259 }
260 
strcmpx(const char * str1,const char * str2)261 static int strcmpx(const char *str1, const char *str2)
262 {
263 	if (strlen(str1) > strlen(str2))
264 		return -1;
265 	return strncmp(str1, str2, strlen(str1));
266 }
267 
dl_argv_match(struct dl * dl,const char * pattern)268 static bool dl_argv_match(struct dl *dl, const char *pattern)
269 {
270 	if (dl_argc(dl) == 0)
271 		return false;
272 	return strcmpx(dl_argv(dl), pattern) == 0;
273 }
274 
dl_no_arg(struct dl * dl)275 static bool dl_no_arg(struct dl *dl)
276 {
277 	return dl_argc(dl) == 0;
278 }
279 
280 static const enum mnl_attr_data_type devlink_policy[DEVLINK_ATTR_MAX + 1] = {
281 	[DEVLINK_ATTR_BUS_NAME] = MNL_TYPE_NUL_STRING,
282 	[DEVLINK_ATTR_DEV_NAME] = MNL_TYPE_NUL_STRING,
283 	[DEVLINK_ATTR_PORT_INDEX] = MNL_TYPE_U32,
284 	[DEVLINK_ATTR_PORT_TYPE] = MNL_TYPE_U16,
285 	[DEVLINK_ATTR_PORT_DESIRED_TYPE] = MNL_TYPE_U16,
286 	[DEVLINK_ATTR_PORT_NETDEV_IFINDEX] = MNL_TYPE_U32,
287 	[DEVLINK_ATTR_PORT_NETDEV_NAME] = MNL_TYPE_NUL_STRING,
288 	[DEVLINK_ATTR_PORT_IBDEV_NAME] = MNL_TYPE_NUL_STRING,
289 	[DEVLINK_ATTR_SB_INDEX] = MNL_TYPE_U32,
290 	[DEVLINK_ATTR_SB_SIZE] = MNL_TYPE_U32,
291 	[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] = MNL_TYPE_U16,
292 	[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] = MNL_TYPE_U16,
293 	[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] = MNL_TYPE_U16,
294 	[DEVLINK_ATTR_SB_EGRESS_TC_COUNT] = MNL_TYPE_U16,
295 	[DEVLINK_ATTR_SB_POOL_INDEX] = MNL_TYPE_U16,
296 	[DEVLINK_ATTR_SB_POOL_TYPE] = MNL_TYPE_U8,
297 	[DEVLINK_ATTR_SB_POOL_SIZE] = MNL_TYPE_U32,
298 	[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE] = MNL_TYPE_U8,
299 	[DEVLINK_ATTR_SB_THRESHOLD] = MNL_TYPE_U32,
300 	[DEVLINK_ATTR_SB_TC_INDEX] = MNL_TYPE_U16,
301 	[DEVLINK_ATTR_SB_OCC_CUR] = MNL_TYPE_U32,
302 	[DEVLINK_ATTR_SB_OCC_MAX] = MNL_TYPE_U32,
303 	[DEVLINK_ATTR_ESWITCH_MODE] = MNL_TYPE_U16,
304 	[DEVLINK_ATTR_ESWITCH_INLINE_MODE] = MNL_TYPE_U8,
305 	[DEVLINK_ATTR_ESWITCH_ENCAP_MODE] = MNL_TYPE_U8,
306 	[DEVLINK_ATTR_DPIPE_TABLES] = MNL_TYPE_NESTED,
307 	[DEVLINK_ATTR_DPIPE_TABLE] = MNL_TYPE_NESTED,
308 	[DEVLINK_ATTR_DPIPE_TABLE_NAME] = MNL_TYPE_STRING,
309 	[DEVLINK_ATTR_DPIPE_TABLE_SIZE] = MNL_TYPE_U64,
310 	[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] = MNL_TYPE_NESTED,
311 	[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] = MNL_TYPE_NESTED,
312 	[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED] =  MNL_TYPE_U8,
313 	[DEVLINK_ATTR_DPIPE_ENTRIES] = MNL_TYPE_NESTED,
314 	[DEVLINK_ATTR_DPIPE_ENTRY] = MNL_TYPE_NESTED,
315 	[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] = MNL_TYPE_U64,
316 	[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] = MNL_TYPE_NESTED,
317 	[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES] = MNL_TYPE_NESTED,
318 	[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER] = MNL_TYPE_U64,
319 	[DEVLINK_ATTR_DPIPE_MATCH] = MNL_TYPE_NESTED,
320 	[DEVLINK_ATTR_DPIPE_MATCH_VALUE] = MNL_TYPE_NESTED,
321 	[DEVLINK_ATTR_DPIPE_MATCH_TYPE] = MNL_TYPE_U32,
322 	[DEVLINK_ATTR_DPIPE_ACTION] = MNL_TYPE_NESTED,
323 	[DEVLINK_ATTR_DPIPE_ACTION_VALUE] = MNL_TYPE_NESTED,
324 	[DEVLINK_ATTR_DPIPE_ACTION_TYPE] = MNL_TYPE_U32,
325 	[DEVLINK_ATTR_DPIPE_VALUE_MAPPING] = MNL_TYPE_U32,
326 	[DEVLINK_ATTR_DPIPE_HEADERS] = MNL_TYPE_NESTED,
327 	[DEVLINK_ATTR_DPIPE_HEADER] = MNL_TYPE_NESTED,
328 	[DEVLINK_ATTR_DPIPE_HEADER_NAME] = MNL_TYPE_STRING,
329 	[DEVLINK_ATTR_DPIPE_HEADER_ID] = MNL_TYPE_U32,
330 	[DEVLINK_ATTR_DPIPE_HEADER_FIELDS] = MNL_TYPE_NESTED,
331 	[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL] = MNL_TYPE_U8,
332 	[DEVLINK_ATTR_DPIPE_HEADER_INDEX] = MNL_TYPE_U32,
333 	[DEVLINK_ATTR_DPIPE_FIELD] = MNL_TYPE_NESTED,
334 	[DEVLINK_ATTR_DPIPE_FIELD_NAME] = MNL_TYPE_STRING,
335 	[DEVLINK_ATTR_DPIPE_FIELD_ID] = MNL_TYPE_U32,
336 	[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] = MNL_TYPE_U32,
337 	[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE] = MNL_TYPE_U32,
338 };
339 
attr_cb(const struct nlattr * attr,void * data)340 static int attr_cb(const struct nlattr *attr, void *data)
341 {
342 	const struct nlattr **tb = data;
343 	int type;
344 
345 	if (mnl_attr_type_valid(attr, DEVLINK_ATTR_MAX) < 0)
346 		return MNL_CB_ERROR;
347 
348 	type = mnl_attr_get_type(attr);
349 	if (mnl_attr_validate(attr, devlink_policy[type]) < 0)
350 		return MNL_CB_ERROR;
351 
352 	tb[type] = attr;
353 	return MNL_CB_OK;
354 }
355 
ifname_map_cb(const struct nlmsghdr * nlh,void * data)356 static int ifname_map_cb(const struct nlmsghdr *nlh, void *data)
357 {
358 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
359 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
360 	struct dl *dl = data;
361 	struct ifname_map *ifname_map;
362 	const char *bus_name;
363 	const char *dev_name;
364 	uint32_t port_ifindex;
365 	const char *port_ifname;
366 
367 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
368 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
369 	    !tb[DEVLINK_ATTR_PORT_INDEX])
370 		return MNL_CB_ERROR;
371 
372 	if (!tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
373 		return MNL_CB_OK;
374 
375 	bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
376 	dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
377 	port_ifindex = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
378 	port_ifname = mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]);
379 	ifname_map = ifname_map_alloc(bus_name, dev_name,
380 				      port_ifindex, port_ifname);
381 	if (!ifname_map)
382 		return MNL_CB_ERROR;
383 	list_add(&ifname_map->list, &dl->ifname_map_list);
384 
385 	return MNL_CB_OK;
386 }
387 
ifname_map_fini(struct dl * dl)388 static void ifname_map_fini(struct dl *dl)
389 {
390 	struct ifname_map *ifname_map, *tmp;
391 
392 	list_for_each_entry_safe(ifname_map, tmp,
393 				 &dl->ifname_map_list, list) {
394 		list_del(&ifname_map->list);
395 		ifname_map_free(ifname_map);
396 	}
397 }
398 
ifname_map_init(struct dl * dl)399 static int ifname_map_init(struct dl *dl)
400 {
401 	struct nlmsghdr *nlh;
402 	int err;
403 
404 	INIT_LIST_HEAD(&dl->ifname_map_list);
405 
406 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET,
407 			       NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP);
408 
409 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, ifname_map_cb, dl);
410 	if (err) {
411 		ifname_map_fini(dl);
412 		return err;
413 	}
414 	return 0;
415 }
416 
ifname_map_lookup(struct dl * dl,const char * ifname,char ** p_bus_name,char ** p_dev_name,uint32_t * p_port_index)417 static int ifname_map_lookup(struct dl *dl, const char *ifname,
418 			     char **p_bus_name, char **p_dev_name,
419 			     uint32_t *p_port_index)
420 {
421 	struct ifname_map *ifname_map;
422 
423 	list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
424 		if (strcmp(ifname, ifname_map->ifname) == 0) {
425 			*p_bus_name = ifname_map->bus_name;
426 			*p_dev_name = ifname_map->dev_name;
427 			*p_port_index = ifname_map->port_index;
428 			return 0;
429 		}
430 	}
431 	return -ENOENT;
432 }
433 
ifname_map_rev_lookup(struct dl * dl,const char * bus_name,const char * dev_name,uint32_t port_index,char ** p_ifname)434 static int ifname_map_rev_lookup(struct dl *dl, const char *bus_name,
435 				 const char *dev_name, uint32_t port_index,
436 				 char **p_ifname)
437 {
438 	struct ifname_map *ifname_map;
439 
440 	list_for_each_entry(ifname_map, &dl->ifname_map_list, list) {
441 		if (strcmp(bus_name, ifname_map->bus_name) == 0 &&
442 		    strcmp(dev_name, ifname_map->dev_name) == 0 &&
443 		    port_index == ifname_map->port_index) {
444 			*p_ifname = ifname_map->ifname;
445 			return 0;
446 		}
447 	}
448 	return -ENOENT;
449 }
450 
strslashcount(char * str)451 static unsigned int strslashcount(char *str)
452 {
453 	unsigned int count = 0;
454 	char *pos = str;
455 
456 	while ((pos = strchr(pos, '/'))) {
457 		count++;
458 		pos++;
459 	}
460 	return count;
461 }
462 
strslashrsplit(char * str,char ** before,char ** after)463 static int strslashrsplit(char *str, char **before, char **after)
464 {
465 	char *slash;
466 
467 	slash = strrchr(str, '/');
468 	if (!slash)
469 		return -EINVAL;
470 	*slash = '\0';
471 	*before = str;
472 	*after = slash + 1;
473 	return 0;
474 }
475 
strtouint32_t(const char * str,uint32_t * p_val)476 static int strtouint32_t(const char *str, uint32_t *p_val)
477 {
478 	char *endptr;
479 	unsigned long int val;
480 
481 	val = strtoul(str, &endptr, 10);
482 	if (endptr == str || *endptr != '\0')
483 		return -EINVAL;
484 	if (val > UINT_MAX)
485 		return -ERANGE;
486 	*p_val = val;
487 	return 0;
488 }
489 
strtouint16_t(const char * str,uint16_t * p_val)490 static int strtouint16_t(const char *str, uint16_t *p_val)
491 {
492 	char *endptr;
493 	unsigned long int val;
494 
495 	val = strtoul(str, &endptr, 10);
496 	if (endptr == str || *endptr != '\0')
497 		return -EINVAL;
498 	if (val > USHRT_MAX)
499 		return -ERANGE;
500 	*p_val = val;
501 	return 0;
502 }
503 
__dl_argv_handle(char * str,char ** p_bus_name,char ** p_dev_name)504 static int __dl_argv_handle(char *str, char **p_bus_name, char **p_dev_name)
505 {
506 	strslashrsplit(str, p_bus_name, p_dev_name);
507 	return 0;
508 }
509 
dl_argv_handle(struct dl * dl,char ** p_bus_name,char ** p_dev_name)510 static int dl_argv_handle(struct dl *dl, char **p_bus_name, char **p_dev_name)
511 {
512 	char *str = dl_argv_next(dl);
513 
514 	if (!str) {
515 		pr_err("Devlink identification (\"bus_name/dev_name\") expected\n");
516 		return -EINVAL;
517 	}
518 	if (strslashcount(str) != 1) {
519 		pr_err("Wrong devlink identification string format.\n");
520 		pr_err("Expected \"bus_name/dev_name\".\n");
521 		return -EINVAL;
522 	}
523 	return __dl_argv_handle(str, p_bus_name, p_dev_name);
524 }
525 
__dl_argv_handle_port(char * str,char ** p_bus_name,char ** p_dev_name,uint32_t * p_port_index)526 static int __dl_argv_handle_port(char *str,
527 				 char **p_bus_name, char **p_dev_name,
528 				 uint32_t *p_port_index)
529 {
530 	char *handlestr;
531 	char *portstr;
532 	int err;
533 
534 	err = strslashrsplit(str, &handlestr, &portstr);
535 	if (err) {
536 		pr_err("Port identification \"%s\" is invalid\n", str);
537 		return err;
538 	}
539 	err = strtouint32_t(portstr, p_port_index);
540 	if (err) {
541 		pr_err("Port index \"%s\" is not a number or not within range\n",
542 		       portstr);
543 		return err;
544 	}
545 	err = strslashrsplit(handlestr, p_bus_name, p_dev_name);
546 	if (err) {
547 		pr_err("Port identification \"%s\" is invalid\n", str);
548 		return err;
549 	}
550 	return 0;
551 }
552 
__dl_argv_handle_port_ifname(struct dl * dl,char * str,char ** p_bus_name,char ** p_dev_name,uint32_t * p_port_index)553 static int __dl_argv_handle_port_ifname(struct dl *dl, char *str,
554 					char **p_bus_name, char **p_dev_name,
555 					uint32_t *p_port_index)
556 {
557 	int err;
558 
559 	err = ifname_map_lookup(dl, str, p_bus_name, p_dev_name,
560 				p_port_index);
561 	if (err) {
562 		pr_err("Netdevice \"%s\" not found\n", str);
563 		return err;
564 	}
565 	return 0;
566 }
567 
dl_argv_handle_port(struct dl * dl,char ** p_bus_name,char ** p_dev_name,uint32_t * p_port_index)568 static int dl_argv_handle_port(struct dl *dl, char **p_bus_name,
569 			       char **p_dev_name, uint32_t *p_port_index)
570 {
571 	char *str = dl_argv_next(dl);
572 	unsigned int slash_count;
573 
574 	if (!str) {
575 		pr_err("Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\") expected.\n");
576 		return -EINVAL;
577 	}
578 	slash_count = strslashcount(str);
579 	switch (slash_count) {
580 	case 0:
581 		return __dl_argv_handle_port_ifname(dl, str, p_bus_name,
582 						    p_dev_name, p_port_index);
583 	case 2:
584 		return __dl_argv_handle_port(str, p_bus_name,
585 					     p_dev_name, p_port_index);
586 	default:
587 		pr_err("Wrong port identification string format.\n");
588 		pr_err("Expected \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
589 		return -EINVAL;
590 	}
591 }
592 
dl_argv_handle_both(struct dl * dl,char ** p_bus_name,char ** p_dev_name,uint32_t * p_port_index,uint32_t * p_handle_bit)593 static int dl_argv_handle_both(struct dl *dl, char **p_bus_name,
594 			       char **p_dev_name, uint32_t *p_port_index,
595 			       uint32_t *p_handle_bit)
596 {
597 	char *str = dl_argv_next(dl);
598 	unsigned int slash_count;
599 	int err;
600 
601 	if (!str) {
602 		pr_err("One of following identifications expected:\n"
603 		       "Devlink identification (\"bus_name/dev_name\")\n"
604 		       "Port identification (\"bus_name/dev_name/port_index\" or \"netdev ifname\")\n");
605 		return -EINVAL;
606 	}
607 	slash_count = strslashcount(str);
608 	if (slash_count == 1) {
609 		err = __dl_argv_handle(str, p_bus_name, p_dev_name);
610 		if (err)
611 			return err;
612 		*p_handle_bit = DL_OPT_HANDLE;
613 	} else if (slash_count == 2) {
614 		err = __dl_argv_handle_port(str, p_bus_name,
615 					    p_dev_name, p_port_index);
616 		if (err)
617 			return err;
618 		*p_handle_bit = DL_OPT_HANDLEP;
619 	} else if (slash_count == 0) {
620 		err = __dl_argv_handle_port_ifname(dl, str, p_bus_name,
621 						   p_dev_name, p_port_index);
622 		if (err)
623 			return err;
624 		*p_handle_bit = DL_OPT_HANDLEP;
625 	} else {
626 		pr_err("Wrong port identification string format.\n");
627 		pr_err("Expected \"bus_name/dev_name\" or \"bus_name/dev_name/port_index\" or \"netdev_ifname\".\n");
628 		return -EINVAL;
629 	}
630 	return 0;
631 }
632 
dl_argv_uint32_t(struct dl * dl,uint32_t * p_val)633 static int dl_argv_uint32_t(struct dl *dl, uint32_t *p_val)
634 {
635 	char *str = dl_argv_next(dl);
636 	int err;
637 
638 	if (!str) {
639 		pr_err("Unsigned number argument expected\n");
640 		return -EINVAL;
641 	}
642 
643 	err = strtouint32_t(str, p_val);
644 	if (err) {
645 		pr_err("\"%s\" is not a number or not within range\n", str);
646 		return err;
647 	}
648 	return 0;
649 }
650 
dl_argv_uint16_t(struct dl * dl,uint16_t * p_val)651 static int dl_argv_uint16_t(struct dl *dl, uint16_t *p_val)
652 {
653 	char *str = dl_argv_next(dl);
654 	int err;
655 
656 	if (!str) {
657 		pr_err("Unsigned number argument expected\n");
658 		return -EINVAL;
659 	}
660 
661 	err = strtouint16_t(str, p_val);
662 	if (err) {
663 		pr_err("\"%s\" is not a number or not within range\n", str);
664 		return err;
665 	}
666 	return 0;
667 }
668 
dl_argv_str(struct dl * dl,const char ** p_str)669 static int dl_argv_str(struct dl *dl, const char **p_str)
670 {
671 	const char *str = dl_argv_next(dl);
672 
673 	if (!str) {
674 		pr_err("String parameter expected\n");
675 		return -EINVAL;
676 	}
677 	*p_str = str;
678 	return 0;
679 }
680 
port_type_get(const char * typestr,enum devlink_port_type * p_type)681 static int port_type_get(const char *typestr, enum devlink_port_type *p_type)
682 {
683 	if (strcmp(typestr, "auto") == 0) {
684 		*p_type = DEVLINK_PORT_TYPE_AUTO;
685 	} else if (strcmp(typestr, "eth") == 0) {
686 		*p_type = DEVLINK_PORT_TYPE_ETH;
687 	} else if (strcmp(typestr, "ib") == 0) {
688 		*p_type = DEVLINK_PORT_TYPE_IB;
689 	} else {
690 		pr_err("Unknown port type \"%s\"\n", typestr);
691 		return -EINVAL;
692 	}
693 	return 0;
694 }
695 
pool_type_get(const char * typestr,enum devlink_sb_pool_type * p_type)696 static int pool_type_get(const char *typestr, enum devlink_sb_pool_type *p_type)
697 {
698 	if (strcmp(typestr, "ingress") == 0) {
699 		*p_type = DEVLINK_SB_POOL_TYPE_INGRESS;
700 	} else if (strcmp(typestr, "egress") == 0) {
701 		*p_type = DEVLINK_SB_POOL_TYPE_EGRESS;
702 	} else {
703 		pr_err("Unknown pool type \"%s\"\n", typestr);
704 		return -EINVAL;
705 	}
706 	return 0;
707 }
708 
threshold_type_get(const char * typestr,enum devlink_sb_threshold_type * p_type)709 static int threshold_type_get(const char *typestr,
710 			      enum devlink_sb_threshold_type *p_type)
711 {
712 	if (strcmp(typestr, "static") == 0) {
713 		*p_type = DEVLINK_SB_THRESHOLD_TYPE_STATIC;
714 	} else if (strcmp(typestr, "dynamic") == 0) {
715 		*p_type = DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC;
716 	} else {
717 		pr_err("Unknown threshold type \"%s\"\n", typestr);
718 		return -EINVAL;
719 	}
720 	return 0;
721 }
722 
eswitch_mode_get(const char * typestr,enum devlink_eswitch_mode * p_mode)723 static int eswitch_mode_get(const char *typestr,
724 			    enum devlink_eswitch_mode *p_mode)
725 {
726 	if (strcmp(typestr, ESWITCH_MODE_LEGACY) == 0) {
727 		*p_mode = DEVLINK_ESWITCH_MODE_LEGACY;
728 	} else if (strcmp(typestr, ESWITCH_MODE_SWITCHDEV) == 0) {
729 		*p_mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
730 	} else {
731 		pr_err("Unknown eswitch mode \"%s\"\n", typestr);
732 		return -EINVAL;
733 	}
734 	return 0;
735 }
736 
eswitch_inline_mode_get(const char * typestr,enum devlink_eswitch_inline_mode * p_mode)737 static int eswitch_inline_mode_get(const char *typestr,
738 				   enum devlink_eswitch_inline_mode *p_mode)
739 {
740 	if (strcmp(typestr, ESWITCH_INLINE_MODE_NONE) == 0) {
741 		*p_mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
742 	} else if (strcmp(typestr, ESWITCH_INLINE_MODE_LINK) == 0) {
743 		*p_mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
744 	} else if (strcmp(typestr, ESWITCH_INLINE_MODE_NETWORK) == 0) {
745 		*p_mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
746 	} else if (strcmp(typestr, ESWITCH_INLINE_MODE_TRANSPORT) == 0) {
747 		*p_mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
748 	} else {
749 		pr_err("Unknown eswitch inline mode \"%s\"\n", typestr);
750 		return -EINVAL;
751 	}
752 	return 0;
753 }
754 
dpipe_counters_enable_get(const char * typestr,bool * counters_enable)755 static int dpipe_counters_enable_get(const char *typestr,
756 				     bool *counters_enable)
757 {
758 	if (strcmp(typestr, "enable") == 0) {
759 		*counters_enable = 1;
760 	} else if (strcmp(typestr, "disable") == 0) {
761 		*counters_enable = 0;
762 	} else {
763 		pr_err("Unknown counter_state \"%s\"\n", typestr);
764 		return -EINVAL;
765 	}
766 	return 0;
767 }
768 
eswitch_encap_mode_get(const char * typestr,bool * p_mode)769 static int eswitch_encap_mode_get(const char *typestr, bool *p_mode)
770 {
771 	if (strcmp(typestr, "enable") == 0) {
772 		*p_mode = true;
773 	} else if (strcmp(typestr, "disable") == 0) {
774 		*p_mode = false;
775 	} else {
776 		pr_err("Unknown eswitch encap mode \"%s\"\n", typestr);
777 		return -EINVAL;
778 	}
779 	return 0;
780 }
781 
dl_argv_parse(struct dl * dl,uint32_t o_required,uint32_t o_optional)782 static int dl_argv_parse(struct dl *dl, uint32_t o_required,
783 			 uint32_t o_optional)
784 {
785 	struct dl_opts *opts = &dl->opts;
786 	uint32_t o_all = o_required | o_optional;
787 	uint32_t o_found = 0;
788 	int err;
789 
790 	if (o_required & DL_OPT_HANDLE && o_required & DL_OPT_HANDLEP) {
791 		uint32_t handle_bit;
792 
793 		err = dl_argv_handle_both(dl, &opts->bus_name, &opts->dev_name,
794 					  &opts->port_index, &handle_bit);
795 		if (err)
796 			return err;
797 		o_found |= handle_bit;
798 	} else if (o_required & DL_OPT_HANDLE) {
799 		err = dl_argv_handle(dl, &opts->bus_name, &opts->dev_name);
800 		if (err)
801 			return err;
802 		o_found |= DL_OPT_HANDLE;
803 	} else if (o_required & DL_OPT_HANDLEP) {
804 		err = dl_argv_handle_port(dl, &opts->bus_name, &opts->dev_name,
805 					  &opts->port_index);
806 		if (err)
807 			return err;
808 		o_found |= DL_OPT_HANDLEP;
809 	}
810 
811 	while (dl_argc(dl)) {
812 		if (dl_argv_match(dl, "type") &&
813 		    (o_all & DL_OPT_PORT_TYPE)) {
814 			const char *typestr;
815 
816 			dl_arg_inc(dl);
817 			err = dl_argv_str(dl, &typestr);
818 			if (err)
819 				return err;
820 			err = port_type_get(typestr, &opts->port_type);
821 			if (err)
822 				return err;
823 			o_found |= DL_OPT_PORT_TYPE;
824 		} else if (dl_argv_match(dl, "count") &&
825 			   (o_all & DL_OPT_PORT_COUNT)) {
826 			dl_arg_inc(dl);
827 			err = dl_argv_uint32_t(dl, &opts->port_count);
828 			if (err)
829 				return err;
830 			o_found |= DL_OPT_PORT_COUNT;
831 		} else if (dl_argv_match(dl, "sb") &&
832 			   (o_all & DL_OPT_SB)) {
833 			dl_arg_inc(dl);
834 			err = dl_argv_uint32_t(dl, &opts->sb_index);
835 			if (err)
836 				return err;
837 			o_found |= DL_OPT_SB;
838 		} else if (dl_argv_match(dl, "pool") &&
839 			   (o_all & DL_OPT_SB_POOL)) {
840 			dl_arg_inc(dl);
841 			err = dl_argv_uint16_t(dl, &opts->sb_pool_index);
842 			if (err)
843 				return err;
844 			o_found |= DL_OPT_SB_POOL;
845 		} else if (dl_argv_match(dl, "size") &&
846 			   (o_all & DL_OPT_SB_SIZE)) {
847 			dl_arg_inc(dl);
848 			err = dl_argv_uint32_t(dl, &opts->sb_pool_size);
849 			if (err)
850 				return err;
851 			o_found |= DL_OPT_SB_SIZE;
852 		} else if (dl_argv_match(dl, "type") &&
853 			   (o_all & DL_OPT_SB_TYPE)) {
854 			const char *typestr;
855 
856 			dl_arg_inc(dl);
857 			err = dl_argv_str(dl, &typestr);
858 			if (err)
859 				return err;
860 			err = pool_type_get(typestr, &opts->sb_pool_type);
861 			if (err)
862 				return err;
863 			o_found |= DL_OPT_SB_TYPE;
864 		} else if (dl_argv_match(dl, "thtype") &&
865 			   (o_all & DL_OPT_SB_THTYPE)) {
866 			const char *typestr;
867 
868 			dl_arg_inc(dl);
869 			err = dl_argv_str(dl, &typestr);
870 			if (err)
871 				return err;
872 			err = threshold_type_get(typestr,
873 						 &opts->sb_pool_thtype);
874 			if (err)
875 				return err;
876 			o_found |= DL_OPT_SB_THTYPE;
877 		} else if (dl_argv_match(dl, "th") &&
878 			   (o_all & DL_OPT_SB_TH)) {
879 			dl_arg_inc(dl);
880 			err = dl_argv_uint32_t(dl, &opts->sb_threshold);
881 			if (err)
882 				return err;
883 			o_found |= DL_OPT_SB_TH;
884 		} else if (dl_argv_match(dl, "tc") &&
885 			   (o_all & DL_OPT_SB_TC)) {
886 			dl_arg_inc(dl);
887 			err = dl_argv_uint16_t(dl, &opts->sb_tc_index);
888 			if (err)
889 				return err;
890 			o_found |= DL_OPT_SB_TC;
891 		} else if (dl_argv_match(dl, "mode") &&
892 			   (o_all & DL_OPT_ESWITCH_MODE)) {
893 			const char *typestr;
894 
895 			dl_arg_inc(dl);
896 			err = dl_argv_str(dl, &typestr);
897 			if (err)
898 				return err;
899 			err = eswitch_mode_get(typestr, &opts->eswitch_mode);
900 			if (err)
901 				return err;
902 			o_found |= DL_OPT_ESWITCH_MODE;
903 		} else if (dl_argv_match(dl, "inline-mode") &&
904 			   (o_all & DL_OPT_ESWITCH_INLINE_MODE)) {
905 			const char *typestr;
906 
907 			dl_arg_inc(dl);
908 			err = dl_argv_str(dl, &typestr);
909 			if (err)
910 				return err;
911 			err = eswitch_inline_mode_get(
912 				typestr, &opts->eswitch_inline_mode);
913 			if (err)
914 				return err;
915 			o_found |= DL_OPT_ESWITCH_INLINE_MODE;
916 		} else if (dl_argv_match(dl, "name") &&
917 			   (o_all & DL_OPT_DPIPE_TABLE_NAME)) {
918 			dl_arg_inc(dl);
919 			err = dl_argv_str(dl, &opts->dpipe_table_name);
920 			if (err)
921 				return err;
922 			o_found |= DL_OPT_DPIPE_TABLE_NAME;
923 		} else if (dl_argv_match(dl, "counters") &&
924 			   (o_all & DL_OPT_DPIPE_TABLE_COUNTERS)) {
925 			const char *typestr;
926 
927 			dl_arg_inc(dl);
928 			err = dl_argv_str(dl, &typestr);
929 			if (err)
930 				return err;
931 			err = dpipe_counters_enable_get(typestr,
932 							&opts->dpipe_counters_enable);
933 			if (err)
934 				return err;
935 			o_found |= DL_OPT_DPIPE_TABLE_COUNTERS;
936 		} else if (dl_argv_match(dl, "encap") &&
937 			   (o_all & DL_OPT_ESWITCH_ENCAP_MODE)) {
938 			const char *typestr;
939 
940 			dl_arg_inc(dl);
941 			err = dl_argv_str(dl, &typestr);
942 			if (err)
943 				return err;
944 			err = eswitch_encap_mode_get(typestr,
945 						     &opts->eswitch_encap_mode);
946 			if (err)
947 				return err;
948 			o_found |= DL_OPT_ESWITCH_ENCAP_MODE;
949 		} else {
950 			pr_err("Unknown option \"%s\"\n", dl_argv(dl));
951 			return -EINVAL;
952 		}
953 	}
954 
955 	opts->present = o_found;
956 
957 	if ((o_optional & DL_OPT_SB) && !(o_found & DL_OPT_SB)) {
958 		opts->sb_index = 0;
959 		opts->present |= DL_OPT_SB;
960 	}
961 
962 	if ((o_required & DL_OPT_PORT_TYPE) && !(o_found & DL_OPT_PORT_TYPE)) {
963 		pr_err("Port type option expected.\n");
964 		return -EINVAL;
965 	}
966 
967 	if ((o_required & DL_OPT_PORT_COUNT) &&
968 	    !(o_found & DL_OPT_PORT_COUNT)) {
969 		pr_err("Port split count option expected.\n");
970 		return -EINVAL;
971 	}
972 
973 	if ((o_required & DL_OPT_SB_POOL) && !(o_found & DL_OPT_SB_POOL)) {
974 		pr_err("Pool index option expected.\n");
975 		return -EINVAL;
976 	}
977 
978 	if ((o_required & DL_OPT_SB_SIZE) && !(o_found & DL_OPT_SB_SIZE)) {
979 		pr_err("Pool size option expected.\n");
980 		return -EINVAL;
981 	}
982 
983 	if ((o_required & DL_OPT_SB_TYPE) && !(o_found & DL_OPT_SB_TYPE)) {
984 		pr_err("Pool type option expected.\n");
985 		return -EINVAL;
986 	}
987 
988 	if ((o_required & DL_OPT_SB_THTYPE) && !(o_found & DL_OPT_SB_THTYPE)) {
989 		pr_err("Pool threshold type option expected.\n");
990 		return -EINVAL;
991 	}
992 
993 	if ((o_required & DL_OPT_SB_TH) && !(o_found & DL_OPT_SB_TH)) {
994 		pr_err("Threshold option expected.\n");
995 		return -EINVAL;
996 	}
997 
998 	if ((o_required & DL_OPT_SB_TC) && !(o_found & DL_OPT_SB_TC)) {
999 		pr_err("TC index option expected.\n");
1000 		return -EINVAL;
1001 	}
1002 
1003 	if ((o_required & DL_OPT_ESWITCH_MODE) &&
1004 	    !(o_found & DL_OPT_ESWITCH_MODE)) {
1005 		pr_err("E-Switch mode option expected.\n");
1006 		return -EINVAL;
1007 	}
1008 
1009 	if ((o_required & DL_OPT_ESWITCH_INLINE_MODE) &&
1010 	    !(o_found & DL_OPT_ESWITCH_INLINE_MODE)) {
1011 		pr_err("E-Switch inline-mode option expected.\n");
1012 		return -EINVAL;
1013 	}
1014 
1015 	if ((o_required & DL_OPT_DPIPE_TABLE_NAME) &&
1016 	    !(o_found & DL_OPT_DPIPE_TABLE_NAME)) {
1017 		pr_err("Dpipe table name expected\n");
1018 		return -EINVAL;
1019 	}
1020 
1021 	if ((o_required & DL_OPT_DPIPE_TABLE_COUNTERS) &&
1022 	    !(o_found & DL_OPT_DPIPE_TABLE_COUNTERS)) {
1023 		pr_err("Dpipe table counter state expected\n");
1024 		return -EINVAL;
1025 	}
1026 
1027 	if ((o_required & DL_OPT_ESWITCH_ENCAP_MODE) &&
1028 	    !(o_found & DL_OPT_ESWITCH_ENCAP_MODE)) {
1029 		pr_err("E-Switch encapsulation option expected.\n");
1030 		return -EINVAL;
1031 	}
1032 
1033 	return 0;
1034 }
1035 
dl_opts_put(struct nlmsghdr * nlh,struct dl * dl)1036 static void dl_opts_put(struct nlmsghdr *nlh, struct dl *dl)
1037 {
1038 	struct dl_opts *opts = &dl->opts;
1039 
1040 	if (opts->present & DL_OPT_HANDLE) {
1041 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1042 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1043 	} else if (opts->present & DL_OPT_HANDLEP) {
1044 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_BUS_NAME, opts->bus_name);
1045 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_DEV_NAME, opts->dev_name);
1046 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_INDEX,
1047 				 opts->port_index);
1048 	}
1049 	if (opts->present & DL_OPT_PORT_TYPE)
1050 		mnl_attr_put_u16(nlh, DEVLINK_ATTR_PORT_TYPE,
1051 				 opts->port_type);
1052 	if (opts->present & DL_OPT_PORT_COUNT)
1053 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_PORT_SPLIT_COUNT,
1054 				 opts->port_count);
1055 	if (opts->present & DL_OPT_SB)
1056 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_INDEX,
1057 				 opts->sb_index);
1058 	if (opts->present & DL_OPT_SB_POOL)
1059 		mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_POOL_INDEX,
1060 				 opts->sb_pool_index);
1061 	if (opts->present & DL_OPT_SB_SIZE)
1062 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_POOL_SIZE,
1063 				 opts->sb_pool_size);
1064 	if (opts->present & DL_OPT_SB_TYPE)
1065 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_TYPE,
1066 				opts->sb_pool_type);
1067 	if (opts->present & DL_OPT_SB_THTYPE)
1068 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE,
1069 				opts->sb_pool_thtype);
1070 	if (opts->present & DL_OPT_SB_TH)
1071 		mnl_attr_put_u32(nlh, DEVLINK_ATTR_SB_THRESHOLD,
1072 				 opts->sb_threshold);
1073 	if (opts->present & DL_OPT_SB_TC)
1074 		mnl_attr_put_u16(nlh, DEVLINK_ATTR_SB_TC_INDEX,
1075 				 opts->sb_tc_index);
1076 	if (opts->present & DL_OPT_ESWITCH_MODE)
1077 		mnl_attr_put_u16(nlh, DEVLINK_ATTR_ESWITCH_MODE,
1078 				 opts->eswitch_mode);
1079 	if (opts->present & DL_OPT_ESWITCH_INLINE_MODE)
1080 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_INLINE_MODE,
1081 				opts->eswitch_inline_mode);
1082 	if (opts->present & DL_OPT_DPIPE_TABLE_NAME)
1083 		mnl_attr_put_strz(nlh, DEVLINK_ATTR_DPIPE_TABLE_NAME,
1084 				  opts->dpipe_table_name);
1085 	if (opts->present & DL_OPT_DPIPE_TABLE_COUNTERS)
1086 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED,
1087 				opts->dpipe_counters_enable);
1088 	if (opts->present & DL_OPT_ESWITCH_ENCAP_MODE)
1089 		mnl_attr_put_u8(nlh, DEVLINK_ATTR_ESWITCH_ENCAP_MODE,
1090 				opts->eswitch_encap_mode);
1091 }
1092 
dl_argv_parse_put(struct nlmsghdr * nlh,struct dl * dl,uint32_t o_required,uint32_t o_optional)1093 static int dl_argv_parse_put(struct nlmsghdr *nlh, struct dl *dl,
1094 			     uint32_t o_required, uint32_t o_optional)
1095 {
1096 	int err;
1097 
1098 	err = dl_argv_parse(dl, o_required, o_optional);
1099 	if (err)
1100 		return err;
1101 	dl_opts_put(nlh, dl);
1102 	return 0;
1103 }
1104 
dl_dump_filter(struct dl * dl,struct nlattr ** tb)1105 static bool dl_dump_filter(struct dl *dl, struct nlattr **tb)
1106 {
1107 	struct dl_opts *opts = &dl->opts;
1108 	struct nlattr *attr_bus_name = tb[DEVLINK_ATTR_BUS_NAME];
1109 	struct nlattr *attr_dev_name = tb[DEVLINK_ATTR_DEV_NAME];
1110 	struct nlattr *attr_port_index = tb[DEVLINK_ATTR_PORT_INDEX];
1111 	struct nlattr *attr_sb_index = tb[DEVLINK_ATTR_SB_INDEX];
1112 
1113 	if (opts->present & DL_OPT_HANDLE &&
1114 	    attr_bus_name && attr_dev_name) {
1115 		const char *bus_name = mnl_attr_get_str(attr_bus_name);
1116 		const char *dev_name = mnl_attr_get_str(attr_dev_name);
1117 
1118 		if (strcmp(bus_name, opts->bus_name) != 0 ||
1119 		    strcmp(dev_name, opts->dev_name) != 0)
1120 			return false;
1121 	}
1122 	if (opts->present & DL_OPT_HANDLEP &&
1123 	    attr_bus_name && attr_dev_name && attr_port_index) {
1124 		const char *bus_name = mnl_attr_get_str(attr_bus_name);
1125 		const char *dev_name = mnl_attr_get_str(attr_dev_name);
1126 		uint32_t port_index = mnl_attr_get_u32(attr_port_index);
1127 
1128 		if (strcmp(bus_name, opts->bus_name) != 0 ||
1129 		    strcmp(dev_name, opts->dev_name) != 0 ||
1130 		    port_index != opts->port_index)
1131 			return false;
1132 	}
1133 	if (opts->present & DL_OPT_SB && attr_sb_index) {
1134 		uint32_t sb_index = mnl_attr_get_u32(attr_sb_index);
1135 
1136 		if (sb_index != opts->sb_index)
1137 			return false;
1138 	}
1139 	return true;
1140 }
1141 
cmd_dev_help(void)1142 static void cmd_dev_help(void)
1143 {
1144 	pr_err("Usage: devlink dev show [ DEV ]\n");
1145 	pr_err("       devlink dev eswitch set DEV [ mode { legacy | switchdev } ]\n");
1146 	pr_err("                               [ inline-mode { none | link | network | transport } ]\n");
1147 	pr_err("                               [ encap { disable | enable } ]\n");
1148 	pr_err("       devlink dev eswitch show DEV\n");
1149 }
1150 
cmp_arr_last_handle(struct dl * dl,const char * bus_name,const char * dev_name)1151 static bool cmp_arr_last_handle(struct dl *dl, const char *bus_name,
1152 				const char *dev_name)
1153 {
1154 	if (!dl->arr_last.present)
1155 		return false;
1156 	return strcmp(dl->arr_last.bus_name, bus_name) == 0 &&
1157 	       strcmp(dl->arr_last.dev_name, dev_name) == 0;
1158 }
1159 
arr_last_handle_set(struct dl * dl,const char * bus_name,const char * dev_name)1160 static void arr_last_handle_set(struct dl *dl, const char *bus_name,
1161 				const char *dev_name)
1162 {
1163 	dl->arr_last.present = true;
1164 	free(dl->arr_last.dev_name);
1165 	free(dl->arr_last.bus_name);
1166 	dl->arr_last.bus_name = strdup(bus_name);
1167 	dl->arr_last.dev_name = strdup(dev_name);
1168 }
1169 
should_arr_last_handle_start(struct dl * dl,const char * bus_name,const char * dev_name)1170 static bool should_arr_last_handle_start(struct dl *dl, const char *bus_name,
1171 					 const char *dev_name)
1172 {
1173 	return !cmp_arr_last_handle(dl, bus_name, dev_name);
1174 }
1175 
should_arr_last_handle_end(struct dl * dl,const char * bus_name,const char * dev_name)1176 static bool should_arr_last_handle_end(struct dl *dl, const char *bus_name,
1177 				       const char *dev_name)
1178 {
1179 	return dl->arr_last.present &&
1180 	       !cmp_arr_last_handle(dl, bus_name, dev_name);
1181 }
1182 
__pr_out_handle_start(struct dl * dl,struct nlattr ** tb,bool content,bool array)1183 static void __pr_out_handle_start(struct dl *dl, struct nlattr **tb,
1184 				  bool content, bool array)
1185 {
1186 	const char *bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1187 	const char *dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1188 	char buf[32];
1189 
1190 	sprintf(buf, "%s/%s", bus_name, dev_name);
1191 
1192 	if (dl->json_output) {
1193 		if (array) {
1194 			if (should_arr_last_handle_end(dl, bus_name, dev_name))
1195 				jsonw_end_array(dl->jw);
1196 			if (should_arr_last_handle_start(dl, bus_name,
1197 							 dev_name)) {
1198 				jsonw_name(dl->jw, buf);
1199 				jsonw_start_array(dl->jw);
1200 				jsonw_start_object(dl->jw);
1201 				arr_last_handle_set(dl, bus_name, dev_name);
1202 			} else {
1203 				jsonw_start_object(dl->jw);
1204 			}
1205 		} else {
1206 			jsonw_name(dl->jw, buf);
1207 			jsonw_start_object(dl->jw);
1208 		}
1209 	} else {
1210 		if (array) {
1211 			if (should_arr_last_handle_end(dl, bus_name, dev_name))
1212 				__pr_out_indent_dec();
1213 			if (should_arr_last_handle_start(dl, bus_name,
1214 							 dev_name)) {
1215 				pr_out("%s%s", buf, content ? ":" : "");
1216 				__pr_out_newline();
1217 				__pr_out_indent_inc();
1218 				arr_last_handle_set(dl, bus_name, dev_name);
1219 			}
1220 		} else {
1221 			pr_out("%s%s", buf, content ? ":" : "");
1222 		}
1223 	}
1224 }
1225 
pr_out_handle_start_arr(struct dl * dl,struct nlattr ** tb)1226 static void pr_out_handle_start_arr(struct dl *dl, struct nlattr **tb)
1227 {
1228 	__pr_out_handle_start(dl, tb, true, true);
1229 }
1230 
pr_out_handle_end(struct dl * dl)1231 static void pr_out_handle_end(struct dl *dl)
1232 {
1233 	if (dl->json_output)
1234 		jsonw_end_object(dl->jw);
1235 	else
1236 		__pr_out_newline();
1237 }
1238 
pr_out_handle(struct dl * dl,struct nlattr ** tb)1239 static void pr_out_handle(struct dl *dl, struct nlattr **tb)
1240 {
1241 	__pr_out_handle_start(dl, tb, false, false);
1242 	pr_out_handle_end(dl);
1243 }
1244 
cmp_arr_last_port_handle(struct dl * dl,const char * bus_name,const char * dev_name,uint32_t port_index)1245 static bool cmp_arr_last_port_handle(struct dl *dl, const char *bus_name,
1246 				     const char *dev_name, uint32_t port_index)
1247 {
1248 	return cmp_arr_last_handle(dl, bus_name, dev_name) &&
1249 	       dl->arr_last.port_index == port_index;
1250 }
1251 
arr_last_port_handle_set(struct dl * dl,const char * bus_name,const char * dev_name,uint32_t port_index)1252 static void arr_last_port_handle_set(struct dl *dl, const char *bus_name,
1253 				     const char *dev_name, uint32_t port_index)
1254 {
1255 	arr_last_handle_set(dl, bus_name, dev_name);
1256 	dl->arr_last.port_index = port_index;
1257 }
1258 
should_arr_last_port_handle_start(struct dl * dl,const char * bus_name,const char * dev_name,uint32_t port_index)1259 static bool should_arr_last_port_handle_start(struct dl *dl,
1260 					      const char *bus_name,
1261 					      const char *dev_name,
1262 					      uint32_t port_index)
1263 {
1264 	return !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
1265 }
1266 
should_arr_last_port_handle_end(struct dl * dl,const char * bus_name,const char * dev_name,uint32_t port_index)1267 static bool should_arr_last_port_handle_end(struct dl *dl,
1268 					    const char *bus_name,
1269 					    const char *dev_name,
1270 					    uint32_t port_index)
1271 {
1272 	return dl->arr_last.present &&
1273 	       !cmp_arr_last_port_handle(dl, bus_name, dev_name, port_index);
1274 }
1275 
__pr_out_port_handle_start(struct dl * dl,const char * bus_name,const char * dev_name,uint32_t port_index,bool try_nice,bool array)1276 static void __pr_out_port_handle_start(struct dl *dl, const char *bus_name,
1277 				       const char *dev_name,
1278 				       uint32_t port_index, bool try_nice,
1279 				       bool array)
1280 {
1281 	static char buf[32];
1282 	char *ifname = NULL;
1283 
1284 	if (dl->no_nice_names || !try_nice ||
1285 	    ifname_map_rev_lookup(dl, bus_name, dev_name,
1286 				  port_index, &ifname) != 0)
1287 		sprintf(buf, "%s/%s/%d", bus_name, dev_name, port_index);
1288 	else
1289 		sprintf(buf, "%s", ifname);
1290 
1291 	if (dl->json_output) {
1292 		if (array) {
1293 			if (should_arr_last_port_handle_end(dl, bus_name,
1294 							    dev_name,
1295 							    port_index))
1296 				jsonw_end_array(dl->jw);
1297 			if (should_arr_last_port_handle_start(dl, bus_name,
1298 							      dev_name,
1299 							      port_index)) {
1300 				jsonw_name(dl->jw, buf);
1301 				jsonw_start_array(dl->jw);
1302 				jsonw_start_object(dl->jw);
1303 				arr_last_port_handle_set(dl, bus_name, dev_name,
1304 							 port_index);
1305 			} else {
1306 				jsonw_start_object(dl->jw);
1307 			}
1308 		} else {
1309 			jsonw_name(dl->jw, buf);
1310 			jsonw_start_object(dl->jw);
1311 		}
1312 	} else {
1313 		pr_out("%s:", buf);
1314 	}
1315 }
1316 
pr_out_port_handle_start(struct dl * dl,struct nlattr ** tb,bool try_nice)1317 static void pr_out_port_handle_start(struct dl *dl, struct nlattr **tb, bool try_nice)
1318 {
1319 	const char *bus_name;
1320 	const char *dev_name;
1321 	uint32_t port_index;
1322 
1323 	bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1324 	dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1325 	port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
1326 	__pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, false);
1327 }
1328 
pr_out_port_handle_start_arr(struct dl * dl,struct nlattr ** tb,bool try_nice)1329 static void pr_out_port_handle_start_arr(struct dl *dl, struct nlattr **tb, bool try_nice)
1330 {
1331 	const char *bus_name;
1332 	const char *dev_name;
1333 	uint32_t port_index;
1334 
1335 	bus_name = mnl_attr_get_str(tb[DEVLINK_ATTR_BUS_NAME]);
1336 	dev_name = mnl_attr_get_str(tb[DEVLINK_ATTR_DEV_NAME]);
1337 	port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
1338 	__pr_out_port_handle_start(dl, bus_name, dev_name, port_index, try_nice, true);
1339 }
1340 
pr_out_port_handle_end(struct dl * dl)1341 static void pr_out_port_handle_end(struct dl *dl)
1342 {
1343 	if (dl->json_output)
1344 		jsonw_end_object(dl->jw);
1345 	else
1346 		pr_out("\n");
1347 }
1348 
1349 
pr_out_str(struct dl * dl,const char * name,const char * val)1350 static void pr_out_str(struct dl *dl, const char *name, const char *val)
1351 {
1352 	if (dl->json_output) {
1353 		jsonw_string_field(dl->jw, name, val);
1354 	} else {
1355 		if (g_indent_newline)
1356 			pr_out("%s %s", name, val);
1357 		else
1358 			pr_out(" %s %s", name, val);
1359 	}
1360 }
1361 
pr_out_uint(struct dl * dl,const char * name,unsigned int val)1362 static void pr_out_uint(struct dl *dl, const char *name, unsigned int val)
1363 {
1364 	if (dl->json_output) {
1365 		jsonw_uint_field(dl->jw, name, val);
1366 	} else {
1367 		if (g_indent_newline)
1368 			pr_out("%s %u", name, val);
1369 		else
1370 			pr_out(" %s %u", name, val);
1371 	}
1372 }
1373 
pr_out_dev(struct dl * dl,struct nlattr ** tb)1374 static void pr_out_dev(struct dl *dl, struct nlattr **tb)
1375 {
1376 	pr_out_handle(dl, tb);
1377 }
1378 
pr_out_section_start(struct dl * dl,const char * name)1379 static void pr_out_section_start(struct dl *dl, const char *name)
1380 {
1381 	if (dl->json_output) {
1382 		jsonw_start_object(dl->jw);
1383 		jsonw_name(dl->jw, name);
1384 		jsonw_start_object(dl->jw);
1385 	}
1386 }
1387 
pr_out_section_end(struct dl * dl)1388 static void pr_out_section_end(struct dl *dl)
1389 {
1390 	if (dl->json_output) {
1391 		if (dl->arr_last.present)
1392 			jsonw_end_array(dl->jw);
1393 		jsonw_end_object(dl->jw);
1394 		jsonw_end_object(dl->jw);
1395 	}
1396 }
1397 
pr_out_array_start(struct dl * dl,const char * name)1398 static void pr_out_array_start(struct dl *dl, const char *name)
1399 {
1400 	if (dl->json_output) {
1401 		jsonw_name(dl->jw, name);
1402 		jsonw_start_array(dl->jw);
1403 	} else {
1404 		if (!g_indent_newline)
1405 			__pr_out_newline();
1406 		pr_out("%s:", name);
1407 		__pr_out_newline();
1408 		__pr_out_indent_inc();
1409 	}
1410 }
1411 
pr_out_array_end(struct dl * dl)1412 static void pr_out_array_end(struct dl *dl)
1413 {
1414 	if (dl->json_output)
1415 		jsonw_end_array(dl->jw);
1416 	else
1417 		__pr_out_indent_dec();
1418 }
1419 
pr_out_entry_start(struct dl * dl)1420 static void pr_out_entry_start(struct dl *dl)
1421 {
1422 	if (dl->json_output)
1423 		jsonw_start_object(dl->jw);
1424 }
1425 
pr_out_entry_end(struct dl * dl)1426 static void pr_out_entry_end(struct dl *dl)
1427 {
1428 	if (dl->json_output)
1429 		jsonw_end_object(dl->jw);
1430 	else
1431 		__pr_out_newline();
1432 }
1433 
eswitch_mode_name(uint32_t mode)1434 static const char *eswitch_mode_name(uint32_t mode)
1435 {
1436 	switch (mode) {
1437 	case DEVLINK_ESWITCH_MODE_LEGACY: return ESWITCH_MODE_LEGACY;
1438 	case DEVLINK_ESWITCH_MODE_SWITCHDEV: return ESWITCH_MODE_SWITCHDEV;
1439 	default: return "<unknown mode>";
1440 	}
1441 }
1442 
eswitch_inline_mode_name(uint32_t mode)1443 static const char *eswitch_inline_mode_name(uint32_t mode)
1444 {
1445 	switch (mode) {
1446 	case DEVLINK_ESWITCH_INLINE_MODE_NONE:
1447 		return ESWITCH_INLINE_MODE_NONE;
1448 	case DEVLINK_ESWITCH_INLINE_MODE_LINK:
1449 		return ESWITCH_INLINE_MODE_LINK;
1450 	case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
1451 		return ESWITCH_INLINE_MODE_NETWORK;
1452 	case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
1453 		return ESWITCH_INLINE_MODE_TRANSPORT;
1454 	default:
1455 		return "<unknown mode>";
1456 	}
1457 }
1458 
pr_out_eswitch(struct dl * dl,struct nlattr ** tb)1459 static void pr_out_eswitch(struct dl *dl, struct nlattr **tb)
1460 {
1461 	__pr_out_handle_start(dl, tb, true, false);
1462 
1463 	if (tb[DEVLINK_ATTR_ESWITCH_MODE])
1464 		pr_out_str(dl, "mode",
1465 			   eswitch_mode_name(mnl_attr_get_u16(tb[DEVLINK_ATTR_ESWITCH_MODE])));
1466 
1467 	if (tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])
1468 		pr_out_str(dl, "inline-mode",
1469 			   eswitch_inline_mode_name(mnl_attr_get_u8(
1470 				   tb[DEVLINK_ATTR_ESWITCH_INLINE_MODE])));
1471 
1472 	if (tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]) {
1473 		bool encap_mode = !!mnl_attr_get_u8(tb[DEVLINK_ATTR_ESWITCH_ENCAP_MODE]);
1474 
1475 		pr_out_str(dl, "encap", encap_mode ? "enable" : "disable");
1476 	}
1477 
1478 	pr_out_handle_end(dl);
1479 }
1480 
cmd_dev_eswitch_show_cb(const struct nlmsghdr * nlh,void * data)1481 static int cmd_dev_eswitch_show_cb(const struct nlmsghdr *nlh, void *data)
1482 {
1483 	struct dl *dl = data;
1484 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1485 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1486 
1487 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1488 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
1489 		return MNL_CB_ERROR;
1490 	pr_out_eswitch(dl, tb);
1491 	return MNL_CB_OK;
1492 }
1493 
cmd_dev_eswitch_show(struct dl * dl)1494 static int cmd_dev_eswitch_show(struct dl *dl)
1495 {
1496 	struct nlmsghdr *nlh;
1497 	int err;
1498 
1499 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_GET,
1500 			       NLM_F_REQUEST | NLM_F_ACK);
1501 
1502 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
1503 	if (err)
1504 		return err;
1505 
1506 	pr_out_section_start(dl, "dev");
1507 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_eswitch_show_cb, dl);
1508 	pr_out_section_end(dl);
1509 	return err;
1510 }
1511 
cmd_dev_eswitch_set(struct dl * dl)1512 static int cmd_dev_eswitch_set(struct dl *dl)
1513 {
1514 	struct nlmsghdr *nlh;
1515 	int err;
1516 
1517 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_ESWITCH_SET,
1518 			       NLM_F_REQUEST | NLM_F_ACK);
1519 
1520 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE,
1521 				DL_OPT_ESWITCH_MODE |
1522 				DL_OPT_ESWITCH_INLINE_MODE |
1523 				DL_OPT_ESWITCH_ENCAP_MODE);
1524 
1525 	if (err)
1526 		return err;
1527 
1528 	if (dl->opts.present == 1) {
1529 		pr_err("Need to set at least one option\n");
1530 		return -ENOENT;
1531 	}
1532 
1533 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1534 }
1535 
cmd_dev_eswitch(struct dl * dl)1536 static int cmd_dev_eswitch(struct dl *dl)
1537 {
1538 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
1539 		cmd_dev_help();
1540 		return 0;
1541 	} else if (dl_argv_match(dl, "set")) {
1542 		dl_arg_inc(dl);
1543 		return cmd_dev_eswitch_set(dl);
1544 	} else if (dl_argv_match(dl, "show")) {
1545 		dl_arg_inc(dl);
1546 		return cmd_dev_eswitch_show(dl);
1547 	}
1548 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
1549 	return -ENOENT;
1550 }
1551 
cmd_dev_show_cb(const struct nlmsghdr * nlh,void * data)1552 static int cmd_dev_show_cb(const struct nlmsghdr *nlh, void *data)
1553 {
1554 	struct dl *dl = data;
1555 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1556 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1557 
1558 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1559 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
1560 		return MNL_CB_ERROR;
1561 	pr_out_dev(dl, tb);
1562 	return MNL_CB_OK;
1563 }
1564 
cmd_dev_show(struct dl * dl)1565 static int cmd_dev_show(struct dl *dl)
1566 {
1567 	struct nlmsghdr *nlh;
1568 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1569 	int err;
1570 
1571 	if (dl_argc(dl) == 0)
1572 		flags |= NLM_F_DUMP;
1573 
1574 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_GET, flags);
1575 
1576 	if (dl_argc(dl) > 0) {
1577 		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
1578 		if (err)
1579 			return err;
1580 	}
1581 
1582 	pr_out_section_start(dl, "dev");
1583 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dev_show_cb, dl);
1584 	pr_out_section_end(dl);
1585 	return err;
1586 }
1587 
cmd_dev(struct dl * dl)1588 static int cmd_dev(struct dl *dl)
1589 {
1590 	if (dl_argv_match(dl, "help")) {
1591 		cmd_dev_help();
1592 		return 0;
1593 	} else if (dl_argv_match(dl, "show") ||
1594 		   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1595 		dl_arg_inc(dl);
1596 		return cmd_dev_show(dl);
1597 	} else if (dl_argv_match(dl, "eswitch")) {
1598 		dl_arg_inc(dl);
1599 		return cmd_dev_eswitch(dl);
1600 	}
1601 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
1602 	return -ENOENT;
1603 }
1604 
cmd_port_help(void)1605 static void cmd_port_help(void)
1606 {
1607 	pr_err("Usage: devlink port show [ DEV/PORT_INDEX ]\n");
1608 	pr_err("       devlink port set DEV/PORT_INDEX [ type { eth | ib | auto} ]\n");
1609 	pr_err("       devlink port split DEV/PORT_INDEX count COUNT\n");
1610 	pr_err("       devlink port unsplit DEV/PORT_INDEX\n");
1611 }
1612 
port_type_name(uint32_t type)1613 static const char *port_type_name(uint32_t type)
1614 {
1615 	switch (type) {
1616 	case DEVLINK_PORT_TYPE_NOTSET: return "notset";
1617 	case DEVLINK_PORT_TYPE_AUTO: return "auto";
1618 	case DEVLINK_PORT_TYPE_ETH: return "eth";
1619 	case DEVLINK_PORT_TYPE_IB: return "ib";
1620 	default: return "<unknown type>";
1621 	}
1622 }
1623 
pr_out_port(struct dl * dl,struct nlattr ** tb)1624 static void pr_out_port(struct dl *dl, struct nlattr **tb)
1625 {
1626 	struct nlattr *pt_attr = tb[DEVLINK_ATTR_PORT_TYPE];
1627 	struct nlattr *dpt_attr = tb[DEVLINK_ATTR_PORT_DESIRED_TYPE];
1628 
1629 	pr_out_port_handle_start(dl, tb, false);
1630 	if (pt_attr) {
1631 		uint16_t port_type = mnl_attr_get_u16(pt_attr);
1632 
1633 		pr_out_str(dl, "type", port_type_name(port_type));
1634 		if (dpt_attr) {
1635 			uint16_t des_port_type = mnl_attr_get_u16(dpt_attr);
1636 
1637 			if (port_type != des_port_type)
1638 				pr_out_str(dl, "des_type",
1639 					   port_type_name(des_port_type));
1640 		}
1641 	}
1642 	if (tb[DEVLINK_ATTR_PORT_NETDEV_NAME])
1643 		pr_out_str(dl, "netdev",
1644 			   mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_NETDEV_NAME]));
1645 	if (tb[DEVLINK_ATTR_PORT_IBDEV_NAME])
1646 		pr_out_str(dl, "ibdev",
1647 			   mnl_attr_get_str(tb[DEVLINK_ATTR_PORT_IBDEV_NAME]));
1648 	if (tb[DEVLINK_ATTR_PORT_SPLIT_GROUP])
1649 		pr_out_uint(dl, "split_group",
1650 			    mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_SPLIT_GROUP]));
1651 	pr_out_port_handle_end(dl);
1652 }
1653 
cmd_port_show_cb(const struct nlmsghdr * nlh,void * data)1654 static int cmd_port_show_cb(const struct nlmsghdr *nlh, void *data)
1655 {
1656 	struct dl *dl = data;
1657 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1658 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1659 
1660 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1661 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1662 	    !tb[DEVLINK_ATTR_PORT_INDEX])
1663 		return MNL_CB_ERROR;
1664 	pr_out_port(dl, tb);
1665 	return MNL_CB_OK;
1666 }
1667 
cmd_port_show(struct dl * dl)1668 static int cmd_port_show(struct dl *dl)
1669 {
1670 	struct nlmsghdr *nlh;
1671 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1672 	int err;
1673 
1674 	if (dl_argc(dl) == 0)
1675 		flags |= NLM_F_DUMP;
1676 
1677 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_GET, flags);
1678 
1679 	if (dl_argc(dl) > 0) {
1680 		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1681 		if (err)
1682 			return err;
1683 	}
1684 
1685 	pr_out_section_start(dl, "port");
1686 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_port_show_cb, dl);
1687 	pr_out_section_end(dl);
1688 	return err;
1689 }
1690 
cmd_port_set(struct dl * dl)1691 static int cmd_port_set(struct dl *dl)
1692 {
1693 	struct nlmsghdr *nlh;
1694 	int err;
1695 
1696 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SET,
1697 			       NLM_F_REQUEST | NLM_F_ACK);
1698 
1699 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_TYPE, 0);
1700 	if (err)
1701 		return err;
1702 
1703 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1704 }
1705 
cmd_port_split(struct dl * dl)1706 static int cmd_port_split(struct dl *dl)
1707 {
1708 	struct nlmsghdr *nlh;
1709 	int err;
1710 
1711 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_SPLIT,
1712 			       NLM_F_REQUEST | NLM_F_ACK);
1713 
1714 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_PORT_COUNT, 0);
1715 	if (err)
1716 		return err;
1717 
1718 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1719 }
1720 
cmd_port_unsplit(struct dl * dl)1721 static int cmd_port_unsplit(struct dl *dl)
1722 {
1723 	struct nlmsghdr *nlh;
1724 	int err;
1725 
1726 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_PORT_UNSPLIT,
1727 			       NLM_F_REQUEST | NLM_F_ACK);
1728 
1729 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP, 0);
1730 	if (err)
1731 		return err;
1732 
1733 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1734 }
1735 
cmd_port(struct dl * dl)1736 static int cmd_port(struct dl *dl)
1737 {
1738 	if (dl_argv_match(dl, "help")) {
1739 		cmd_port_help();
1740 		return 0;
1741 	} else if (dl_argv_match(dl, "show") ||
1742 		   dl_argv_match(dl, "list") ||  dl_no_arg(dl)) {
1743 		dl_arg_inc(dl);
1744 		return cmd_port_show(dl);
1745 	} else if (dl_argv_match(dl, "set")) {
1746 		dl_arg_inc(dl);
1747 		return cmd_port_set(dl);
1748 	} else if (dl_argv_match(dl, "split")) {
1749 		dl_arg_inc(dl);
1750 		return cmd_port_split(dl);
1751 	} else if (dl_argv_match(dl, "unsplit")) {
1752 		dl_arg_inc(dl);
1753 		return cmd_port_unsplit(dl);
1754 	}
1755 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
1756 	return -ENOENT;
1757 }
1758 
cmd_sb_help(void)1759 static void cmd_sb_help(void)
1760 {
1761 	pr_err("Usage: devlink sb show [ DEV [ sb SB_INDEX ] ]\n");
1762 	pr_err("       devlink sb pool show [ DEV [ sb SB_INDEX ] pool POOL_INDEX ]\n");
1763 	pr_err("       devlink sb pool set DEV [ sb SB_INDEX ] pool POOL_INDEX\n");
1764 	pr_err("                           size POOL_SIZE thtype { static | dynamic }\n");
1765 	pr_err("       devlink sb port pool show [ DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1766 	pr_err("                                   pool POOL_INDEX ]\n");
1767 	pr_err("       devlink sb port pool set DEV/PORT_INDEX [ sb SB_INDEX ]\n");
1768 	pr_err("                                pool POOL_INDEX th THRESHOLD\n");
1769 	pr_err("       devlink sb tc bind show [ DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1770 	pr_err("                                 type { ingress | egress } ]\n");
1771 	pr_err("       devlink sb tc bind set DEV/PORT_INDEX [ sb SB_INDEX ] tc TC_INDEX\n");
1772 	pr_err("                              type { ingress | egress } pool POOL_INDEX\n");
1773 	pr_err("                              th THRESHOLD\n");
1774 	pr_err("       devlink sb occupancy show { DEV | DEV/PORT_INDEX } [ sb SB_INDEX ]\n");
1775 	pr_err("       devlink sb occupancy snapshot DEV [ sb SB_INDEX ]\n");
1776 	pr_err("       devlink sb occupancy clearmax DEV [ sb SB_INDEX ]\n");
1777 }
1778 
pr_out_sb(struct dl * dl,struct nlattr ** tb)1779 static void pr_out_sb(struct dl *dl, struct nlattr **tb)
1780 {
1781 	pr_out_handle_start_arr(dl, tb);
1782 	pr_out_uint(dl, "sb",
1783 		    mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1784 	pr_out_uint(dl, "size",
1785 		    mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_SIZE]));
1786 	pr_out_uint(dl, "ing_pools",
1787 		    mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT]));
1788 	pr_out_uint(dl, "eg_pools",
1789 		    mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT]));
1790 	pr_out_uint(dl, "ing_tcs",
1791 		    mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT]));
1792 	pr_out_uint(dl, "eg_tcs",
1793 		    mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT]));
1794 	pr_out_handle_end(dl);
1795 }
1796 
cmd_sb_show_cb(const struct nlmsghdr * nlh,void * data)1797 static int cmd_sb_show_cb(const struct nlmsghdr *nlh, void *data)
1798 {
1799 	struct dl *dl = data;
1800 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1801 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1802 
1803 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1804 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1805 	    !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_SIZE] ||
1806 	    !tb[DEVLINK_ATTR_SB_INGRESS_POOL_COUNT] ||
1807 	    !tb[DEVLINK_ATTR_SB_EGRESS_POOL_COUNT] ||
1808 	    !tb[DEVLINK_ATTR_SB_INGRESS_TC_COUNT] ||
1809 	    !tb[DEVLINK_ATTR_SB_EGRESS_TC_COUNT])
1810 		return MNL_CB_ERROR;
1811 	pr_out_sb(dl, tb);
1812 	return MNL_CB_OK;
1813 }
1814 
cmd_sb_show(struct dl * dl)1815 static int cmd_sb_show(struct dl *dl)
1816 {
1817 	struct nlmsghdr *nlh;
1818 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1819 	int err;
1820 
1821 	if (dl_argc(dl) == 0)
1822 		flags |= NLM_F_DUMP;
1823 
1824 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_GET, flags);
1825 
1826 	if (dl_argc(dl) > 0) {
1827 		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
1828 		if (err)
1829 			return err;
1830 	}
1831 
1832 	pr_out_section_start(dl, "sb");
1833 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_show_cb, dl);
1834 	pr_out_section_end(dl);
1835 	return err;
1836 }
1837 
pool_type_name(uint8_t type)1838 static const char *pool_type_name(uint8_t type)
1839 {
1840 	switch (type) {
1841 	case DEVLINK_SB_POOL_TYPE_INGRESS: return "ingress";
1842 	case DEVLINK_SB_POOL_TYPE_EGRESS: return "egress";
1843 	default: return "<unknown type>";
1844 	}
1845 }
1846 
threshold_type_name(uint8_t type)1847 static const char *threshold_type_name(uint8_t type)
1848 {
1849 	switch (type) {
1850 	case DEVLINK_SB_THRESHOLD_TYPE_STATIC: return "static";
1851 	case DEVLINK_SB_THRESHOLD_TYPE_DYNAMIC: return "dynamic";
1852 	default: return "<unknown type>";
1853 	}
1854 }
1855 
pr_out_sb_pool(struct dl * dl,struct nlattr ** tb)1856 static void pr_out_sb_pool(struct dl *dl, struct nlattr **tb)
1857 {
1858 	pr_out_handle_start_arr(dl, tb);
1859 	pr_out_uint(dl, "sb",
1860 		    mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1861 	pr_out_uint(dl, "pool",
1862 		    mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
1863 	pr_out_str(dl, "type",
1864 		   pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
1865 	pr_out_uint(dl, "size",
1866 		    mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_POOL_SIZE]));
1867 	pr_out_str(dl, "thtype",
1868 		   threshold_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])));
1869 	pr_out_handle_end(dl);
1870 }
1871 
cmd_sb_pool_show_cb(const struct nlmsghdr * nlh,void * data)1872 static int cmd_sb_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1873 {
1874 	struct dl *dl = data;
1875 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1876 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1877 
1878 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1879 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1880 	    !tb[DEVLINK_ATTR_SB_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
1881 	    !tb[DEVLINK_ATTR_SB_POOL_TYPE] || !tb[DEVLINK_ATTR_SB_POOL_SIZE] ||
1882 	    !tb[DEVLINK_ATTR_SB_POOL_THRESHOLD_TYPE])
1883 		return MNL_CB_ERROR;
1884 	pr_out_sb_pool(dl, tb);
1885 	return MNL_CB_OK;
1886 }
1887 
cmd_sb_pool_show(struct dl * dl)1888 static int cmd_sb_pool_show(struct dl *dl)
1889 {
1890 	struct nlmsghdr *nlh;
1891 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1892 	int err;
1893 
1894 	if (dl_argc(dl) == 0)
1895 		flags |= NLM_F_DUMP;
1896 
1897 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_GET, flags);
1898 
1899 	if (dl_argc(dl) > 0) {
1900 		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL,
1901 					DL_OPT_SB);
1902 		if (err)
1903 			return err;
1904 	}
1905 
1906 	pr_out_section_start(dl, "pool");
1907 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_pool_show_cb, dl);
1908 	pr_out_section_end(dl);
1909 	return err;
1910 }
1911 
cmd_sb_pool_set(struct dl * dl)1912 static int cmd_sb_pool_set(struct dl *dl)
1913 {
1914 	struct nlmsghdr *nlh;
1915 	int err;
1916 
1917 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_POOL_SET,
1918 			       NLM_F_REQUEST | NLM_F_ACK);
1919 
1920 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE | DL_OPT_SB_POOL |
1921 				DL_OPT_SB_SIZE | DL_OPT_SB_THTYPE, DL_OPT_SB);
1922 	if (err)
1923 		return err;
1924 
1925 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
1926 }
1927 
cmd_sb_pool(struct dl * dl)1928 static int cmd_sb_pool(struct dl *dl)
1929 {
1930 	if (dl_argv_match(dl, "help")) {
1931 		cmd_sb_help();
1932 		return 0;
1933 	} else if (dl_argv_match(dl, "show") ||
1934 		   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
1935 		dl_arg_inc(dl);
1936 		return cmd_sb_pool_show(dl);
1937 	} else if (dl_argv_match(dl, "set")) {
1938 		dl_arg_inc(dl);
1939 		return cmd_sb_pool_set(dl);
1940 	}
1941 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
1942 	return -ENOENT;
1943 }
1944 
pr_out_sb_port_pool(struct dl * dl,struct nlattr ** tb)1945 static void pr_out_sb_port_pool(struct dl *dl, struct nlattr **tb)
1946 {
1947 	pr_out_port_handle_start_arr(dl, tb, true);
1948 	pr_out_uint(dl, "sb",
1949 		    mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
1950 	pr_out_uint(dl, "pool",
1951 		    mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
1952 	pr_out_uint(dl, "threshold",
1953 		    mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
1954 	pr_out_port_handle_end(dl);
1955 }
1956 
cmd_sb_port_pool_show_cb(const struct nlmsghdr * nlh,void * data)1957 static int cmd_sb_port_pool_show_cb(const struct nlmsghdr *nlh, void *data)
1958 {
1959 	struct dl *dl = data;
1960 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
1961 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
1962 
1963 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
1964 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
1965 	    !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
1966 	    !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
1967 		return MNL_CB_ERROR;
1968 	pr_out_sb_port_pool(dl, tb);
1969 	return MNL_CB_OK;
1970 }
1971 
cmd_sb_port_pool_show(struct dl * dl)1972 static int cmd_sb_port_pool_show(struct dl *dl)
1973 {
1974 	struct nlmsghdr *nlh;
1975 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
1976 	int err;
1977 
1978 	if (dl_argc(dl) == 0)
1979 		flags |= NLM_F_DUMP;
1980 
1981 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
1982 
1983 	if (dl_argc(dl) > 0) {
1984 		err = dl_argv_parse_put(nlh, dl,
1985 					DL_OPT_HANDLEP | DL_OPT_SB_POOL,
1986 					DL_OPT_SB);
1987 		if (err)
1988 			return err;
1989 	}
1990 
1991 	pr_out_section_start(dl, "port_pool");
1992 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_port_pool_show_cb, dl);
1993 	pr_out_section_end(dl);
1994 	return 0;
1995 }
1996 
cmd_sb_port_pool_set(struct dl * dl)1997 static int cmd_sb_port_pool_set(struct dl *dl)
1998 {
1999 	struct nlmsghdr *nlh;
2000 	int err;
2001 
2002 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_SET,
2003 			       NLM_F_REQUEST | NLM_F_ACK);
2004 
2005 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_POOL |
2006 				DL_OPT_SB_TH, DL_OPT_SB);
2007 	if (err)
2008 		return err;
2009 
2010 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2011 }
2012 
cmd_sb_port_pool(struct dl * dl)2013 static int cmd_sb_port_pool(struct dl *dl)
2014 {
2015 	if (dl_argv_match(dl, "help")) {
2016 		cmd_sb_help();
2017 		return 0;
2018 	} else if (dl_argv_match(dl, "show") ||
2019 		   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2020 		dl_arg_inc(dl);
2021 		return cmd_sb_port_pool_show(dl);
2022 	} else if (dl_argv_match(dl, "set")) {
2023 		dl_arg_inc(dl);
2024 		return cmd_sb_port_pool_set(dl);
2025 	}
2026 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
2027 	return -ENOENT;
2028 }
2029 
cmd_sb_port(struct dl * dl)2030 static int cmd_sb_port(struct dl *dl)
2031 {
2032 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2033 		cmd_sb_help();
2034 		return 0;
2035 	} else if (dl_argv_match(dl, "pool")) {
2036 		dl_arg_inc(dl);
2037 		return cmd_sb_port_pool(dl);
2038 	}
2039 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
2040 	return -ENOENT;
2041 }
2042 
pr_out_sb_tc_bind(struct dl * dl,struct nlattr ** tb)2043 static void pr_out_sb_tc_bind(struct dl *dl, struct nlattr **tb)
2044 {
2045 	pr_out_port_handle_start_arr(dl, tb, true);
2046 	pr_out_uint(dl, "sb",
2047 	       mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_INDEX]));
2048 	pr_out_uint(dl, "tc",
2049 	       mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]));
2050 	pr_out_str(dl, "type",
2051 	       pool_type_name(mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE])));
2052 	pr_out_uint(dl, "pool",
2053 	       mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]));
2054 	pr_out_uint(dl, "threshold",
2055 	       mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_THRESHOLD]));
2056 	pr_out_port_handle_end(dl);
2057 }
2058 
cmd_sb_tc_bind_show_cb(const struct nlmsghdr * nlh,void * data)2059 static int cmd_sb_tc_bind_show_cb(const struct nlmsghdr *nlh, void *data)
2060 {
2061 	struct dl *dl = data;
2062 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2063 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2064 
2065 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2066 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2067 	    !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2068 	    !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
2069 	    !tb[DEVLINK_ATTR_SB_POOL_INDEX] || !tb[DEVLINK_ATTR_SB_THRESHOLD])
2070 		return MNL_CB_ERROR;
2071 	pr_out_sb_tc_bind(dl, tb);
2072 	return MNL_CB_OK;
2073 }
2074 
cmd_sb_tc_bind_show(struct dl * dl)2075 static int cmd_sb_tc_bind_show(struct dl *dl)
2076 {
2077 	struct nlmsghdr *nlh;
2078 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
2079 	int err;
2080 
2081 	if (dl_argc(dl) == 0)
2082 		flags |= NLM_F_DUMP;
2083 
2084 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
2085 
2086 	if (dl_argc(dl) > 0) {
2087 		err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
2088 					DL_OPT_SB_TYPE, DL_OPT_SB);
2089 		if (err)
2090 			return err;
2091 	}
2092 
2093 	pr_out_section_start(dl, "tc_bind");
2094 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_sb_tc_bind_show_cb, dl);
2095 	pr_out_section_end(dl);
2096 	return err;
2097 }
2098 
cmd_sb_tc_bind_set(struct dl * dl)2099 static int cmd_sb_tc_bind_set(struct dl *dl)
2100 {
2101 	struct nlmsghdr *nlh;
2102 	int err;
2103 
2104 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_SET,
2105 			       NLM_F_REQUEST | NLM_F_ACK);
2106 
2107 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLEP | DL_OPT_SB_TC |
2108 				DL_OPT_SB_TYPE | DL_OPT_SB_POOL | DL_OPT_SB_TH,
2109 				DL_OPT_SB);
2110 	if (err)
2111 		return err;
2112 
2113 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2114 }
2115 
cmd_sb_tc_bind(struct dl * dl)2116 static int cmd_sb_tc_bind(struct dl *dl)
2117 {
2118 	if (dl_argv_match(dl, "help")) {
2119 		cmd_sb_help();
2120 		return 0;
2121 	} else if (dl_argv_match(dl, "show") ||
2122 		   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2123 		dl_arg_inc(dl);
2124 		return cmd_sb_tc_bind_show(dl);
2125 	} else if (dl_argv_match(dl, "set")) {
2126 		dl_arg_inc(dl);
2127 		return cmd_sb_tc_bind_set(dl);
2128 	}
2129 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
2130 	return -ENOENT;
2131 }
2132 
cmd_sb_tc(struct dl * dl)2133 static int cmd_sb_tc(struct dl *dl)
2134 {
2135 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2136 		cmd_sb_help();
2137 		return 0;
2138 	} else if (dl_argv_match(dl, "bind")) {
2139 		dl_arg_inc(dl);
2140 		return cmd_sb_tc_bind(dl);
2141 	}
2142 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
2143 	return -ENOENT;
2144 }
2145 
2146 struct occ_item {
2147 	struct list_head list;
2148 	uint32_t index;
2149 	uint32_t cur;
2150 	uint32_t max;
2151 	uint32_t bound_pool_index;
2152 };
2153 
2154 struct occ_port {
2155 	struct list_head list;
2156 	char *bus_name;
2157 	char *dev_name;
2158 	uint32_t port_index;
2159 	uint32_t sb_index;
2160 	struct list_head pool_list;
2161 	struct list_head ing_tc_list;
2162 	struct list_head eg_tc_list;
2163 };
2164 
2165 struct occ_show {
2166 	struct dl *dl;
2167 	int err;
2168 	struct list_head port_list;
2169 };
2170 
occ_item_alloc(void)2171 static struct occ_item *occ_item_alloc(void)
2172 {
2173 	return calloc(1, sizeof(struct occ_item));
2174 }
2175 
occ_item_free(struct occ_item * occ_item)2176 static void occ_item_free(struct occ_item *occ_item)
2177 {
2178 	free(occ_item);
2179 }
2180 
occ_port_alloc(uint32_t port_index)2181 static struct occ_port *occ_port_alloc(uint32_t port_index)
2182 {
2183 	struct occ_port *occ_port;
2184 
2185 	occ_port = calloc(1, sizeof(*occ_port));
2186 	if (!occ_port)
2187 		return NULL;
2188 	occ_port->port_index = port_index;
2189 	INIT_LIST_HEAD(&occ_port->pool_list);
2190 	INIT_LIST_HEAD(&occ_port->ing_tc_list);
2191 	INIT_LIST_HEAD(&occ_port->eg_tc_list);
2192 	return occ_port;
2193 }
2194 
occ_port_free(struct occ_port * occ_port)2195 static void occ_port_free(struct occ_port *occ_port)
2196 {
2197 	struct occ_item *occ_item, *tmp;
2198 
2199 	list_for_each_entry_safe(occ_item, tmp, &occ_port->pool_list, list)
2200 		occ_item_free(occ_item);
2201 	list_for_each_entry_safe(occ_item, tmp, &occ_port->ing_tc_list, list)
2202 		occ_item_free(occ_item);
2203 	list_for_each_entry_safe(occ_item, tmp, &occ_port->eg_tc_list, list)
2204 		occ_item_free(occ_item);
2205 }
2206 
occ_show_alloc(struct dl * dl)2207 static struct occ_show *occ_show_alloc(struct dl *dl)
2208 {
2209 	struct occ_show *occ_show;
2210 
2211 	occ_show = calloc(1, sizeof(*occ_show));
2212 	if (!occ_show)
2213 		return NULL;
2214 	occ_show->dl = dl;
2215 	INIT_LIST_HEAD(&occ_show->port_list);
2216 	return occ_show;
2217 }
2218 
occ_show_free(struct occ_show * occ_show)2219 static void occ_show_free(struct occ_show *occ_show)
2220 {
2221 	struct occ_port *occ_port, *tmp;
2222 
2223 	list_for_each_entry_safe(occ_port, tmp, &occ_show->port_list, list)
2224 		occ_port_free(occ_port);
2225 }
2226 
occ_port_get(struct occ_show * occ_show,struct nlattr ** tb)2227 static struct occ_port *occ_port_get(struct occ_show *occ_show,
2228 				     struct nlattr **tb)
2229 {
2230 	struct occ_port *occ_port;
2231 	uint32_t port_index;
2232 
2233 	port_index = mnl_attr_get_u32(tb[DEVLINK_ATTR_PORT_INDEX]);
2234 
2235 	list_for_each_entry_reverse(occ_port, &occ_show->port_list, list) {
2236 		if (occ_port->port_index == port_index)
2237 			return occ_port;
2238 	}
2239 	occ_port = occ_port_alloc(port_index);
2240 	if (!occ_port)
2241 		return NULL;
2242 	list_add_tail(&occ_port->list, &occ_show->port_list);
2243 	return occ_port;
2244 }
2245 
pr_out_occ_show_item_list(const char * label,struct list_head * list,bool bound_pool)2246 static void pr_out_occ_show_item_list(const char *label, struct list_head *list,
2247 				      bool bound_pool)
2248 {
2249 	struct occ_item *occ_item;
2250 	int i = 1;
2251 
2252 	pr_out_sp(7, "  %s:", label);
2253 	list_for_each_entry(occ_item, list, list) {
2254 		if ((i - 1) % 4 == 0 && i != 1)
2255 			pr_out_sp(7, " ");
2256 		if (bound_pool)
2257 			pr_out_sp(7, "%2u(%u):", occ_item->index,
2258 				  occ_item->bound_pool_index);
2259 		else
2260 			pr_out_sp(7, "%2u:", occ_item->index);
2261 		pr_out_sp(15, "%7u/%u", occ_item->cur, occ_item->max);
2262 		if (i++ % 4 == 0)
2263 			pr_out("\n");
2264 	}
2265 	if ((i - 1) % 4 != 0)
2266 		pr_out("\n");
2267 }
2268 
pr_out_json_occ_show_item_list(struct dl * dl,const char * label,struct list_head * list,bool bound_pool)2269 static void pr_out_json_occ_show_item_list(struct dl *dl, const char *label,
2270 					   struct list_head *list,
2271 					   bool bound_pool)
2272 {
2273 	struct occ_item *occ_item;
2274 	char buf[32];
2275 
2276 	jsonw_name(dl->jw, label);
2277 	jsonw_start_object(dl->jw);
2278 	list_for_each_entry(occ_item, list, list) {
2279 		sprintf(buf, "%u", occ_item->index);
2280 		jsonw_name(dl->jw, buf);
2281 		jsonw_start_object(dl->jw);
2282 		if (bound_pool)
2283 			jsonw_uint_field(dl->jw, "bound_pool",
2284 					 occ_item->bound_pool_index);
2285 		jsonw_uint_field(dl->jw, "current", occ_item->cur);
2286 		jsonw_uint_field(dl->jw, "max", occ_item->max);
2287 		jsonw_end_object(dl->jw);
2288 	}
2289 	jsonw_end_object(dl->jw);
2290 }
2291 
pr_out_occ_show_port(struct dl * dl,struct occ_port * occ_port)2292 static void pr_out_occ_show_port(struct dl *dl, struct occ_port *occ_port)
2293 {
2294 	if (dl->json_output) {
2295 		pr_out_json_occ_show_item_list(dl, "pool",
2296 					       &occ_port->pool_list, false);
2297 		pr_out_json_occ_show_item_list(dl, "itc",
2298 					       &occ_port->ing_tc_list, true);
2299 		pr_out_json_occ_show_item_list(dl, "etc",
2300 					       &occ_port->eg_tc_list, true);
2301 	} else {
2302 		pr_out("\n");
2303 		pr_out_occ_show_item_list("pool", &occ_port->pool_list, false);
2304 		pr_out_occ_show_item_list("itc", &occ_port->ing_tc_list, true);
2305 		pr_out_occ_show_item_list("etc", &occ_port->eg_tc_list, true);
2306 	}
2307 }
2308 
pr_out_occ_show(struct occ_show * occ_show)2309 static void pr_out_occ_show(struct occ_show *occ_show)
2310 {
2311 	struct dl *dl = occ_show->dl;
2312 	struct dl_opts *opts = &dl->opts;
2313 	struct occ_port *occ_port;
2314 
2315 	list_for_each_entry(occ_port, &occ_show->port_list, list) {
2316 		__pr_out_port_handle_start(dl, opts->bus_name, opts->dev_name,
2317 					   occ_port->port_index, true, false);
2318 		pr_out_occ_show_port(dl, occ_port);
2319 		pr_out_port_handle_end(dl);
2320 	}
2321 }
2322 
cmd_sb_occ_port_pool_process(struct occ_show * occ_show,struct nlattr ** tb)2323 static void cmd_sb_occ_port_pool_process(struct occ_show *occ_show,
2324 					 struct nlattr **tb)
2325 {
2326 	struct occ_port *occ_port;
2327 	struct occ_item *occ_item;
2328 
2329 	if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
2330 		return;
2331 
2332 	occ_port = occ_port_get(occ_show, tb);
2333 	if (!occ_port) {
2334 		occ_show->err = -ENOMEM;
2335 		return;
2336 	}
2337 
2338 	occ_item = occ_item_alloc();
2339 	if (!occ_item) {
2340 		occ_show->err = -ENOMEM;
2341 		return;
2342 	}
2343 	occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
2344 	occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
2345 	occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
2346 	list_add_tail(&occ_item->list, &occ_port->pool_list);
2347 }
2348 
cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr * nlh,void * data)2349 static int cmd_sb_occ_port_pool_process_cb(const struct nlmsghdr *nlh, void *data)
2350 {
2351 	struct occ_show *occ_show = data;
2352 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2353 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2354 
2355 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2356 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2357 	    !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2358 	    !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
2359 	    !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
2360 		return MNL_CB_ERROR;
2361 	cmd_sb_occ_port_pool_process(occ_show, tb);
2362 	return MNL_CB_OK;
2363 }
2364 
cmd_sb_occ_tc_pool_process(struct occ_show * occ_show,struct nlattr ** tb)2365 static void cmd_sb_occ_tc_pool_process(struct occ_show *occ_show,
2366 				       struct nlattr **tb)
2367 {
2368 	struct occ_port *occ_port;
2369 	struct occ_item *occ_item;
2370 	uint8_t pool_type;
2371 
2372 	if (occ_show->err || !dl_dump_filter(occ_show->dl, tb))
2373 		return;
2374 
2375 	occ_port = occ_port_get(occ_show, tb);
2376 	if (!occ_port) {
2377 		occ_show->err = -ENOMEM;
2378 		return;
2379 	}
2380 
2381 	occ_item = occ_item_alloc();
2382 	if (!occ_item) {
2383 		occ_show->err = -ENOMEM;
2384 		return;
2385 	}
2386 	occ_item->index = mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_TC_INDEX]);
2387 	occ_item->cur = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_CUR]);
2388 	occ_item->max = mnl_attr_get_u32(tb[DEVLINK_ATTR_SB_OCC_MAX]);
2389 	occ_item->bound_pool_index =
2390 			mnl_attr_get_u16(tb[DEVLINK_ATTR_SB_POOL_INDEX]);
2391 	pool_type = mnl_attr_get_u8(tb[DEVLINK_ATTR_SB_POOL_TYPE]);
2392 	if (pool_type == DEVLINK_SB_POOL_TYPE_INGRESS)
2393 		list_add_tail(&occ_item->list, &occ_port->ing_tc_list);
2394 	else if (pool_type == DEVLINK_SB_POOL_TYPE_EGRESS)
2395 		list_add_tail(&occ_item->list, &occ_port->eg_tc_list);
2396 	else
2397 		occ_item_free(occ_item);
2398 }
2399 
cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr * nlh,void * data)2400 static int cmd_sb_occ_tc_pool_process_cb(const struct nlmsghdr *nlh, void *data)
2401 {
2402 	struct occ_show *occ_show = data;
2403 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2404 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2405 
2406 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2407 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2408 	    !tb[DEVLINK_ATTR_PORT_INDEX] || !tb[DEVLINK_ATTR_SB_INDEX] ||
2409 	    !tb[DEVLINK_ATTR_SB_TC_INDEX] || !tb[DEVLINK_ATTR_SB_POOL_TYPE] ||
2410 	    !tb[DEVLINK_ATTR_SB_POOL_INDEX] ||
2411 	    !tb[DEVLINK_ATTR_SB_OCC_CUR] || !tb[DEVLINK_ATTR_SB_OCC_MAX])
2412 		return MNL_CB_ERROR;
2413 	cmd_sb_occ_tc_pool_process(occ_show, tb);
2414 	return MNL_CB_OK;
2415 }
2416 
cmd_sb_occ_show(struct dl * dl)2417 static int cmd_sb_occ_show(struct dl *dl)
2418 {
2419 	struct nlmsghdr *nlh;
2420 	struct occ_show *occ_show;
2421 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP;
2422 	int err;
2423 
2424 	err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_HANDLEP, DL_OPT_SB);
2425 	if (err)
2426 		return err;
2427 
2428 	occ_show = occ_show_alloc(dl);
2429 	if (!occ_show)
2430 		return -ENOMEM;
2431 
2432 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_PORT_POOL_GET, flags);
2433 
2434 	err = _mnlg_socket_sndrcv(dl->nlg, nlh,
2435 				  cmd_sb_occ_port_pool_process_cb, occ_show);
2436 	if (err)
2437 		goto out;
2438 
2439 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_TC_POOL_BIND_GET, flags);
2440 
2441 	err = _mnlg_socket_sndrcv(dl->nlg, nlh,
2442 				  cmd_sb_occ_tc_pool_process_cb, occ_show);
2443 	if (err)
2444 		goto out;
2445 
2446 	pr_out_section_start(dl, "occupancy");
2447 	pr_out_occ_show(occ_show);
2448 	pr_out_section_end(dl);
2449 
2450 out:
2451 	occ_show_free(occ_show);
2452 	return err;
2453 }
2454 
cmd_sb_occ_snapshot(struct dl * dl)2455 static int cmd_sb_occ_snapshot(struct dl *dl)
2456 {
2457 	struct nlmsghdr *nlh;
2458 	int err;
2459 
2460 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_SNAPSHOT,
2461 			       NLM_F_REQUEST | NLM_F_ACK);
2462 
2463 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
2464 	if (err)
2465 		return err;
2466 
2467 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2468 }
2469 
cmd_sb_occ_clearmax(struct dl * dl)2470 static int cmd_sb_occ_clearmax(struct dl *dl)
2471 {
2472 	struct nlmsghdr *nlh;
2473 	int err;
2474 
2475 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_SB_OCC_MAX_CLEAR,
2476 			       NLM_F_REQUEST | NLM_F_ACK);
2477 
2478 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, DL_OPT_SB);
2479 	if (err)
2480 		return err;
2481 
2482 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
2483 }
2484 
cmd_sb_occ(struct dl * dl)2485 static int cmd_sb_occ(struct dl *dl)
2486 {
2487 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
2488 		cmd_sb_help();
2489 		return 0;
2490 	} else if (dl_argv_match(dl, "show") ||
2491 		   dl_argv_match(dl, "list")) {
2492 		dl_arg_inc(dl);
2493 		return cmd_sb_occ_show(dl);
2494 	} else if (dl_argv_match(dl, "snapshot")) {
2495 		dl_arg_inc(dl);
2496 		return cmd_sb_occ_snapshot(dl);
2497 	} else if (dl_argv_match(dl, "clearmax")) {
2498 		dl_arg_inc(dl);
2499 		return cmd_sb_occ_clearmax(dl);
2500 	}
2501 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
2502 	return -ENOENT;
2503 }
2504 
cmd_sb(struct dl * dl)2505 static int cmd_sb(struct dl *dl)
2506 {
2507 	if (dl_argv_match(dl, "help")) {
2508 		cmd_sb_help();
2509 		return 0;
2510 	} else if (dl_argv_match(dl, "show") ||
2511 		   dl_argv_match(dl, "list") || dl_no_arg(dl)) {
2512 		dl_arg_inc(dl);
2513 		return cmd_sb_show(dl);
2514 	} else if (dl_argv_match(dl, "pool")) {
2515 		dl_arg_inc(dl);
2516 		return cmd_sb_pool(dl);
2517 	} else if (dl_argv_match(dl, "port")) {
2518 		dl_arg_inc(dl);
2519 		return cmd_sb_port(dl);
2520 	} else if (dl_argv_match(dl, "tc")) {
2521 		dl_arg_inc(dl);
2522 		return cmd_sb_tc(dl);
2523 	} else if (dl_argv_match(dl, "occupancy")) {
2524 		dl_arg_inc(dl);
2525 		return cmd_sb_occ(dl);
2526 	}
2527 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
2528 	return -ENOENT;
2529 }
2530 
cmd_name(uint8_t cmd)2531 static const char *cmd_name(uint8_t cmd)
2532 {
2533 	switch (cmd) {
2534 	case DEVLINK_CMD_UNSPEC: return "unspec";
2535 	case DEVLINK_CMD_GET: return "get";
2536 	case DEVLINK_CMD_SET: return "set";
2537 	case DEVLINK_CMD_NEW: return "new";
2538 	case DEVLINK_CMD_DEL: return "del";
2539 	case DEVLINK_CMD_PORT_GET: return "get";
2540 	case DEVLINK_CMD_PORT_SET: return "set";
2541 	case DEVLINK_CMD_PORT_NEW: return "net";
2542 	case DEVLINK_CMD_PORT_DEL: return "del";
2543 	default: return "<unknown cmd>";
2544 	}
2545 }
2546 
cmd_obj(uint8_t cmd)2547 static const char *cmd_obj(uint8_t cmd)
2548 {
2549 	switch (cmd) {
2550 	case DEVLINK_CMD_UNSPEC: return "unspec";
2551 	case DEVLINK_CMD_GET:
2552 	case DEVLINK_CMD_SET:
2553 	case DEVLINK_CMD_NEW:
2554 	case DEVLINK_CMD_DEL:
2555 		return "dev";
2556 	case DEVLINK_CMD_PORT_GET:
2557 	case DEVLINK_CMD_PORT_SET:
2558 	case DEVLINK_CMD_PORT_NEW:
2559 	case DEVLINK_CMD_PORT_DEL:
2560 		return "port";
2561 	default: return "<unknown obj>";
2562 	}
2563 }
2564 
pr_out_mon_header(uint8_t cmd)2565 static void pr_out_mon_header(uint8_t cmd)
2566 {
2567 	pr_out("[%s,%s] ", cmd_obj(cmd), cmd_name(cmd));
2568 }
2569 
cmd_filter_check(struct dl * dl,uint8_t cmd)2570 static bool cmd_filter_check(struct dl *dl, uint8_t cmd)
2571 {
2572 	const char *obj = cmd_obj(cmd);
2573 	unsigned int index = 0;
2574 	const char *cur_obj;
2575 
2576 	if (dl_no_arg(dl))
2577 		return true;
2578 	while ((cur_obj = dl_argv_index(dl, index++))) {
2579 		if (strcmp(cur_obj, obj) == 0 || strcmp(cur_obj, "all") == 0)
2580 			return true;
2581 	}
2582 	return false;
2583 }
2584 
cmd_mon_show_cb(const struct nlmsghdr * nlh,void * data)2585 static int cmd_mon_show_cb(const struct nlmsghdr *nlh, void *data)
2586 {
2587 	struct dl *dl = data;
2588 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
2589 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
2590 	uint8_t cmd = genl->cmd;
2591 
2592 	if (!cmd_filter_check(dl, cmd))
2593 		return MNL_CB_OK;
2594 
2595 	switch (cmd) {
2596 	case DEVLINK_CMD_GET: /* fall through */
2597 	case DEVLINK_CMD_SET: /* fall through */
2598 	case DEVLINK_CMD_NEW: /* fall through */
2599 	case DEVLINK_CMD_DEL:
2600 		mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2601 		if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME])
2602 			return MNL_CB_ERROR;
2603 		pr_out_mon_header(genl->cmd);
2604 		pr_out_dev(dl, tb);
2605 		break;
2606 	case DEVLINK_CMD_PORT_GET: /* fall through */
2607 	case DEVLINK_CMD_PORT_SET: /* fall through */
2608 	case DEVLINK_CMD_PORT_NEW: /* fall through */
2609 	case DEVLINK_CMD_PORT_DEL:
2610 		mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
2611 		if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
2612 		    !tb[DEVLINK_ATTR_PORT_INDEX])
2613 			return MNL_CB_ERROR;
2614 		pr_out_mon_header(genl->cmd);
2615 		pr_out_port(dl, tb);
2616 		break;
2617 	}
2618 	return MNL_CB_OK;
2619 }
2620 
cmd_mon_show(struct dl * dl)2621 static int cmd_mon_show(struct dl *dl)
2622 {
2623 	int err;
2624 	unsigned int index = 0;
2625 	const char *cur_obj;
2626 
2627 	while ((cur_obj = dl_argv_index(dl, index++))) {
2628 		if (strcmp(cur_obj, "all") != 0 &&
2629 		    strcmp(cur_obj, "dev") != 0 &&
2630 		    strcmp(cur_obj, "port") != 0) {
2631 			pr_err("Unknown object \"%s\"\n", cur_obj);
2632 			return -EINVAL;
2633 		}
2634 	}
2635 	err = _mnlg_socket_group_add(dl->nlg, DEVLINK_GENL_MCGRP_CONFIG_NAME);
2636 	if (err)
2637 		return err;
2638 	err = _mnlg_socket_recv_run(dl->nlg, cmd_mon_show_cb, dl);
2639 	if (err)
2640 		return err;
2641 	return 0;
2642 }
2643 
cmd_mon_help(void)2644 static void cmd_mon_help(void)
2645 {
2646 	pr_err("Usage: devlink monitor [ all | OBJECT-LIST ]\n"
2647 	       "where  OBJECT-LIST := { dev | port }\n");
2648 }
2649 
cmd_mon(struct dl * dl)2650 static int cmd_mon(struct dl *dl)
2651 {
2652 	if (dl_argv_match(dl, "help")) {
2653 		cmd_mon_help();
2654 		return 0;
2655 	} else if (dl_no_arg(dl)) {
2656 		dl_arg_inc(dl);
2657 		return cmd_mon_show(dl);
2658 	}
2659 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
2660 	return -ENOENT;
2661 }
2662 
2663 struct dpipe_field {
2664 	char *name;
2665 	unsigned int id;
2666 	unsigned int bitwidth;
2667 	enum devlink_dpipe_field_mapping_type mapping_type;
2668 };
2669 
2670 struct dpipe_header {
2671 	struct list_head list;
2672 	char *name;
2673 	unsigned int id;
2674 	struct dpipe_field *fields;
2675 	unsigned int fields_count;
2676 };
2677 
2678 struct dpipe_ctx {
2679 	struct dl *dl;
2680 	int err;
2681 	struct list_head global_headers;
2682 	struct list_head local_headers;
2683 	bool print_headers;
2684 };
2685 
dpipe_header_alloc(unsigned int fields_count)2686 static struct dpipe_header *dpipe_header_alloc(unsigned int fields_count)
2687 {
2688 	struct dpipe_header *header;
2689 
2690 	header = calloc(1, sizeof(struct dpipe_header));
2691 	if (!header)
2692 		return NULL;
2693 	header->fields = calloc(fields_count, sizeof(struct dpipe_field));
2694 	if (!header->fields)
2695 		goto err_fields_alloc;
2696 	header->fields_count = fields_count;
2697 	return header;
2698 
2699 err_fields_alloc:
2700 	free(header);
2701 	return NULL;
2702 }
2703 
dpipe_header_free(struct dpipe_header * header)2704 static void dpipe_header_free(struct dpipe_header *header)
2705 {
2706 	free(header->fields);
2707 	free(header);
2708 }
2709 
dpipe_header_clear(struct dpipe_header * header)2710 static void dpipe_header_clear(struct dpipe_header *header)
2711 {
2712 	struct dpipe_field *field;
2713 	int i;
2714 
2715 	for (i = 0; i < header->fields_count; i++) {
2716 		field = &header->fields[i];
2717 		free(field->name);
2718 	}
2719 	free(header->name);
2720 }
2721 
dpipe_header_add(struct dpipe_ctx * ctx,struct dpipe_header * header,bool global)2722 static void dpipe_header_add(struct dpipe_ctx *ctx,
2723 			     struct dpipe_header *header, bool global)
2724 {
2725 	if (global)
2726 		list_add(&header->list, &ctx->global_headers);
2727 	else
2728 		list_add(&header->list, &ctx->local_headers);
2729 }
2730 
dpipe_header_del(struct dpipe_header * header)2731 static void dpipe_header_del(struct dpipe_header *header)
2732 {
2733 	list_del(&header->list);
2734 }
2735 
dpipe_ctx_alloc(struct dl * dl)2736 static struct dpipe_ctx *dpipe_ctx_alloc(struct dl *dl)
2737 {
2738 	struct dpipe_ctx *ctx;
2739 
2740 	ctx = calloc(1, sizeof(struct dpipe_ctx));
2741 	if (!ctx)
2742 		return NULL;
2743 	ctx->dl = dl;
2744 	INIT_LIST_HEAD(&ctx->global_headers);
2745 	INIT_LIST_HEAD(&ctx->local_headers);
2746 	return ctx;
2747 }
2748 
dpipe_ctx_free(struct dpipe_ctx * ctx)2749 static void dpipe_ctx_free(struct dpipe_ctx *ctx)
2750 {
2751 	free(ctx);
2752 }
2753 
dpipe_ctx_clear(struct dpipe_ctx * ctx)2754 static void dpipe_ctx_clear(struct dpipe_ctx *ctx)
2755 {
2756 	struct dpipe_header *header, *tmp;
2757 
2758 	list_for_each_entry_safe(header, tmp, &ctx->global_headers,
2759 				 list) {
2760 		dpipe_header_del(header);
2761 		dpipe_header_clear(header);
2762 		dpipe_header_free(header);
2763 	}
2764 	list_for_each_entry_safe(header, tmp, &ctx->local_headers,
2765 				 list) {
2766 		dpipe_header_del(header);
2767 		dpipe_header_clear(header);
2768 		dpipe_header_free(header);
2769 	}
2770 }
2771 
dpipe_header_id2s(struct dpipe_ctx * ctx,uint32_t header_id,bool global)2772 static const char *dpipe_header_id2s(struct dpipe_ctx *ctx,
2773 				     uint32_t header_id, bool global)
2774 {
2775 	struct list_head *header_list;
2776 	struct dpipe_header *header;
2777 
2778 	if (global)
2779 		header_list = &ctx->global_headers;
2780 	else
2781 		header_list = &ctx->local_headers;
2782 	list_for_each_entry(header, header_list, list) {
2783 		if (header->id != header_id)
2784 			continue;
2785 		return header->name;
2786 	}
2787 	return NULL;
2788 }
2789 
dpipe_field_id2s(struct dpipe_ctx * ctx,uint32_t header_id,uint32_t field_id,bool global)2790 static const char *dpipe_field_id2s(struct dpipe_ctx *ctx,
2791 				    uint32_t header_id,
2792 				    uint32_t field_id, bool global)
2793 {
2794 	struct list_head *header_list;
2795 	struct dpipe_header *header;
2796 
2797 	if (global)
2798 		header_list = &ctx->global_headers;
2799 	else
2800 		header_list = &ctx->local_headers;
2801 	list_for_each_entry(header, header_list, list) {
2802 		if (header->id != header_id)
2803 			continue;
2804 		return header->fields[field_id].name;
2805 	}
2806 	return NULL;
2807 }
2808 
2809 static const char *
dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)2810 dpipe_field_mapping_e2s(enum devlink_dpipe_field_mapping_type mapping_type)
2811 {
2812 	switch (mapping_type) {
2813 	case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_NONE:
2814 		return NULL;
2815 	case DEVLINK_DPIPE_FIELD_MAPPING_TYPE_IFINDEX:
2816 		return "ifindex";
2817 	default:
2818 		return "<unknown>";
2819 	}
2820 }
2821 
2822 static const char *
dpipe_mapping_get(struct dpipe_ctx * ctx,uint32_t header_id,uint32_t field_id,bool global)2823 dpipe_mapping_get(struct dpipe_ctx *ctx, uint32_t header_id,
2824 		  uint32_t field_id, bool global)
2825 {
2826 	enum devlink_dpipe_field_mapping_type mapping_type;
2827 	struct list_head *header_list;
2828 	struct dpipe_header *header;
2829 
2830 	if (global)
2831 		header_list = &ctx->global_headers;
2832 	else
2833 		header_list = &ctx->local_headers;
2834 	list_for_each_entry(header, header_list, list) {
2835 		if (header->id != header_id)
2836 			continue;
2837 		mapping_type = header->fields[field_id].mapping_type;
2838 		return dpipe_field_mapping_e2s(mapping_type);
2839 	}
2840 	return NULL;
2841 }
2842 
pr_out_dpipe_fields(struct dpipe_ctx * ctx,struct dpipe_field * fields,unsigned int field_count)2843 static void pr_out_dpipe_fields(struct dpipe_ctx *ctx,
2844 				struct dpipe_field *fields,
2845 				unsigned int field_count)
2846 {
2847 	struct dpipe_field *field;
2848 	int i;
2849 
2850 	for (i = 0; i < field_count; i++) {
2851 		field = &fields[i];
2852 		pr_out_entry_start(ctx->dl);
2853 		pr_out_str(ctx->dl, "name", field->name);
2854 		if (ctx->dl->verbose)
2855 			pr_out_uint(ctx->dl, "id", field->id);
2856 		pr_out_uint(ctx->dl, "bitwidth", field->bitwidth);
2857 		if (field->mapping_type)
2858 			pr_out_str(ctx->dl, "mapping_type",
2859 				   dpipe_field_mapping_e2s(field->mapping_type));
2860 		pr_out_entry_end(ctx->dl);
2861 	}
2862 }
2863 
2864 static void
pr_out_dpipe_header(struct dpipe_ctx * ctx,struct nlattr ** tb,struct dpipe_header * header,bool global)2865 pr_out_dpipe_header(struct dpipe_ctx *ctx, struct nlattr **tb,
2866 		    struct dpipe_header *header, bool global)
2867 {
2868 	pr_out_handle_start_arr(ctx->dl, tb);
2869 	pr_out_str(ctx->dl, "name", header->name);
2870 	if (ctx->dl->verbose) {
2871 		pr_out_uint(ctx->dl, "id", header->id);
2872 		pr_out_str(ctx->dl, "global",
2873 			   global ? "true" : "false");
2874 	}
2875 	pr_out_array_start(ctx->dl, "field");
2876 	pr_out_dpipe_fields(ctx, header->fields,
2877 			    header->fields_count);
2878 	pr_out_array_end(ctx->dl);
2879 	pr_out_handle_end(ctx->dl);
2880 }
2881 
pr_out_dpipe_headers(struct dpipe_ctx * ctx,struct nlattr ** tb)2882 static void pr_out_dpipe_headers(struct dpipe_ctx *ctx,
2883 				 struct nlattr **tb)
2884 {
2885 	struct dpipe_header *header;
2886 
2887 	list_for_each_entry(header, &ctx->local_headers, list)
2888 		pr_out_dpipe_header(ctx, tb, header, false);
2889 
2890 	list_for_each_entry(header, &ctx->global_headers, list)
2891 		pr_out_dpipe_header(ctx, tb, header, true);
2892 }
2893 
dpipe_header_field_get(struct nlattr * nl,struct dpipe_field * field)2894 static int dpipe_header_field_get(struct nlattr *nl, struct dpipe_field *field)
2895 {
2896 	struct nlattr *nla_field[DEVLINK_ATTR_MAX + 1] = {};
2897 	const char *name;
2898 	int err;
2899 
2900 	err = mnl_attr_parse_nested(nl, attr_cb, nla_field);
2901 	if (err != MNL_CB_OK)
2902 		return -EINVAL;
2903 	if (!nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID] ||
2904 	    !nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME] ||
2905 	    !nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH] ||
2906 	    !nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE])
2907 		return -EINVAL;
2908 
2909 	name = mnl_attr_get_str(nla_field[DEVLINK_ATTR_DPIPE_FIELD_NAME]);
2910 	field->id = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_ID]);
2911 	field->bitwidth = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_BITWIDTH]);
2912 	field->name = strdup(name);
2913 	if (!field->name)
2914 		return -ENOMEM;
2915 	field->mapping_type = mnl_attr_get_u32(nla_field[DEVLINK_ATTR_DPIPE_FIELD_MAPPING_TYPE]);
2916 	return 0;
2917 }
2918 
dpipe_header_fields_get(struct nlattr * nla_fields,struct dpipe_field * fields)2919 static int dpipe_header_fields_get(struct nlattr *nla_fields,
2920 				   struct dpipe_field *fields)
2921 {
2922 	struct nlattr *nla_field;
2923 	int count = 0;
2924 	int err;
2925 
2926 	mnl_attr_for_each_nested(nla_field, nla_fields) {
2927 		err = dpipe_header_field_get(nla_field, &fields[count]);
2928 		if (err)
2929 			return err;
2930 		count++;
2931 	}
2932 	return 0;
2933 }
2934 
dpipe_header_field_count_get(struct nlattr * nla_fields)2935 static unsigned int dpipe_header_field_count_get(struct nlattr *nla_fields)
2936 {
2937 	struct nlattr *nla_field;
2938 	unsigned int count = 0;
2939 
2940 	mnl_attr_for_each_nested(nla_field, nla_fields)
2941 		count++;
2942 	return count;
2943 }
2944 
dpipe_header_get(struct dpipe_ctx * ctx,struct nlattr * nl)2945 static int dpipe_header_get(struct dpipe_ctx *ctx, struct nlattr *nl)
2946 {
2947 	struct nlattr *nla_header[DEVLINK_ATTR_MAX + 1] = {};
2948 	struct dpipe_header *header;
2949 	unsigned int fields_count;
2950 	const char *header_name;
2951 	bool global;
2952 	int err;
2953 
2954 	err = mnl_attr_parse_nested(nl, attr_cb, nla_header);
2955 	if (err != MNL_CB_OK)
2956 		return -EINVAL;
2957 
2958 	if (!nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME] ||
2959 	    !nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
2960 	    !nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS])
2961 		return -EINVAL;
2962 
2963 	fields_count = dpipe_header_field_count_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS]);
2964 	header = dpipe_header_alloc(fields_count);
2965 	if (!header)
2966 		return -ENOMEM;
2967 
2968 	header_name = mnl_attr_get_str(nla_header[DEVLINK_ATTR_DPIPE_HEADER_NAME]);
2969 	header->name = strdup(header_name);
2970 	header->id = mnl_attr_get_u32(nla_header[DEVLINK_ATTR_DPIPE_HEADER_ID]);
2971 	header->fields_count = fields_count;
2972 	global = !!mnl_attr_get_u8(nla_header[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
2973 
2974 	err = dpipe_header_fields_get(nla_header[DEVLINK_ATTR_DPIPE_HEADER_FIELDS],
2975 				      header->fields);
2976 	if (err)
2977 		goto err_field_get;
2978 	dpipe_header_add(ctx, header, global);
2979 	return 0;
2980 
2981 err_field_get:
2982 	dpipe_header_free(header);
2983 	return err;
2984 }
2985 
dpipe_headers_get(struct dpipe_ctx * ctx,struct nlattr ** tb)2986 static int dpipe_headers_get(struct dpipe_ctx *ctx, struct nlattr **tb)
2987 {
2988 	struct nlattr *nla_headers = tb[DEVLINK_ATTR_DPIPE_HEADERS];
2989 	struct nlattr *nla_header;
2990 	int err;
2991 
2992 	mnl_attr_for_each_nested(nla_header, nla_headers) {
2993 		err = dpipe_header_get(ctx, nla_header);
2994 		if (err)
2995 			return err;
2996 	}
2997 	return 0;
2998 }
2999 
cmd_dpipe_header_cb(const struct nlmsghdr * nlh,void * data)3000 static int cmd_dpipe_header_cb(const struct nlmsghdr *nlh, void *data)
3001 {
3002 	struct dpipe_ctx *ctx = data;
3003 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3004 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3005 	int err;
3006 
3007 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3008 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3009 	    !tb[DEVLINK_ATTR_DPIPE_HEADERS])
3010 		return MNL_CB_ERROR;
3011 	err = dpipe_headers_get(ctx, tb);
3012 	if (err) {
3013 		ctx->err = err;
3014 		return MNL_CB_ERROR;
3015 	}
3016 
3017 	if (ctx->print_headers)
3018 		pr_out_dpipe_headers(ctx, tb);
3019 	return MNL_CB_OK;
3020 }
3021 
cmd_dpipe_headers_show(struct dl * dl)3022 static int cmd_dpipe_headers_show(struct dl *dl)
3023 {
3024 	struct nlmsghdr *nlh;
3025 	struct dpipe_ctx *ctx;
3026 	uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
3027 	int err;
3028 
3029 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3030 
3031 	err = dl_argv_parse_put(nlh, dl, DL_OPT_HANDLE, 0);
3032 	if (err)
3033 		return err;
3034 
3035 	ctx = dpipe_ctx_alloc(dl);
3036 	if (!ctx)
3037 		return -ENOMEM;
3038 
3039 	ctx->print_headers = true;
3040 
3041 	pr_out_section_start(dl, "header");
3042 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
3043 	if (err)
3044 		pr_err("error get headers %s\n", strerror(ctx->err));
3045 	pr_out_section_end(dl);
3046 
3047 	dpipe_ctx_clear(ctx);
3048 	dpipe_ctx_free(ctx);
3049 	return err;
3050 }
3051 
cmd_dpipe_header_help(void)3052 static void cmd_dpipe_header_help(void)
3053 {
3054 	pr_err("Usage: devlink dpipe headers show DEV\n");
3055 }
3056 
cmd_dpipe_header(struct dl * dl)3057 static int cmd_dpipe_header(struct dl *dl)
3058 {
3059 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3060 		cmd_dpipe_header_help();
3061 		return 0;
3062 	} else if (dl_argv_match(dl, "show")) {
3063 		dl_arg_inc(dl);
3064 		return cmd_dpipe_headers_show(dl);
3065 	}
3066 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
3067 	return -ENOENT;
3068 }
3069 
3070 static const char
dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)3071 *dpipe_action_type_e2s(enum devlink_dpipe_action_type action_type)
3072 {
3073 	switch (action_type) {
3074 	case DEVLINK_DPIPE_ACTION_TYPE_FIELD_MODIFY:
3075 		return "field_modify";
3076 	default:
3077 		return "<unknown>";
3078 	}
3079 }
3080 
3081 struct dpipe_op_info {
3082 	uint32_t header_id;
3083 	uint32_t field_id;
3084 	bool header_global;
3085 };
3086 
3087 struct dpipe_action {
3088 	struct dpipe_op_info info;
3089 	uint32_t type;
3090 };
3091 
pr_out_dpipe_action(struct dpipe_action * action,struct dpipe_ctx * ctx)3092 static void pr_out_dpipe_action(struct dpipe_action *action,
3093 				struct dpipe_ctx *ctx)
3094 {
3095 	struct dpipe_op_info *op_info = &action->info;
3096 	const char *mapping;
3097 
3098 	pr_out_str(ctx->dl, "type",
3099 		   dpipe_action_type_e2s(action->type));
3100 	pr_out_str(ctx->dl, "header",
3101 		   dpipe_header_id2s(ctx, op_info->header_id,
3102 				     op_info->header_global));
3103 	pr_out_str(ctx->dl, "field",
3104 		   dpipe_field_id2s(ctx, op_info->header_id,
3105 				    op_info->field_id,
3106 				    op_info->header_global));
3107 	mapping = dpipe_mapping_get(ctx, op_info->header_id,
3108 				    op_info->field_id,
3109 				    op_info->header_global);
3110 	if (mapping)
3111 		pr_out_str(ctx->dl, "mapping", mapping);
3112 }
3113 
dpipe_action_parse(struct dpipe_action * action,struct nlattr * nl)3114 static int dpipe_action_parse(struct dpipe_action *action, struct nlattr *nl)
3115 {
3116 	struct nlattr *nla_action[DEVLINK_ATTR_MAX + 1] = {};
3117 	int err;
3118 
3119 	err = mnl_attr_parse_nested(nl, attr_cb, nla_action);
3120 	if (err != MNL_CB_OK)
3121 		return -EINVAL;
3122 
3123 	if (!nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE] ||
3124 	    !nla_action[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
3125 	    !nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
3126 	    !nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
3127 		return -EINVAL;
3128 	}
3129 
3130 	action->type = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_ACTION_TYPE]);
3131 	action->info.header_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_HEADER_ID]);
3132 	action->info.field_id = mnl_attr_get_u32(nla_action[DEVLINK_ATTR_DPIPE_FIELD_ID]);
3133 	action->info.header_global = !!mnl_attr_get_u8(nla_action[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
3134 
3135 	return 0;
3136 }
3137 
dpipe_table_actions_show(struct dpipe_ctx * ctx,struct nlattr * nla_actions)3138 static int dpipe_table_actions_show(struct dpipe_ctx *ctx,
3139 				    struct nlattr *nla_actions)
3140 {
3141 	struct nlattr *nla_action;
3142 	struct dpipe_action action;
3143 
3144 	mnl_attr_for_each_nested(nla_action, nla_actions) {
3145 		pr_out_entry_start(ctx->dl);
3146 		if (dpipe_action_parse(&action, nla_action))
3147 			goto err_action_parse;
3148 		pr_out_dpipe_action(&action, ctx);
3149 		pr_out_entry_end(ctx->dl);
3150 	}
3151 	return 0;
3152 
3153 err_action_parse:
3154 	pr_out_entry_end(ctx->dl);
3155 	return -EINVAL;
3156 }
3157 
3158 static const char *
dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)3159 dpipe_match_type_e2s(enum devlink_dpipe_match_type match_type)
3160 {
3161 	switch (match_type) {
3162 	case DEVLINK_DPIPE_MATCH_TYPE_FIELD_EXACT:
3163 		return "field_exact";
3164 	default:
3165 		return "<unknown>";
3166 	}
3167 }
3168 
3169 struct dpipe_match {
3170 	struct dpipe_op_info info;
3171 	uint32_t type;
3172 };
3173 
pr_out_dpipe_match(struct dpipe_match * match,struct dpipe_ctx * ctx)3174 static void pr_out_dpipe_match(struct dpipe_match *match,
3175 			       struct dpipe_ctx *ctx)
3176 {
3177 	struct dpipe_op_info *op_info = &match->info;
3178 	const char *mapping;
3179 
3180 	pr_out_str(ctx->dl, "type",
3181 		   dpipe_match_type_e2s(match->type));
3182 	pr_out_str(ctx->dl, "header",
3183 		   dpipe_header_id2s(ctx, op_info->header_id,
3184 				     op_info->header_global));
3185 	pr_out_str(ctx->dl, "field",
3186 		   dpipe_field_id2s(ctx, op_info->header_id,
3187 				    op_info->field_id,
3188 				    op_info->header_global));
3189 	mapping = dpipe_mapping_get(ctx, op_info->header_id,
3190 				    op_info->field_id,
3191 				    op_info->header_global);
3192 	if (mapping)
3193 		pr_out_str(ctx->dl, "mapping", mapping);
3194 }
3195 
dpipe_match_parse(struct dpipe_match * match,struct nlattr * nl)3196 static int dpipe_match_parse(struct dpipe_match *match,
3197 			     struct nlattr *nl)
3198 
3199 {
3200 	struct nlattr *nla_match[DEVLINK_ATTR_MAX + 1] = {};
3201 	int err;
3202 
3203 	err = mnl_attr_parse_nested(nl, attr_cb, nla_match);
3204 	if (err != MNL_CB_OK)
3205 		return -EINVAL;
3206 
3207 	if (!nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE] ||
3208 	    !nla_match[DEVLINK_ATTR_DPIPE_HEADER_INDEX] ||
3209 	    !nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID] ||
3210 	    !nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]) {
3211 		return -EINVAL;
3212 	}
3213 
3214 	match->type = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_MATCH_TYPE]);
3215 	match->info.header_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_HEADER_ID]);
3216 	match->info.field_id = mnl_attr_get_u32(nla_match[DEVLINK_ATTR_DPIPE_FIELD_ID]);
3217 	match->info.header_global = !!mnl_attr_get_u8(nla_match[DEVLINK_ATTR_DPIPE_HEADER_GLOBAL]);
3218 
3219 	return 0;
3220 }
3221 
dpipe_table_matches_show(struct dpipe_ctx * ctx,struct nlattr * nla_matches)3222 static int dpipe_table_matches_show(struct dpipe_ctx *ctx,
3223 				    struct nlattr *nla_matches)
3224 {
3225 	struct nlattr *nla_match;
3226 	struct dpipe_match match;
3227 
3228 	mnl_attr_for_each_nested(nla_match, nla_matches) {
3229 		pr_out_entry_start(ctx->dl);
3230 		if (dpipe_match_parse(&match, nla_match))
3231 			goto err_match_parse;
3232 		pr_out_dpipe_match(&match, ctx);
3233 		pr_out_entry_end(ctx->dl);
3234 	}
3235 	return 0;
3236 
3237 err_match_parse:
3238 	pr_out_entry_end(ctx->dl);
3239 	return -EINVAL;
3240 }
3241 
dpipe_table_show(struct dpipe_ctx * ctx,struct nlattr * nl)3242 static int dpipe_table_show(struct dpipe_ctx *ctx, struct nlattr *nl)
3243 {
3244 	struct nlattr *nla_table[DEVLINK_ATTR_MAX + 1] = {};
3245 	bool counters_enabled;
3246 	const char *name;
3247 	uint32_t size;
3248 	int err;
3249 
3250 	err = mnl_attr_parse_nested(nl, attr_cb, nla_table);
3251 	if (err != MNL_CB_OK)
3252 		return -EINVAL;
3253 
3254 	if (!nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME] ||
3255 	    !nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE] ||
3256 	    !nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS] ||
3257 	    !nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES] ||
3258 	    !nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]) {
3259 		return -EINVAL;
3260 	}
3261 
3262 	name = mnl_attr_get_str(nla_table[DEVLINK_ATTR_DPIPE_TABLE_NAME]);
3263 	size = mnl_attr_get_u32(nla_table[DEVLINK_ATTR_DPIPE_TABLE_SIZE]);
3264 	counters_enabled = !!mnl_attr_get_u8(nla_table[DEVLINK_ATTR_DPIPE_TABLE_COUNTERS_ENABLED]);
3265 
3266 	pr_out_str(ctx->dl, "name", name);
3267 	pr_out_uint(ctx->dl, "size", size);
3268 	pr_out_str(ctx->dl, "counters_enabled",
3269 		   counters_enabled ? "true" : "false");
3270 
3271 	pr_out_array_start(ctx->dl, "match");
3272 	if (dpipe_table_matches_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_MATCHES]))
3273 		goto err_matches_show;
3274 	pr_out_array_end(ctx->dl);
3275 
3276 	pr_out_array_start(ctx->dl, "action");
3277 	if (dpipe_table_actions_show(ctx, nla_table[DEVLINK_ATTR_DPIPE_TABLE_ACTIONS]))
3278 		goto err_actions_show;
3279 	pr_out_array_end(ctx->dl);
3280 
3281 	return 0;
3282 
3283 err_actions_show:
3284 err_matches_show:
3285 	pr_out_array_end(ctx->dl);
3286 	return -EINVAL;
3287 }
3288 
dpipe_tables_show(struct dpipe_ctx * ctx,struct nlattr ** tb)3289 static int dpipe_tables_show(struct dpipe_ctx *ctx, struct nlattr **tb)
3290 {
3291 	struct nlattr *nla_tables = tb[DEVLINK_ATTR_DPIPE_TABLES];
3292 	struct nlattr *nla_table;
3293 
3294 	mnl_attr_for_each_nested(nla_table, nla_tables) {
3295 		pr_out_handle_start_arr(ctx->dl, tb);
3296 		if (dpipe_table_show(ctx, nla_table))
3297 			goto err_table_show;
3298 		pr_out_handle_end(ctx->dl);
3299 	}
3300 	return 0;
3301 
3302 err_table_show:
3303 	pr_out_handle_end(ctx->dl);
3304 	return -EINVAL;
3305 }
3306 
cmd_dpipe_table_show_cb(const struct nlmsghdr * nlh,void * data)3307 static int cmd_dpipe_table_show_cb(const struct nlmsghdr *nlh, void *data)
3308 {
3309 	struct dpipe_ctx *ctx = data;
3310 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3311 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3312 
3313 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3314 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3315 	    !tb[DEVLINK_ATTR_DPIPE_TABLES])
3316 		return MNL_CB_ERROR;
3317 
3318 	if (dpipe_tables_show(ctx, tb))
3319 		return MNL_CB_ERROR;
3320 	return MNL_CB_OK;
3321 }
3322 
cmd_dpipe_table_show(struct dl * dl)3323 static int cmd_dpipe_table_show(struct dl *dl)
3324 {
3325 	struct nlmsghdr *nlh;
3326 	struct dpipe_ctx *ctx;
3327 	uint16_t flags = NLM_F_REQUEST;
3328 	int err;
3329 
3330 	ctx = dpipe_ctx_alloc(dl);
3331 	if (!ctx)
3332 		return -ENOMEM;
3333 
3334 	err = dl_argv_parse(dl, DL_OPT_HANDLE, DL_OPT_DPIPE_TABLE_NAME);
3335 	if (err)
3336 		goto out;
3337 
3338 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3339 	dl_opts_put(nlh, dl);
3340 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
3341 	if (err) {
3342 		pr_err("error get headers %s\n", strerror(ctx->err));
3343 		goto out;
3344 	}
3345 
3346 	flags = NLM_F_REQUEST | NLM_F_ACK;
3347 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_GET, flags);
3348 	dl_opts_put(nlh, dl);
3349 
3350 	pr_out_section_start(dl, "table");
3351 	_mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_show_cb, ctx);
3352 	pr_out_section_end(dl);
3353 out:
3354 	dpipe_ctx_clear(ctx);
3355 	dpipe_ctx_free(ctx);
3356 	return err;
3357 }
3358 
cmd_dpipe_table_set(struct dl * dl)3359 static int cmd_dpipe_table_set(struct dl *dl)
3360 {
3361 	struct nlmsghdr *nlh;
3362 	int err;
3363 
3364 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_TABLE_COUNTERS_SET,
3365 			       NLM_F_REQUEST | NLM_F_ACK);
3366 
3367 	err = dl_argv_parse_put(nlh, dl,
3368 				DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME |
3369 				DL_OPT_DPIPE_TABLE_COUNTERS, 0);
3370 	if (err)
3371 		return err;
3372 
3373 	return _mnlg_socket_sndrcv(dl->nlg, nlh, NULL, NULL);
3374 }
3375 
3376 enum dpipe_value_type {
3377 	DPIPE_VALUE_TYPE_VALUE,
3378 	DPIPE_VALUE_TYPE_MASK,
3379 };
3380 
3381 static const char *
dpipe_value_type_e2s(enum dpipe_value_type type)3382 dpipe_value_type_e2s(enum dpipe_value_type type)
3383 {
3384 	switch (type) {
3385 	case DPIPE_VALUE_TYPE_VALUE:
3386 		return "value";
3387 	case DPIPE_VALUE_TYPE_MASK:
3388 		return "value_mask";
3389 	default:
3390 		return "<unknown>";
3391 	}
3392 }
3393 
3394 struct dpipe_field_printer {
3395 	unsigned int field_id;
3396 	void (*printer)(struct dpipe_ctx *, enum dpipe_value_type, void *);
3397 };
3398 
3399 struct dpipe_header_printer {
3400 	struct dpipe_field_printer *printers;
3401 	unsigned int printers_count;
3402 	unsigned int header_id;
3403 };
3404 
dpipe_field_printer_ipv4_addr(struct dpipe_ctx * ctx,enum dpipe_value_type type,void * value)3405 static void dpipe_field_printer_ipv4_addr(struct dpipe_ctx *ctx,
3406 					  enum dpipe_value_type type,
3407 					  void *value)
3408 {
3409 	struct in_addr ip_addr;
3410 
3411 	ip_addr.s_addr = htonl(*(uint32_t *)value);
3412 	pr_out_str(ctx->dl, dpipe_value_type_e2s(type), inet_ntoa(ip_addr));
3413 }
3414 
3415 static void
dpipe_field_printer_ethernet_addr(struct dpipe_ctx * ctx,enum dpipe_value_type type,void * value)3416 dpipe_field_printer_ethernet_addr(struct dpipe_ctx *ctx,
3417 				  enum dpipe_value_type type,
3418 				  void *value)
3419 {
3420 	pr_out_str(ctx->dl, dpipe_value_type_e2s(type),
3421 		   ether_ntoa((struct ether_addr *)value));
3422 }
3423 
dpipe_field_printer_ipv6_addr(struct dpipe_ctx * ctx,enum dpipe_value_type type,void * value)3424 static void dpipe_field_printer_ipv6_addr(struct dpipe_ctx *ctx,
3425 					  enum dpipe_value_type type,
3426 					  void *value)
3427 {
3428 	char str[INET6_ADDRSTRLEN];
3429 
3430 	inet_ntop(AF_INET6, value, str, INET6_ADDRSTRLEN);
3431 	pr_out_str(ctx->dl, dpipe_value_type_e2s(type), str);
3432 }
3433 
3434 static struct dpipe_field_printer dpipe_field_printers_ipv4[] = {
3435 	{
3436 		.printer = dpipe_field_printer_ipv4_addr,
3437 		.field_id = DEVLINK_DPIPE_FIELD_IPV4_DST_IP,
3438 	}
3439 };
3440 
3441 static struct dpipe_header_printer dpipe_header_printer_ipv4  = {
3442 	.printers = dpipe_field_printers_ipv4,
3443 	.printers_count = ARRAY_SIZE(dpipe_field_printers_ipv4),
3444 	.header_id = DEVLINK_DPIPE_HEADER_IPV4,
3445 };
3446 
3447 static struct dpipe_field_printer dpipe_field_printers_ethernet[] = {
3448 	{
3449 		.printer = dpipe_field_printer_ethernet_addr,
3450 		.field_id = DEVLINK_DPIPE_FIELD_ETHERNET_DST_MAC,
3451 	},
3452 };
3453 
3454 static struct dpipe_header_printer dpipe_header_printer_ethernet = {
3455 	.printers = dpipe_field_printers_ethernet,
3456 	.printers_count = ARRAY_SIZE(dpipe_field_printers_ethernet),
3457 	.header_id = DEVLINK_DPIPE_HEADER_ETHERNET,
3458 };
3459 
3460 static struct dpipe_field_printer dpipe_field_printers_ipv6[] = {
3461 	{
3462 		.printer = dpipe_field_printer_ipv6_addr,
3463 		.field_id = DEVLINK_DPIPE_FIELD_IPV6_DST_IP,
3464 	}
3465 };
3466 
3467 static struct dpipe_header_printer dpipe_header_printer_ipv6 = {
3468 	.printers = dpipe_field_printers_ipv6,
3469 	.printers_count = ARRAY_SIZE(dpipe_field_printers_ipv6),
3470 	.header_id = DEVLINK_DPIPE_HEADER_IPV6,
3471 };
3472 
3473 static struct dpipe_header_printer *dpipe_header_printers[] = {
3474 	&dpipe_header_printer_ipv4,
3475 	&dpipe_header_printer_ethernet,
3476 	&dpipe_header_printer_ipv6,
3477 };
3478 
dpipe_print_prot_header(struct dpipe_ctx * ctx,struct dpipe_op_info * info,enum dpipe_value_type type,void * value)3479 static int dpipe_print_prot_header(struct dpipe_ctx *ctx,
3480 				   struct dpipe_op_info *info,
3481 				   enum dpipe_value_type type,
3482 				   void *value)
3483 {
3484 	unsigned int header_printers_count = ARRAY_SIZE(dpipe_header_printers);
3485 	struct dpipe_header_printer *header_printer;
3486 	struct dpipe_field_printer *field_printer;
3487 	unsigned int field_printers_count;
3488 	int j;
3489 	int i;
3490 
3491 	for (i = 0; i < header_printers_count; i++) {
3492 		header_printer = dpipe_header_printers[i];
3493 		if (header_printer->header_id != info->header_id)
3494 			continue;
3495 		field_printers_count = header_printer->printers_count;
3496 		for (j = 0; j < field_printers_count; j++) {
3497 			field_printer = &header_printer->printers[j];
3498 			if (field_printer->field_id != info->field_id)
3499 				continue;
3500 			field_printer->printer(ctx, type, value);
3501 			return 0;
3502 		}
3503 	}
3504 
3505 	return -EINVAL;
3506 }
3507 
__pr_out_entry_value(struct dpipe_ctx * ctx,void * value,unsigned int value_len,struct dpipe_op_info * info,enum dpipe_value_type type)3508 static void __pr_out_entry_value(struct dpipe_ctx *ctx,
3509 				 void *value,
3510 				 unsigned int value_len,
3511 				 struct dpipe_op_info *info,
3512 				 enum dpipe_value_type type)
3513 {
3514 	if (info->header_global &&
3515 	    !dpipe_print_prot_header(ctx, info, type, value))
3516 		return;
3517 
3518 	if (value_len == sizeof(uint32_t)) {
3519 		uint32_t *value_32 = value;
3520 
3521 		pr_out_uint(ctx->dl, dpipe_value_type_e2s(type), *value_32);
3522 	}
3523 }
3524 
pr_out_dpipe_entry_value(struct dpipe_ctx * ctx,struct nlattr ** nla_match_value,struct dpipe_op_info * info)3525 static void pr_out_dpipe_entry_value(struct dpipe_ctx *ctx,
3526 				     struct nlattr **nla_match_value,
3527 				     struct dpipe_op_info *info)
3528 {
3529 	void *value, *value_mask;
3530 	uint32_t value_mapping;
3531 	uint16_t value_len;
3532 	bool mask, mapping;
3533 
3534 	mask = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MASK];
3535 	mapping = !!nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING];
3536 
3537 	value_len = mnl_attr_get_payload_len(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3538 	value = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3539 
3540 	if (mapping) {
3541 		value_mapping = mnl_attr_get_u32(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE_MAPPING]);
3542 		pr_out_uint(ctx->dl, "mapping_value", value_mapping);
3543 	}
3544 
3545 	if (mask) {
3546 		value_mask = mnl_attr_get_payload(nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]);
3547 		__pr_out_entry_value(ctx, value_mask, value_len, info,
3548 				     DPIPE_VALUE_TYPE_MASK);
3549 	}
3550 
3551 	__pr_out_entry_value(ctx, value, value_len, info, DPIPE_VALUE_TYPE_VALUE);
3552 }
3553 
dpipe_entry_match_value_show(struct dpipe_ctx * ctx,struct nlattr * nl)3554 static int dpipe_entry_match_value_show(struct dpipe_ctx *ctx,
3555 					struct nlattr *nl)
3556 {
3557 	struct nlattr *nla_match_value[DEVLINK_ATTR_MAX + 1] = {};
3558 	struct dpipe_match match;
3559 	int err;
3560 
3561 	err = mnl_attr_parse_nested(nl, attr_cb, nla_match_value);
3562 	if (err != MNL_CB_OK)
3563 		return -EINVAL;
3564 
3565 	if (!nla_match_value[DEVLINK_ATTR_DPIPE_MATCH] ||
3566 	    !nla_match_value[DEVLINK_ATTR_DPIPE_VALUE]) {
3567 		return -EINVAL;
3568 	}
3569 
3570 	pr_out_entry_start(ctx->dl);
3571 	if (dpipe_match_parse(&match,
3572 			      nla_match_value[DEVLINK_ATTR_DPIPE_MATCH]))
3573 		goto err_match_parse;
3574 	pr_out_dpipe_match(&match, ctx);
3575 	pr_out_dpipe_entry_value(ctx, nla_match_value, &match.info);
3576 	pr_out_entry_end(ctx->dl);
3577 
3578 	return 0;
3579 
3580 err_match_parse:
3581 	pr_out_entry_end(ctx->dl);
3582 	return -EINVAL;
3583 }
3584 
dpipe_entry_action_value_show(struct dpipe_ctx * ctx,struct nlattr * nl)3585 static int dpipe_entry_action_value_show(struct dpipe_ctx *ctx,
3586 					 struct nlattr *nl)
3587 {
3588 	struct nlattr *nla_action_value[DEVLINK_ATTR_MAX + 1] = {};
3589 	struct dpipe_action action;
3590 	int err;
3591 
3592 	err = mnl_attr_parse_nested(nl, attr_cb, nla_action_value);
3593 	if (err != MNL_CB_OK)
3594 		return -EINVAL;
3595 
3596 	if (!nla_action_value[DEVLINK_ATTR_DPIPE_ACTION] ||
3597 	    !nla_action_value[DEVLINK_ATTR_DPIPE_VALUE]) {
3598 		return -EINVAL;
3599 	}
3600 
3601 	pr_out_entry_start(ctx->dl);
3602 	if (dpipe_action_parse(&action,
3603 			       nla_action_value[DEVLINK_ATTR_DPIPE_ACTION]))
3604 		goto err_action_parse;
3605 	pr_out_dpipe_action(&action, ctx);
3606 	pr_out_dpipe_entry_value(ctx, nla_action_value, &action.info);
3607 	pr_out_entry_end(ctx->dl);
3608 
3609 	return 0;
3610 
3611 err_action_parse:
3612 	pr_out_entry_end(ctx->dl);
3613 	return -EINVAL;
3614 }
3615 
3616 static int
dpipe_tables_action_values_show(struct dpipe_ctx * ctx,struct nlattr * nla_action_values)3617 dpipe_tables_action_values_show(struct dpipe_ctx *ctx,
3618 				struct nlattr *nla_action_values)
3619 {
3620 	struct nlattr *nla_action_value;
3621 
3622 	mnl_attr_for_each_nested(nla_action_value, nla_action_values) {
3623 		if (dpipe_entry_action_value_show(ctx, nla_action_value))
3624 			return -EINVAL;
3625 	}
3626 	return 0;
3627 }
3628 
3629 static int
dpipe_tables_match_values_show(struct dpipe_ctx * ctx,struct nlattr * nla_match_values)3630 dpipe_tables_match_values_show(struct dpipe_ctx *ctx,
3631 			       struct nlattr *nla_match_values)
3632 {
3633 	struct nlattr *nla_match_value;
3634 
3635 	mnl_attr_for_each_nested(nla_match_value, nla_match_values) {
3636 		if (dpipe_entry_match_value_show(ctx, nla_match_value))
3637 			return -EINVAL;
3638 	}
3639 	return 0;
3640 }
3641 
dpipe_entry_show(struct dpipe_ctx * ctx,struct nlattr * nl)3642 static int dpipe_entry_show(struct dpipe_ctx *ctx, struct nlattr *nl)
3643 {
3644 	struct nlattr *nla_entry[DEVLINK_ATTR_MAX + 1] = {};
3645 	uint32_t entry_index;
3646 	uint64_t counter;
3647 	int err;
3648 
3649 	err = mnl_attr_parse_nested(nl, attr_cb, nla_entry);
3650 	if (err != MNL_CB_OK)
3651 		return -EINVAL;
3652 
3653 	if (!nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX] ||
3654 	    !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES] ||
3655 	    !nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]) {
3656 		return -EINVAL;
3657 	}
3658 
3659 	entry_index = mnl_attr_get_u32(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_INDEX]);
3660 	pr_out_uint(ctx->dl, "index", entry_index);
3661 
3662 	if (nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]) {
3663 		counter = mnl_attr_get_u64(nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_COUNTER]);
3664 		pr_out_uint(ctx->dl, "counter", counter);
3665 	}
3666 
3667 	pr_out_array_start(ctx->dl, "match_value");
3668 	if (dpipe_tables_match_values_show(ctx,
3669 					   nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_MATCH_VALUES]))
3670 		goto err_match_values_show;
3671 	pr_out_array_end(ctx->dl);
3672 
3673 	pr_out_array_start(ctx->dl, "action_value");
3674 	if (dpipe_tables_action_values_show(ctx,
3675 					    nla_entry[DEVLINK_ATTR_DPIPE_ENTRY_ACTION_VALUES]))
3676 		goto err_action_values_show;
3677 	pr_out_array_end(ctx->dl);
3678 	return 0;
3679 
3680 err_action_values_show:
3681 err_match_values_show:
3682 	pr_out_array_end(ctx->dl);
3683 	return -EINVAL;
3684 }
3685 
dpipe_table_entries_show(struct dpipe_ctx * ctx,struct nlattr ** tb)3686 static int dpipe_table_entries_show(struct dpipe_ctx *ctx, struct nlattr **tb)
3687 {
3688 	struct nlattr *nla_entries = tb[DEVLINK_ATTR_DPIPE_ENTRIES];
3689 	struct nlattr *nla_entry;
3690 
3691 	mnl_attr_for_each_nested(nla_entry, nla_entries) {
3692 		pr_out_handle_start_arr(ctx->dl, tb);
3693 		if (dpipe_entry_show(ctx, nla_entry))
3694 			goto err_entry_show;
3695 		pr_out_handle_end(ctx->dl);
3696 	}
3697 	return 0;
3698 
3699 err_entry_show:
3700 	pr_out_handle_end(ctx->dl);
3701 	return -EINVAL;
3702 }
3703 
cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr * nlh,void * data)3704 static int cmd_dpipe_table_entry_dump_cb(const struct nlmsghdr *nlh, void *data)
3705 {
3706 	struct dpipe_ctx *ctx = data;
3707 	struct nlattr *tb[DEVLINK_ATTR_MAX + 1] = {};
3708 	struct genlmsghdr *genl = mnl_nlmsg_get_payload(nlh);
3709 
3710 	mnl_attr_parse(nlh, sizeof(*genl), attr_cb, tb);
3711 	if (!tb[DEVLINK_ATTR_BUS_NAME] || !tb[DEVLINK_ATTR_DEV_NAME] ||
3712 	    !tb[DEVLINK_ATTR_DPIPE_ENTRIES])
3713 		return MNL_CB_ERROR;
3714 
3715 	if (dpipe_table_entries_show(ctx, tb))
3716 		return MNL_CB_ERROR;
3717 	return MNL_CB_OK;
3718 }
3719 
cmd_dpipe_table_dump(struct dl * dl)3720 static int cmd_dpipe_table_dump(struct dl *dl)
3721 {
3722 	struct nlmsghdr *nlh;
3723 	struct dpipe_ctx *ctx;
3724 	uint16_t flags = NLM_F_REQUEST;
3725 	int err;
3726 
3727 	ctx = dpipe_ctx_alloc(dl);
3728 	if (!ctx)
3729 		return -ENOMEM;
3730 
3731 	err = dl_argv_parse(dl, DL_OPT_HANDLE | DL_OPT_DPIPE_TABLE_NAME, 0);
3732 	if (err)
3733 		goto out;
3734 
3735 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_HEADERS_GET, flags);
3736 	dl_opts_put(nlh, dl);
3737 	err = _mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_header_cb, ctx);
3738 	if (err) {
3739 		pr_err("error get headers %s\n", strerror(ctx->err));
3740 		goto out;
3741 	}
3742 
3743 	flags = NLM_F_REQUEST | NLM_F_ACK;
3744 	nlh = mnlg_msg_prepare(dl->nlg, DEVLINK_CMD_DPIPE_ENTRIES_GET, flags);
3745 	dl_opts_put(nlh, dl);
3746 
3747 	pr_out_section_start(dl, "table_entry");
3748 	_mnlg_socket_sndrcv(dl->nlg, nlh, cmd_dpipe_table_entry_dump_cb, ctx);
3749 	pr_out_section_end(dl);
3750 out:
3751 	dpipe_ctx_clear(ctx);
3752 	dpipe_ctx_free(ctx);
3753 	return err;
3754 }
3755 
cmd_dpipe_table_help(void)3756 static void cmd_dpipe_table_help(void)
3757 {
3758 	pr_err("Usage: devlink dpipe table [ OBJECT-LIST ]\n"
3759 	       "where  OBJECT-LIST := { show | set | dump }\n");
3760 }
3761 
cmd_dpipe_table(struct dl * dl)3762 static int cmd_dpipe_table(struct dl *dl)
3763 {
3764 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3765 		cmd_dpipe_table_help();
3766 		return 0;
3767 	} else if (dl_argv_match(dl, "show")) {
3768 		dl_arg_inc(dl);
3769 		return cmd_dpipe_table_show(dl);
3770 	} else if (dl_argv_match(dl, "set")) {
3771 		dl_arg_inc(dl);
3772 		return cmd_dpipe_table_set(dl);
3773 	}  else if (dl_argv_match(dl, "dump")) {
3774 		dl_arg_inc(dl);
3775 		return cmd_dpipe_table_dump(dl);
3776 	}
3777 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
3778 	return -ENOENT;
3779 }
3780 
cmd_dpipe_help(void)3781 static void cmd_dpipe_help(void)
3782 {
3783 	pr_err("Usage: devlink dpipe [ OBJECT-LIST ]\n"
3784 	       "where  OBJECT-LIST := { header | table }\n");
3785 }
3786 
cmd_dpipe(struct dl * dl)3787 static int cmd_dpipe(struct dl *dl)
3788 {
3789 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3790 		cmd_dpipe_help();
3791 		return 0;
3792 	} else if (dl_argv_match(dl, "header")) {
3793 		dl_arg_inc(dl);
3794 		return cmd_dpipe_header(dl);
3795 	} else if (dl_argv_match(dl, "table")) {
3796 		dl_arg_inc(dl);
3797 		return cmd_dpipe_table(dl);
3798 	}
3799 	pr_err("Command \"%s\" not found\n", dl_argv(dl));
3800 	return -ENOENT;
3801 }
3802 
help(void)3803 static void help(void)
3804 {
3805 	pr_err("Usage: devlink [ OPTIONS ] OBJECT { COMMAND | help }\n"
3806 	       "       devlink [ -f[orce] ] -b[atch] filename\n"
3807 	       "where  OBJECT := { dev | port | sb | monitor | dpipe }\n"
3808 	       "       OPTIONS := { -V[ersion] | -n[no-nice-names] | -j[json] | -p[pretty] | -v[verbose] }\n");
3809 }
3810 
dl_cmd(struct dl * dl,int argc,char ** argv)3811 static int dl_cmd(struct dl *dl, int argc, char **argv)
3812 {
3813 	dl->argc = argc;
3814 	dl->argv = argv;
3815 
3816 	if (dl_argv_match(dl, "help") || dl_no_arg(dl)) {
3817 		help();
3818 		return 0;
3819 	} else if (dl_argv_match(dl, "dev")) {
3820 		dl_arg_inc(dl);
3821 		return cmd_dev(dl);
3822 	} else if (dl_argv_match(dl, "port")) {
3823 		dl_arg_inc(dl);
3824 		return cmd_port(dl);
3825 	} else if (dl_argv_match(dl, "sb")) {
3826 		dl_arg_inc(dl);
3827 		return cmd_sb(dl);
3828 	} else if (dl_argv_match(dl, "monitor")) {
3829 		dl_arg_inc(dl);
3830 		return cmd_mon(dl);
3831 	} else if (dl_argv_match(dl, "dpipe")) {
3832 		dl_arg_inc(dl);
3833 		return cmd_dpipe(dl);
3834 	}
3835 	pr_err("Object \"%s\" not found\n", dl_argv(dl));
3836 	return -ENOENT;
3837 }
3838 
dl_init(struct dl * dl)3839 static int dl_init(struct dl *dl)
3840 {
3841 	int err;
3842 
3843 	dl->nlg = mnlg_socket_open(DEVLINK_GENL_NAME, DEVLINK_GENL_VERSION);
3844 	if (!dl->nlg) {
3845 		pr_err("Failed to connect to devlink Netlink\n");
3846 		return -errno;
3847 	}
3848 
3849 	err = ifname_map_init(dl);
3850 	if (err) {
3851 		pr_err("Failed to create index map\n");
3852 		goto err_ifname_map_create;
3853 	}
3854 	if (dl->json_output) {
3855 		dl->jw = jsonw_new(stdout);
3856 		if (!dl->jw) {
3857 			pr_err("Failed to create JSON writer\n");
3858 			goto err_json_new;
3859 		}
3860 		jsonw_pretty(dl->jw, dl->pretty_output);
3861 	}
3862 	return 0;
3863 
3864 err_json_new:
3865 	ifname_map_fini(dl);
3866 err_ifname_map_create:
3867 	mnlg_socket_close(dl->nlg);
3868 	return err;
3869 }
3870 
dl_fini(struct dl * dl)3871 static void dl_fini(struct dl *dl)
3872 {
3873 	if (dl->json_output)
3874 		jsonw_destroy(&dl->jw);
3875 	ifname_map_fini(dl);
3876 	mnlg_socket_close(dl->nlg);
3877 }
3878 
dl_alloc(void)3879 static struct dl *dl_alloc(void)
3880 {
3881 	struct dl *dl;
3882 
3883 	dl = calloc(1, sizeof(*dl));
3884 	if (!dl)
3885 		return NULL;
3886 	return dl;
3887 }
3888 
dl_free(struct dl * dl)3889 static void dl_free(struct dl *dl)
3890 {
3891 	free(dl);
3892 }
3893 
dl_batch(struct dl * dl,const char * name,bool force)3894 static int dl_batch(struct dl *dl, const char *name, bool force)
3895 {
3896 	char *line = NULL;
3897 	size_t len = 0;
3898 	int ret = EXIT_SUCCESS;
3899 
3900 	if (name && strcmp(name, "-") != 0) {
3901 		if (freopen(name, "r", stdin) == NULL) {
3902 			fprintf(stderr,
3903 				"Cannot open file \"%s\" for reading: %s\n",
3904 				name, strerror(errno));
3905 			return EXIT_FAILURE;
3906 		}
3907 	}
3908 
3909 	cmdlineno = 0;
3910 	while (getcmdline(&line, &len, stdin) != -1) {
3911 		char *largv[100];
3912 		int largc;
3913 
3914 		largc = makeargs(line, largv, 100);
3915 		if (!largc)
3916 			continue;	/* blank line */
3917 
3918 		if (dl_cmd(dl, largc, largv)) {
3919 			fprintf(stderr, "Command failed %s:%d\n",
3920 				name, cmdlineno);
3921 			ret = EXIT_FAILURE;
3922 			if (!force)
3923 				break;
3924 		}
3925 	}
3926 
3927 	if (line)
3928 		free(line);
3929 
3930 	return ret;
3931 }
3932 
main(int argc,char ** argv)3933 int main(int argc, char **argv)
3934 {
3935 	static const struct option long_options[] = {
3936 		{ "Version",		no_argument,		NULL, 'V' },
3937 		{ "force",		no_argument,		NULL, 'f' },
3938 		{ "batch",		required_argument,	NULL, 'b' },
3939 		{ "no-nice-names",	no_argument,		NULL, 'n' },
3940 		{ "json",		no_argument,		NULL, 'j' },
3941 		{ "pretty",		no_argument,		NULL, 'p' },
3942 		{ "verbose",		no_argument,		NULL, 'v' },
3943 		{ NULL, 0, NULL, 0 }
3944 	};
3945 	const char *batch_file = NULL;
3946 	bool force = false;
3947 	struct dl *dl;
3948 	int opt;
3949 	int err;
3950 	int ret;
3951 
3952 	dl = dl_alloc();
3953 	if (!dl) {
3954 		pr_err("Failed to allocate memory for devlink\n");
3955 		return EXIT_FAILURE;
3956 	}
3957 
3958 	while ((opt = getopt_long(argc, argv, "Vfb:njpv",
3959 				  long_options, NULL)) >= 0) {
3960 
3961 		switch (opt) {
3962 		case 'V':
3963 			printf("devlink utility, iproute2-ss%s\n", SNAPSHOT);
3964 			ret = EXIT_SUCCESS;
3965 			goto dl_free;
3966 		case 'f':
3967 			force = true;
3968 			break;
3969 		case 'b':
3970 			batch_file = optarg;
3971 			break;
3972 		case 'n':
3973 			dl->no_nice_names = true;
3974 			break;
3975 		case 'j':
3976 			dl->json_output = true;
3977 			break;
3978 		case 'p':
3979 			dl->pretty_output = true;
3980 			break;
3981 		case 'v':
3982 			dl->verbose = true;
3983 			break;
3984 		default:
3985 			pr_err("Unknown option.\n");
3986 			help();
3987 			ret = EXIT_FAILURE;
3988 			goto dl_free;
3989 		}
3990 	}
3991 
3992 	argc -= optind;
3993 	argv += optind;
3994 
3995 	err = dl_init(dl);
3996 	if (err) {
3997 		ret = EXIT_FAILURE;
3998 		goto dl_free;
3999 	}
4000 
4001 	if (batch_file)
4002 		err = dl_batch(dl, batch_file, force);
4003 	else
4004 		err = dl_cmd(dl, argc, argv);
4005 
4006 	if (err) {
4007 		ret = EXIT_FAILURE;
4008 		goto dl_fini;
4009 	}
4010 
4011 	ret = EXIT_SUCCESS;
4012 
4013 dl_fini:
4014 	dl_fini(dl);
4015 dl_free:
4016 	dl_free(dl);
4017 
4018 	return ret;
4019 }
4020