1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
22bfe3f2eSlogwang  * Copyright 2017 6WIND S.A.
3d30ea906Sjfb8856606  * Copyright 2017 Mellanox Technologies, Ltd
42bfe3f2eSlogwang  */
52bfe3f2eSlogwang 
6d30ea906Sjfb8856606 #include <fcntl.h>
7d30ea906Sjfb8856606 #include <stdio.h>
8d30ea906Sjfb8856606 #include <stdlib.h>
92bfe3f2eSlogwang #include <string.h>
10d30ea906Sjfb8856606 #include <unistd.h>
112bfe3f2eSlogwang #include <errno.h>
122bfe3f2eSlogwang 
132bfe3f2eSlogwang #include <rte_debug.h>
142bfe3f2eSlogwang #include <rte_devargs.h>
152bfe3f2eSlogwang #include <rte_malloc.h>
162bfe3f2eSlogwang #include <rte_kvargs.h>
17d30ea906Sjfb8856606 #include <rte_string_fns.h>
182bfe3f2eSlogwang 
192bfe3f2eSlogwang #include "failsafe_private.h"
202bfe3f2eSlogwang 
212bfe3f2eSlogwang /* Callback used when a new device is found in devargs */
222bfe3f2eSlogwang typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
232bfe3f2eSlogwang 		uint8_t head);
242bfe3f2eSlogwang 
25d30ea906Sjfb8856606 uint64_t failsafe_hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
26d30ea906Sjfb8856606 int failsafe_mac_from_arg;
272bfe3f2eSlogwang 
28d30ea906Sjfb8856606 static const char * const pmd_failsafe_init_parameters[] = {
292bfe3f2eSlogwang 	PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
302bfe3f2eSlogwang 	PMD_FAILSAFE_MAC_KVARG,
312bfe3f2eSlogwang 	NULL,
322bfe3f2eSlogwang };
332bfe3f2eSlogwang 
342bfe3f2eSlogwang /*
352bfe3f2eSlogwang  * input: text.
362bfe3f2eSlogwang  * output: 0: if text[0] != '(',
372bfe3f2eSlogwang  *         0: if there are no corresponding ')'
382bfe3f2eSlogwang  *         n: distance to corresponding ')' otherwise
392bfe3f2eSlogwang  */
402bfe3f2eSlogwang static size_t
closing_paren(const char * text)412bfe3f2eSlogwang closing_paren(const char *text)
422bfe3f2eSlogwang {
432bfe3f2eSlogwang 	int nb_open = 0;
442bfe3f2eSlogwang 	size_t i = 0;
452bfe3f2eSlogwang 
462bfe3f2eSlogwang 	while (text[i] != '\0') {
472bfe3f2eSlogwang 		if (text[i] == '(')
482bfe3f2eSlogwang 			nb_open++;
492bfe3f2eSlogwang 		if (text[i] == ')')
502bfe3f2eSlogwang 			nb_open--;
512bfe3f2eSlogwang 		if (nb_open == 0)
522bfe3f2eSlogwang 			return i;
532bfe3f2eSlogwang 		i++;
542bfe3f2eSlogwang 	}
552bfe3f2eSlogwang 	return 0;
562bfe3f2eSlogwang }
572bfe3f2eSlogwang 
582bfe3f2eSlogwang static int
fs_parse_device(struct sub_device * sdev,char * args)592bfe3f2eSlogwang fs_parse_device(struct sub_device *sdev, char *args)
602bfe3f2eSlogwang {
612bfe3f2eSlogwang 	struct rte_devargs *d;
622bfe3f2eSlogwang 	int ret;
632bfe3f2eSlogwang 
642bfe3f2eSlogwang 	d = &sdev->devargs;
652bfe3f2eSlogwang 	DEBUG("%s", args);
66d30ea906Sjfb8856606 	ret = rte_devargs_parse(d, args);
672bfe3f2eSlogwang 	if (ret) {
682bfe3f2eSlogwang 		DEBUG("devargs parsing failed with code %d", ret);
692bfe3f2eSlogwang 		return ret;
702bfe3f2eSlogwang 	}
712bfe3f2eSlogwang 	sdev->bus = d->bus;
722bfe3f2eSlogwang 	sdev->state = DEV_PARSED;
732bfe3f2eSlogwang 	return 0;
742bfe3f2eSlogwang }
752bfe3f2eSlogwang 
762bfe3f2eSlogwang static void
fs_sanitize_cmdline(char * args)772bfe3f2eSlogwang fs_sanitize_cmdline(char *args)
782bfe3f2eSlogwang {
792bfe3f2eSlogwang 	char *nl;
802bfe3f2eSlogwang 
812bfe3f2eSlogwang 	nl = strrchr(args, '\n');
822bfe3f2eSlogwang 	if (nl)
832bfe3f2eSlogwang 		nl[0] = '\0';
842bfe3f2eSlogwang }
852bfe3f2eSlogwang 
862bfe3f2eSlogwang static int
fs_execute_cmd(struct sub_device * sdev,char * cmdline)872bfe3f2eSlogwang fs_execute_cmd(struct sub_device *sdev, char *cmdline)
882bfe3f2eSlogwang {
892bfe3f2eSlogwang 	FILE *fp;
902bfe3f2eSlogwang 	/* store possible newline as well */
912bfe3f2eSlogwang 	char output[DEVARGS_MAXLEN + 1];
922bfe3f2eSlogwang 	size_t len;
932bfe3f2eSlogwang 	int ret;
942bfe3f2eSlogwang 
952bfe3f2eSlogwang 	RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL);
962bfe3f2eSlogwang 	if (sdev->cmdline == NULL) {
972bfe3f2eSlogwang 		size_t i;
982bfe3f2eSlogwang 
992bfe3f2eSlogwang 		len = strlen(cmdline) + 1;
1002bfe3f2eSlogwang 		sdev->cmdline = calloc(1, len);
1012bfe3f2eSlogwang 		if (sdev->cmdline == NULL) {
1022bfe3f2eSlogwang 			ERROR("Command line allocation failed");
1032bfe3f2eSlogwang 			return -ENOMEM;
1042bfe3f2eSlogwang 		}
105*4418919fSjohnjiang 		strlcpy(sdev->cmdline, cmdline, len);
1062bfe3f2eSlogwang 		/* Replace all commas in the command line by spaces */
1072bfe3f2eSlogwang 		for (i = 0; i < len; i++)
1082bfe3f2eSlogwang 			if (sdev->cmdline[i] == ',')
1092bfe3f2eSlogwang 				sdev->cmdline[i] = ' ';
1102bfe3f2eSlogwang 	}
1112bfe3f2eSlogwang 	DEBUG("'%s'", sdev->cmdline);
1122bfe3f2eSlogwang 	fp = popen(sdev->cmdline, "r");
1132bfe3f2eSlogwang 	if (fp == NULL) {
1142bfe3f2eSlogwang 		ret = -errno;
1152bfe3f2eSlogwang 		ERROR("popen: %s", strerror(errno));
1162bfe3f2eSlogwang 		return ret;
1172bfe3f2eSlogwang 	}
1182bfe3f2eSlogwang 	/* We only read one line */
1192bfe3f2eSlogwang 	if (fgets(output, sizeof(output) - 1, fp) == NULL) {
1202bfe3f2eSlogwang 		DEBUG("Could not read command output");
1212bfe3f2eSlogwang 		ret = -ENODEV;
1222bfe3f2eSlogwang 		goto ret_pclose;
1232bfe3f2eSlogwang 	}
1242bfe3f2eSlogwang 	fs_sanitize_cmdline(output);
1252bfe3f2eSlogwang 	if (output[0] == '\0') {
1262bfe3f2eSlogwang 		ret = -ENODEV;
1272bfe3f2eSlogwang 		goto ret_pclose;
1282bfe3f2eSlogwang 	}
1292bfe3f2eSlogwang 	ret = fs_parse_device(sdev, output);
1302bfe3f2eSlogwang 	if (ret)
1312bfe3f2eSlogwang 		ERROR("Parsing device '%s' failed", output);
1322bfe3f2eSlogwang ret_pclose:
1332bfe3f2eSlogwang 	if (pclose(fp) == -1)
1342bfe3f2eSlogwang 		ERROR("pclose: %s", strerror(errno));
1352bfe3f2eSlogwang 	return ret;
1362bfe3f2eSlogwang }
1372bfe3f2eSlogwang 
1382bfe3f2eSlogwang static int
fs_read_fd(struct sub_device * sdev,char * fd_str)139d30ea906Sjfb8856606 fs_read_fd(struct sub_device *sdev, char *fd_str)
140d30ea906Sjfb8856606 {
141d30ea906Sjfb8856606 	FILE *fp = NULL;
142d30ea906Sjfb8856606 	int fd = -1;
143d30ea906Sjfb8856606 	/* store possible newline as well */
144d30ea906Sjfb8856606 	char output[DEVARGS_MAXLEN + 1];
145d30ea906Sjfb8856606 	int err = -ENODEV;
146d30ea906Sjfb8856606 	int oflags;
147d30ea906Sjfb8856606 	int lcount;
148d30ea906Sjfb8856606 
149d30ea906Sjfb8856606 	RTE_ASSERT(fd_str != NULL || sdev->fd_str != NULL);
150d30ea906Sjfb8856606 	if (sdev->fd_str == NULL) {
151d30ea906Sjfb8856606 		sdev->fd_str = strdup(fd_str);
152d30ea906Sjfb8856606 		if (sdev->fd_str == NULL) {
153d30ea906Sjfb8856606 			ERROR("Command line allocation failed");
154d30ea906Sjfb8856606 			return -ENOMEM;
155d30ea906Sjfb8856606 		}
156d30ea906Sjfb8856606 	}
157d30ea906Sjfb8856606 	errno = 0;
158d30ea906Sjfb8856606 	fd = strtol(fd_str, &fd_str, 0);
159d30ea906Sjfb8856606 	if (errno || *fd_str || fd < 0) {
160d30ea906Sjfb8856606 		ERROR("Parsing FD number failed");
161d30ea906Sjfb8856606 		goto error;
162d30ea906Sjfb8856606 	}
163d30ea906Sjfb8856606 	/* Fiddle with copy of file descriptor */
164d30ea906Sjfb8856606 	fd = dup(fd);
165d30ea906Sjfb8856606 	if (fd == -1)
166d30ea906Sjfb8856606 		goto error;
167d30ea906Sjfb8856606 	oflags = fcntl(fd, F_GETFL);
168d30ea906Sjfb8856606 	if (oflags == -1)
169d30ea906Sjfb8856606 		goto error;
170d30ea906Sjfb8856606 	if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1)
171d30ea906Sjfb8856606 		goto error;
172d30ea906Sjfb8856606 	fp = fdopen(fd, "r");
173d30ea906Sjfb8856606 	if (fp == NULL)
174d30ea906Sjfb8856606 		goto error;
175d30ea906Sjfb8856606 	fd = -1;
176d30ea906Sjfb8856606 	/* Only take the last line into account */
177d30ea906Sjfb8856606 	lcount = 0;
178d30ea906Sjfb8856606 	while (fgets(output, sizeof(output), fp))
179d30ea906Sjfb8856606 		++lcount;
180d30ea906Sjfb8856606 	if (lcount == 0)
181d30ea906Sjfb8856606 		goto error;
182d30ea906Sjfb8856606 	else if (ferror(fp) && errno != EAGAIN)
183d30ea906Sjfb8856606 		goto error;
184d30ea906Sjfb8856606 	/* Line must end with a newline character */
185d30ea906Sjfb8856606 	fs_sanitize_cmdline(output);
186d30ea906Sjfb8856606 	if (output[0] == '\0')
187d30ea906Sjfb8856606 		goto error;
188d30ea906Sjfb8856606 	err = fs_parse_device(sdev, output);
189d30ea906Sjfb8856606 	if (err)
190d30ea906Sjfb8856606 		ERROR("Parsing device '%s' failed", output);
191d30ea906Sjfb8856606 error:
192d30ea906Sjfb8856606 	if (fp)
193d30ea906Sjfb8856606 		fclose(fp);
194d30ea906Sjfb8856606 	if (fd != -1)
195d30ea906Sjfb8856606 		close(fd);
196d30ea906Sjfb8856606 	return err;
197d30ea906Sjfb8856606 }
198d30ea906Sjfb8856606 
199d30ea906Sjfb8856606 static int
fs_parse_device_param(struct rte_eth_dev * dev,const char * param,uint8_t head)2002bfe3f2eSlogwang fs_parse_device_param(struct rte_eth_dev *dev, const char *param,
2012bfe3f2eSlogwang 		uint8_t head)
2022bfe3f2eSlogwang {
2032bfe3f2eSlogwang 	struct fs_priv *priv;
2042bfe3f2eSlogwang 	struct sub_device *sdev;
2052bfe3f2eSlogwang 	char *args = NULL;
2062bfe3f2eSlogwang 	size_t a, b;
2072bfe3f2eSlogwang 	int ret;
2082bfe3f2eSlogwang 
2092bfe3f2eSlogwang 	priv = PRIV(dev);
2102bfe3f2eSlogwang 	a = 0;
2112bfe3f2eSlogwang 	b = 0;
2122bfe3f2eSlogwang 	ret = 0;
2132bfe3f2eSlogwang 	while  (param[b] != '(' &&
2142bfe3f2eSlogwang 		param[b] != '\0')
2152bfe3f2eSlogwang 		b++;
2162bfe3f2eSlogwang 	a = b;
2172bfe3f2eSlogwang 	b += closing_paren(&param[b]);
2182bfe3f2eSlogwang 	if (a == b) {
2192bfe3f2eSlogwang 		ERROR("Dangling parenthesis");
2202bfe3f2eSlogwang 		return -EINVAL;
2212bfe3f2eSlogwang 	}
2222bfe3f2eSlogwang 	a += 1;
2232bfe3f2eSlogwang 	args = strndup(&param[a], b - a);
2242bfe3f2eSlogwang 	if (args == NULL) {
2252bfe3f2eSlogwang 		ERROR("Not enough memory for parameter parsing");
2262bfe3f2eSlogwang 		return -ENOMEM;
2272bfe3f2eSlogwang 	}
2282bfe3f2eSlogwang 	sdev = &priv->subs[head];
2292bfe3f2eSlogwang 	if (strncmp(param, "dev", 3) == 0) {
2302bfe3f2eSlogwang 		ret = fs_parse_device(sdev, args);
2312bfe3f2eSlogwang 		if (ret)
2322bfe3f2eSlogwang 			goto free_args;
2332bfe3f2eSlogwang 	} else if (strncmp(param, "exec", 4) == 0) {
2342bfe3f2eSlogwang 		ret = fs_execute_cmd(sdev, args);
2352bfe3f2eSlogwang 		if (ret == -ENODEV) {
2362bfe3f2eSlogwang 			DEBUG("Reading device info from command line failed");
2372bfe3f2eSlogwang 			ret = 0;
2382bfe3f2eSlogwang 		}
2392bfe3f2eSlogwang 		if (ret)
2402bfe3f2eSlogwang 			goto free_args;
241d30ea906Sjfb8856606 	} else if (strncmp(param, "fd(", 3) == 0) {
242d30ea906Sjfb8856606 		ret = fs_read_fd(sdev, args);
243d30ea906Sjfb8856606 		if (ret == -ENODEV) {
244d30ea906Sjfb8856606 			DEBUG("Reading device info from FD failed");
245d30ea906Sjfb8856606 			ret = 0;
246d30ea906Sjfb8856606 		}
247d30ea906Sjfb8856606 		if (ret)
248d30ea906Sjfb8856606 			goto free_args;
2492bfe3f2eSlogwang 	} else {
2502bfe3f2eSlogwang 		ERROR("Unrecognized device type: %.*s", (int)b, param);
2512bfe3f2eSlogwang 		return -EINVAL;
2522bfe3f2eSlogwang 	}
2532bfe3f2eSlogwang free_args:
2542bfe3f2eSlogwang 	free(args);
2552bfe3f2eSlogwang 	return ret;
2562bfe3f2eSlogwang }
2572bfe3f2eSlogwang 
2582bfe3f2eSlogwang static int
fs_parse_sub_devices(parse_cb * cb,struct rte_eth_dev * dev,const char * params)2592bfe3f2eSlogwang fs_parse_sub_devices(parse_cb *cb,
2602bfe3f2eSlogwang 		struct rte_eth_dev *dev, const char *params)
2612bfe3f2eSlogwang {
2622bfe3f2eSlogwang 	size_t a, b;
2632bfe3f2eSlogwang 	uint8_t head;
2642bfe3f2eSlogwang 	int ret;
2652bfe3f2eSlogwang 
2662bfe3f2eSlogwang 	a = 0;
2672bfe3f2eSlogwang 	head = 0;
2682bfe3f2eSlogwang 	ret = 0;
2692bfe3f2eSlogwang 	while (params[a] != '\0') {
2702bfe3f2eSlogwang 		b = a;
2712bfe3f2eSlogwang 		while (params[b] != '(' &&
2722bfe3f2eSlogwang 		       params[b] != ',' &&
2732bfe3f2eSlogwang 		       params[b] != '\0')
2742bfe3f2eSlogwang 			b++;
2752bfe3f2eSlogwang 		if (b == a) {
2762bfe3f2eSlogwang 			ERROR("Invalid parameter");
2772bfe3f2eSlogwang 			return -EINVAL;
2782bfe3f2eSlogwang 		}
2792bfe3f2eSlogwang 		if (params[b] == ',') {
2802bfe3f2eSlogwang 			a = b + 1;
2812bfe3f2eSlogwang 			continue;
2822bfe3f2eSlogwang 		}
2832bfe3f2eSlogwang 		if (params[b] == '(') {
2842bfe3f2eSlogwang 			size_t start = b;
2852bfe3f2eSlogwang 
2862bfe3f2eSlogwang 			b += closing_paren(&params[b]);
2872bfe3f2eSlogwang 			if (b == start) {
2882bfe3f2eSlogwang 				ERROR("Dangling parenthesis");
2892bfe3f2eSlogwang 				return -EINVAL;
2902bfe3f2eSlogwang 			}
2912bfe3f2eSlogwang 			ret = (*cb)(dev, &params[a], head);
2922bfe3f2eSlogwang 			if (ret)
2932bfe3f2eSlogwang 				return ret;
2942bfe3f2eSlogwang 			head += 1;
2952bfe3f2eSlogwang 			b += 1;
2962bfe3f2eSlogwang 			if (params[b] == '\0')
2972bfe3f2eSlogwang 				return 0;
2982bfe3f2eSlogwang 		}
2992bfe3f2eSlogwang 		a = b + 1;
3002bfe3f2eSlogwang 	}
3012bfe3f2eSlogwang 	return 0;
3022bfe3f2eSlogwang }
3032bfe3f2eSlogwang 
3042bfe3f2eSlogwang static int
fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])3052bfe3f2eSlogwang fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
3062bfe3f2eSlogwang {
3072bfe3f2eSlogwang 	char buffer[DEVARGS_MAXLEN] = {0};
3082bfe3f2eSlogwang 	size_t a, b;
3092bfe3f2eSlogwang 	int i;
3102bfe3f2eSlogwang 
3112bfe3f2eSlogwang 	a = 0;
3122bfe3f2eSlogwang 	i = 0;
3132bfe3f2eSlogwang 	while (params[a] != '\0') {
3142bfe3f2eSlogwang 		b = a;
3152bfe3f2eSlogwang 		while (params[b] != '(' &&
3162bfe3f2eSlogwang 		       params[b] != ',' &&
3172bfe3f2eSlogwang 		       params[b] != '\0')
3182bfe3f2eSlogwang 			b++;
3192bfe3f2eSlogwang 		if (b == a) {
3202bfe3f2eSlogwang 			ERROR("Invalid parameter");
3212bfe3f2eSlogwang 			return -EINVAL;
3222bfe3f2eSlogwang 		}
3232bfe3f2eSlogwang 		if (params[b] == ',' || params[b] == '\0') {
3242bfe3f2eSlogwang 			size_t len = b - a;
3252bfe3f2eSlogwang 
3262bfe3f2eSlogwang 			if (i > 0)
3272bfe3f2eSlogwang 				len += 1;
3282bfe3f2eSlogwang 			snprintf(&buffer[i], len + 1, "%s%s",
3292bfe3f2eSlogwang 					i ? "," : "", &params[a]);
3302bfe3f2eSlogwang 			i += len;
3312bfe3f2eSlogwang 		} else if (params[b] == '(') {
3322bfe3f2eSlogwang 			size_t start = b;
3332bfe3f2eSlogwang 
3342bfe3f2eSlogwang 			b += closing_paren(&params[b]);
3352bfe3f2eSlogwang 			if (b == start)
3362bfe3f2eSlogwang 				return -EINVAL;
3372bfe3f2eSlogwang 			b += 1;
3382bfe3f2eSlogwang 			if (params[b] == '\0')
3392bfe3f2eSlogwang 				goto out;
3402bfe3f2eSlogwang 		}
3412bfe3f2eSlogwang 		a = b + 1;
3422bfe3f2eSlogwang 	}
3432bfe3f2eSlogwang out:
344d30ea906Sjfb8856606 	strlcpy(params, buffer, DEVARGS_MAXLEN);
3452bfe3f2eSlogwang 	return 0;
3462bfe3f2eSlogwang }
3472bfe3f2eSlogwang 
3482bfe3f2eSlogwang static int
fs_get_u64_arg(const char * key __rte_unused,const char * value,void * out)3492bfe3f2eSlogwang fs_get_u64_arg(const char *key __rte_unused,
3502bfe3f2eSlogwang 		const char *value, void *out)
3512bfe3f2eSlogwang {
3522bfe3f2eSlogwang 	uint64_t *u64 = out;
3532bfe3f2eSlogwang 	char *endptr = NULL;
3542bfe3f2eSlogwang 
3552bfe3f2eSlogwang 	if ((value == NULL) || (out == NULL))
3562bfe3f2eSlogwang 		return -EINVAL;
3572bfe3f2eSlogwang 	errno = 0;
3582bfe3f2eSlogwang 	*u64 = strtoull(value, &endptr, 0);
3592bfe3f2eSlogwang 	if (errno != 0)
3602bfe3f2eSlogwang 		return -errno;
3612bfe3f2eSlogwang 	if (endptr == value)
3622bfe3f2eSlogwang 		return -1;
3632bfe3f2eSlogwang 	return 0;
3642bfe3f2eSlogwang }
3652bfe3f2eSlogwang 
3662bfe3f2eSlogwang static int
fs_get_mac_addr_arg(const char * key __rte_unused,const char * value,void * out)3672bfe3f2eSlogwang fs_get_mac_addr_arg(const char *key __rte_unused,
3682bfe3f2eSlogwang 		const char *value, void *out)
3692bfe3f2eSlogwang {
370*4418919fSjohnjiang 	struct rte_ether_addr *ea = out;
3712bfe3f2eSlogwang 
3722bfe3f2eSlogwang 	if ((value == NULL) || (out == NULL))
3732bfe3f2eSlogwang 		return -EINVAL;
374*4418919fSjohnjiang 
375*4418919fSjohnjiang 	return rte_ether_unformat_addr(value, ea);
3762bfe3f2eSlogwang }
3772bfe3f2eSlogwang 
3782bfe3f2eSlogwang int
failsafe_args_parse(struct rte_eth_dev * dev,const char * params)3792bfe3f2eSlogwang failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
3802bfe3f2eSlogwang {
3812bfe3f2eSlogwang 	struct fs_priv *priv;
3822bfe3f2eSlogwang 	char mut_params[DEVARGS_MAXLEN] = "";
3832bfe3f2eSlogwang 	struct rte_kvargs *kvlist = NULL;
3842bfe3f2eSlogwang 	unsigned int arg_count;
3852bfe3f2eSlogwang 	size_t n;
3862bfe3f2eSlogwang 	int ret;
3872bfe3f2eSlogwang 
3882bfe3f2eSlogwang 	priv = PRIV(dev);
3892bfe3f2eSlogwang 	ret = 0;
3902bfe3f2eSlogwang 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
3912bfe3f2eSlogwang 	/* default parameters */
392d30ea906Sjfb8856606 	n = strlcpy(mut_params, params, sizeof(mut_params));
3932bfe3f2eSlogwang 	if (n >= sizeof(mut_params)) {
3942bfe3f2eSlogwang 		ERROR("Parameter string too long (>=%zu)",
3952bfe3f2eSlogwang 				sizeof(mut_params));
3962bfe3f2eSlogwang 		return -ENOMEM;
3972bfe3f2eSlogwang 	}
3982bfe3f2eSlogwang 	ret = fs_parse_sub_devices(fs_parse_device_param,
3992bfe3f2eSlogwang 				   dev, params);
4002bfe3f2eSlogwang 	if (ret < 0)
4012bfe3f2eSlogwang 		return ret;
4022bfe3f2eSlogwang 	ret = fs_remove_sub_devices_definition(mut_params);
4032bfe3f2eSlogwang 	if (ret < 0)
4042bfe3f2eSlogwang 		return ret;
4052bfe3f2eSlogwang 	if (strnlen(mut_params, sizeof(mut_params)) > 0) {
4062bfe3f2eSlogwang 		kvlist = rte_kvargs_parse(mut_params,
4072bfe3f2eSlogwang 				pmd_failsafe_init_parameters);
4082bfe3f2eSlogwang 		if (kvlist == NULL) {
4092bfe3f2eSlogwang 			ERROR("Error parsing parameters, usage:\n"
4102bfe3f2eSlogwang 				PMD_FAILSAFE_PARAM_STRING);
4112bfe3f2eSlogwang 			return -1;
4122bfe3f2eSlogwang 		}
4132bfe3f2eSlogwang 		/* PLUG_IN event poll timer */
4142bfe3f2eSlogwang 		arg_count = rte_kvargs_count(kvlist,
4152bfe3f2eSlogwang 				PMD_FAILSAFE_HOTPLUG_POLL_KVARG);
4162bfe3f2eSlogwang 		if (arg_count == 1) {
4172bfe3f2eSlogwang 			ret = rte_kvargs_process(kvlist,
4182bfe3f2eSlogwang 					PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
419d30ea906Sjfb8856606 					&fs_get_u64_arg, &failsafe_hotplug_poll);
4202bfe3f2eSlogwang 			if (ret < 0)
4212bfe3f2eSlogwang 				goto free_kvlist;
4222bfe3f2eSlogwang 		}
4232bfe3f2eSlogwang 		/* MAC addr */
4242bfe3f2eSlogwang 		arg_count = rte_kvargs_count(kvlist,
4252bfe3f2eSlogwang 				PMD_FAILSAFE_MAC_KVARG);
4262bfe3f2eSlogwang 		if (arg_count > 0) {
4272bfe3f2eSlogwang 			ret = rte_kvargs_process(kvlist,
4282bfe3f2eSlogwang 					PMD_FAILSAFE_MAC_KVARG,
4292bfe3f2eSlogwang 					&fs_get_mac_addr_arg,
4302bfe3f2eSlogwang 					&dev->data->mac_addrs[0]);
4312bfe3f2eSlogwang 			if (ret < 0)
4322bfe3f2eSlogwang 				goto free_kvlist;
4332bfe3f2eSlogwang 
434d30ea906Sjfb8856606 			failsafe_mac_from_arg = 1;
4352bfe3f2eSlogwang 		}
4362bfe3f2eSlogwang 	}
4372bfe3f2eSlogwang 	PRIV(dev)->state = DEV_PARSED;
4382bfe3f2eSlogwang free_kvlist:
4392bfe3f2eSlogwang 	rte_kvargs_free(kvlist);
4402bfe3f2eSlogwang 	return ret;
4412bfe3f2eSlogwang }
4422bfe3f2eSlogwang 
4432bfe3f2eSlogwang void
failsafe_args_free(struct rte_eth_dev * dev)4442bfe3f2eSlogwang failsafe_args_free(struct rte_eth_dev *dev)
4452bfe3f2eSlogwang {
4462bfe3f2eSlogwang 	struct sub_device *sdev;
4472bfe3f2eSlogwang 	uint8_t i;
4482bfe3f2eSlogwang 
4492bfe3f2eSlogwang 	FOREACH_SUBDEV(sdev, i, dev) {
4502bfe3f2eSlogwang 		free(sdev->cmdline);
4512bfe3f2eSlogwang 		sdev->cmdline = NULL;
452d30ea906Sjfb8856606 		free(sdev->fd_str);
453d30ea906Sjfb8856606 		sdev->fd_str = NULL;
4542bfe3f2eSlogwang 		free(sdev->devargs.args);
4552bfe3f2eSlogwang 		sdev->devargs.args = NULL;
4562bfe3f2eSlogwang 	}
4572bfe3f2eSlogwang }
4582bfe3f2eSlogwang 
4592bfe3f2eSlogwang static int
fs_count_device(struct rte_eth_dev * dev,const char * param,uint8_t head __rte_unused)4602bfe3f2eSlogwang fs_count_device(struct rte_eth_dev *dev, const char *param,
4612bfe3f2eSlogwang 		uint8_t head __rte_unused)
4622bfe3f2eSlogwang {
4632bfe3f2eSlogwang 	size_t b = 0;
4642bfe3f2eSlogwang 
4652bfe3f2eSlogwang 	while  (param[b] != '(' &&
4662bfe3f2eSlogwang 		param[b] != '\0')
4672bfe3f2eSlogwang 		b++;
4682bfe3f2eSlogwang 	if (strncmp(param, "dev", b) != 0 &&
469d30ea906Sjfb8856606 	    strncmp(param, "exec", b) != 0 &&
470d30ea906Sjfb8856606 	    strncmp(param, "fd(", b) != 0) {
4712bfe3f2eSlogwang 		ERROR("Unrecognized device type: %.*s", (int)b, param);
4722bfe3f2eSlogwang 		return -EINVAL;
4732bfe3f2eSlogwang 	}
4742bfe3f2eSlogwang 	PRIV(dev)->subs_tail += 1;
4752bfe3f2eSlogwang 	return 0;
4762bfe3f2eSlogwang }
4772bfe3f2eSlogwang 
4782bfe3f2eSlogwang int
failsafe_args_count_subdevice(struct rte_eth_dev * dev,const char * params)4792bfe3f2eSlogwang failsafe_args_count_subdevice(struct rte_eth_dev *dev,
4802bfe3f2eSlogwang 			const char *params)
4812bfe3f2eSlogwang {
4822bfe3f2eSlogwang 	return fs_parse_sub_devices(fs_count_device,
4832bfe3f2eSlogwang 				    dev, params);
4842bfe3f2eSlogwang }
4852bfe3f2eSlogwang 
4862bfe3f2eSlogwang static int
fs_parse_sub_device(struct sub_device * sdev)4872bfe3f2eSlogwang fs_parse_sub_device(struct sub_device *sdev)
4882bfe3f2eSlogwang {
4892bfe3f2eSlogwang 	struct rte_devargs *da;
4902bfe3f2eSlogwang 	char devstr[DEVARGS_MAXLEN] = "";
4912bfe3f2eSlogwang 
4922bfe3f2eSlogwang 	da = &sdev->devargs;
4932bfe3f2eSlogwang 	snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
4942bfe3f2eSlogwang 	return fs_parse_device(sdev, devstr);
4952bfe3f2eSlogwang }
4962bfe3f2eSlogwang 
4972bfe3f2eSlogwang int
failsafe_args_parse_subs(struct rte_eth_dev * dev)4982bfe3f2eSlogwang failsafe_args_parse_subs(struct rte_eth_dev *dev)
4992bfe3f2eSlogwang {
5002bfe3f2eSlogwang 	struct sub_device *sdev;
5012bfe3f2eSlogwang 	uint8_t i;
5022bfe3f2eSlogwang 	int ret = 0;
5032bfe3f2eSlogwang 
5042bfe3f2eSlogwang 	FOREACH_SUBDEV(sdev, i, dev) {
5052bfe3f2eSlogwang 		if (sdev->state >= DEV_PARSED)
5062bfe3f2eSlogwang 			continue;
5072bfe3f2eSlogwang 		if (sdev->cmdline)
5082bfe3f2eSlogwang 			ret = fs_execute_cmd(sdev, sdev->cmdline);
509d30ea906Sjfb8856606 		else if (sdev->fd_str)
510d30ea906Sjfb8856606 			ret = fs_read_fd(sdev, sdev->fd_str);
5112bfe3f2eSlogwang 		else
5122bfe3f2eSlogwang 			ret = fs_parse_sub_device(sdev);
5132bfe3f2eSlogwang 		if (ret == 0)
5142bfe3f2eSlogwang 			sdev->state = DEV_PARSED;
5152bfe3f2eSlogwang 	}
5162bfe3f2eSlogwang 	return 0;
5172bfe3f2eSlogwang }
518