xref: /dpdk/drivers/net/failsafe/failsafe_args.c (revision f665790a5dbad7b645ff46f31d65e977324e7bfc)
1009c327cSOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
2a46f8d58SGaetan Rivet  * Copyright 2017 6WIND S.A.
35feecc57SShahaf Shuler  * Copyright 2017 Mellanox Technologies, Ltd
4a46f8d58SGaetan Rivet  */
5a46f8d58SGaetan Rivet 
6d1b961dbSMatan Azrad #include <fcntl.h>
7d1b961dbSMatan Azrad #include <stdio.h>
8d1b961dbSMatan Azrad #include <stdlib.h>
9a46f8d58SGaetan Rivet #include <string.h>
10d1b961dbSMatan Azrad #include <unistd.h>
11ebea83f8SGaetan Rivet #include <errno.h>
12a46f8d58SGaetan Rivet 
13a0194d82SGaetan Rivet #include <rte_debug.h>
14a46f8d58SGaetan Rivet #include <rte_devargs.h>
15a46f8d58SGaetan Rivet #include <rte_malloc.h>
16a46f8d58SGaetan Rivet #include <rte_kvargs.h>
17c022cb40SBruce Richardson #include <rte_string_fns.h>
18a46f8d58SGaetan Rivet 
19a46f8d58SGaetan Rivet #include "failsafe_private.h"
20a46f8d58SGaetan Rivet 
21a46f8d58SGaetan Rivet /* Callback used when a new device is found in devargs */
22a46f8d58SGaetan Rivet typedef int (parse_cb)(struct rte_eth_dev *dev, const char *params,
23a46f8d58SGaetan Rivet 		uint8_t head);
24a46f8d58SGaetan Rivet 
25520dd992SFerruh Yigit uint64_t failsafe_hotplug_poll = FAILSAFE_HOTPLUG_DEFAULT_TIMEOUT_MS;
26520dd992SFerruh Yigit int failsafe_mac_from_arg;
27a46f8d58SGaetan Rivet 
28b74fd6b8SFerruh Yigit static const char * const pmd_failsafe_init_parameters[] = {
29ebea83f8SGaetan Rivet 	PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
30a46f8d58SGaetan Rivet 	PMD_FAILSAFE_MAC_KVARG,
31a46f8d58SGaetan Rivet 	NULL,
32a46f8d58SGaetan Rivet };
33a46f8d58SGaetan Rivet 
34a46f8d58SGaetan Rivet /*
35a46f8d58SGaetan Rivet  * input: text.
36a46f8d58SGaetan Rivet  * output: 0: if text[0] != '(',
37a46f8d58SGaetan Rivet  *         0: if there are no corresponding ')'
38a46f8d58SGaetan Rivet  *         n: distance to corresponding ')' otherwise
39a46f8d58SGaetan Rivet  */
40a46f8d58SGaetan Rivet static size_t
41a46f8d58SGaetan Rivet closing_paren(const char *text)
42a46f8d58SGaetan Rivet {
43a46f8d58SGaetan Rivet 	int nb_open = 0;
44a46f8d58SGaetan Rivet 	size_t i = 0;
45a46f8d58SGaetan Rivet 
46a46f8d58SGaetan Rivet 	while (text[i] != '\0') {
47a46f8d58SGaetan Rivet 		if (text[i] == '(')
48a46f8d58SGaetan Rivet 			nb_open++;
49a46f8d58SGaetan Rivet 		if (text[i] == ')')
50a46f8d58SGaetan Rivet 			nb_open--;
51a46f8d58SGaetan Rivet 		if (nb_open == 0)
52a46f8d58SGaetan Rivet 			return i;
53a46f8d58SGaetan Rivet 		i++;
54a46f8d58SGaetan Rivet 	}
55a46f8d58SGaetan Rivet 	return 0;
56a46f8d58SGaetan Rivet }
57a46f8d58SGaetan Rivet 
58a46f8d58SGaetan Rivet static int
59a46f8d58SGaetan Rivet fs_parse_device(struct sub_device *sdev, char *args)
60a46f8d58SGaetan Rivet {
61a46f8d58SGaetan Rivet 	struct rte_devargs *d;
62a46f8d58SGaetan Rivet 	int ret;
63a46f8d58SGaetan Rivet 
64a46f8d58SGaetan Rivet 	d = &sdev->devargs;
65a46f8d58SGaetan Rivet 	DEBUG("%s", args);
66a23bc2c4SGaetan Rivet 	ret = rte_devargs_parse(d, args);
67a46f8d58SGaetan Rivet 	if (ret) {
68a46f8d58SGaetan Rivet 		DEBUG("devargs parsing failed with code %d", ret);
69a46f8d58SGaetan Rivet 		return ret;
70a46f8d58SGaetan Rivet 	}
71a46f8d58SGaetan Rivet 	sdev->bus = d->bus;
72a46f8d58SGaetan Rivet 	sdev->state = DEV_PARSED;
73a46f8d58SGaetan Rivet 	return 0;
74a46f8d58SGaetan Rivet }
75a46f8d58SGaetan Rivet 
76a0194d82SGaetan Rivet static void
77a0194d82SGaetan Rivet fs_sanitize_cmdline(char *args)
78a0194d82SGaetan Rivet {
7979da7b91SGaetan Rivet 	char *nl;
80a0194d82SGaetan Rivet 
8179da7b91SGaetan Rivet 	nl = strrchr(args, '\n');
8279da7b91SGaetan Rivet 	if (nl)
8379da7b91SGaetan Rivet 		nl[0] = '\0';
84a0194d82SGaetan Rivet }
85a0194d82SGaetan Rivet 
86a0194d82SGaetan Rivet static int
87a0194d82SGaetan Rivet fs_execute_cmd(struct sub_device *sdev, char *cmdline)
88a0194d82SGaetan Rivet {
89a0194d82SGaetan Rivet 	FILE *fp;
90a0194d82SGaetan Rivet 	/* store possible newline as well */
91a0194d82SGaetan Rivet 	char output[DEVARGS_MAXLEN + 1];
92a0194d82SGaetan Rivet 	size_t len;
934853f2beSGaetan Rivet 	int ret;
94a0194d82SGaetan Rivet 
95a0194d82SGaetan Rivet 	RTE_ASSERT(cmdline != NULL || sdev->cmdline != NULL);
96a0194d82SGaetan Rivet 	if (sdev->cmdline == NULL) {
97a0194d82SGaetan Rivet 		size_t i;
98a0194d82SGaetan Rivet 
99a0194d82SGaetan Rivet 		len = strlen(cmdline) + 1;
100a0194d82SGaetan Rivet 		sdev->cmdline = calloc(1, len);
101a0194d82SGaetan Rivet 		if (sdev->cmdline == NULL) {
102a0194d82SGaetan Rivet 			ERROR("Command line allocation failed");
103a0194d82SGaetan Rivet 			return -ENOMEM;
104a0194d82SGaetan Rivet 		}
105f9acaf84SBruce Richardson 		strlcpy(sdev->cmdline, cmdline, len);
106a0194d82SGaetan Rivet 		/* Replace all commas in the command line by spaces */
107a0194d82SGaetan Rivet 		for (i = 0; i < len; i++)
108a0194d82SGaetan Rivet 			if (sdev->cmdline[i] == ',')
109a0194d82SGaetan Rivet 				sdev->cmdline[i] = ' ';
110a0194d82SGaetan Rivet 	}
111a0194d82SGaetan Rivet 	DEBUG("'%s'", sdev->cmdline);
112a0194d82SGaetan Rivet 	fp = popen(sdev->cmdline, "r");
113a0194d82SGaetan Rivet 	if (fp == NULL) {
1144853f2beSGaetan Rivet 		ret = -errno;
115a0194d82SGaetan Rivet 		ERROR("popen: %s", strerror(errno));
116a0194d82SGaetan Rivet 		return ret;
117a0194d82SGaetan Rivet 	}
118a0194d82SGaetan Rivet 	/* We only read one line */
119a0194d82SGaetan Rivet 	if (fgets(output, sizeof(output) - 1, fp) == NULL) {
120a0194d82SGaetan Rivet 		DEBUG("Could not read command output");
12135ffe420SRaslan Darawsheh 		ret = -ENODEV;
12235ffe420SRaslan Darawsheh 		goto ret_pclose;
123a0194d82SGaetan Rivet 	}
124a0194d82SGaetan Rivet 	fs_sanitize_cmdline(output);
12579da7b91SGaetan Rivet 	if (output[0] == '\0') {
12679da7b91SGaetan Rivet 		ret = -ENODEV;
12779da7b91SGaetan Rivet 		goto ret_pclose;
12879da7b91SGaetan Rivet 	}
129a0194d82SGaetan Rivet 	ret = fs_parse_device(sdev, output);
1304853f2beSGaetan Rivet 	if (ret)
131a0194d82SGaetan Rivet 		ERROR("Parsing device '%s' failed", output);
132a0194d82SGaetan Rivet ret_pclose:
1334853f2beSGaetan Rivet 	if (pclose(fp) == -1)
134a0194d82SGaetan Rivet 		ERROR("pclose: %s", strerror(errno));
135a0194d82SGaetan Rivet 	return ret;
136a0194d82SGaetan Rivet }
137a0194d82SGaetan Rivet 
138a46f8d58SGaetan Rivet static int
139d1b961dbSMatan Azrad fs_read_fd(struct sub_device *sdev, char *fd_str)
140d1b961dbSMatan Azrad {
141d1b961dbSMatan Azrad 	FILE *fp = NULL;
142d1b961dbSMatan Azrad 	int fd = -1;
143d1b961dbSMatan Azrad 	/* store possible newline as well */
144d1b961dbSMatan Azrad 	char output[DEVARGS_MAXLEN + 1];
145d1b961dbSMatan Azrad 	int err = -ENODEV;
146d1b961dbSMatan Azrad 	int oflags;
147d1b961dbSMatan Azrad 	int lcount;
148d1b961dbSMatan Azrad 
149d1b961dbSMatan Azrad 	RTE_ASSERT(fd_str != NULL || sdev->fd_str != NULL);
150d1b961dbSMatan Azrad 	if (sdev->fd_str == NULL) {
151d1b961dbSMatan Azrad 		sdev->fd_str = strdup(fd_str);
152d1b961dbSMatan Azrad 		if (sdev->fd_str == NULL) {
153d1b961dbSMatan Azrad 			ERROR("Command line allocation failed");
154d1b961dbSMatan Azrad 			return -ENOMEM;
155d1b961dbSMatan Azrad 		}
156d1b961dbSMatan Azrad 	}
157d1b961dbSMatan Azrad 	errno = 0;
158d1b961dbSMatan Azrad 	fd = strtol(fd_str, &fd_str, 0);
159d1b961dbSMatan Azrad 	if (errno || *fd_str || fd < 0) {
160d1b961dbSMatan Azrad 		ERROR("Parsing FD number failed");
161d1b961dbSMatan Azrad 		goto error;
162d1b961dbSMatan Azrad 	}
163d1b961dbSMatan Azrad 	/* Fiddle with copy of file descriptor */
164d1b961dbSMatan Azrad 	fd = dup(fd);
165d1b961dbSMatan Azrad 	if (fd == -1)
166d1b961dbSMatan Azrad 		goto error;
167d1b961dbSMatan Azrad 	oflags = fcntl(fd, F_GETFL);
168d1b961dbSMatan Azrad 	if (oflags == -1)
169d1b961dbSMatan Azrad 		goto error;
170d1b961dbSMatan Azrad 	if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1)
171d1b961dbSMatan Azrad 		goto error;
172d1b961dbSMatan Azrad 	fp = fdopen(fd, "r");
173d1b961dbSMatan Azrad 	if (fp == NULL)
174d1b961dbSMatan Azrad 		goto error;
175d1b961dbSMatan Azrad 	fd = -1;
176d1b961dbSMatan Azrad 	/* Only take the last line into account */
177d1b961dbSMatan Azrad 	lcount = 0;
178d1b961dbSMatan Azrad 	while (fgets(output, sizeof(output), fp))
179d1b961dbSMatan Azrad 		++lcount;
180d1b961dbSMatan Azrad 	if (lcount == 0)
181d1b961dbSMatan Azrad 		goto error;
182d1b961dbSMatan Azrad 	else if (ferror(fp) && errno != EAGAIN)
183d1b961dbSMatan Azrad 		goto error;
184d1b961dbSMatan Azrad 	/* Line must end with a newline character */
185d1b961dbSMatan Azrad 	fs_sanitize_cmdline(output);
186d1b961dbSMatan Azrad 	if (output[0] == '\0')
187d1b961dbSMatan Azrad 		goto error;
188d1b961dbSMatan Azrad 	err = fs_parse_device(sdev, output);
189d1b961dbSMatan Azrad 	if (err)
190d1b961dbSMatan Azrad 		ERROR("Parsing device '%s' failed", output);
191d1b961dbSMatan Azrad error:
192d1b961dbSMatan Azrad 	if (fp)
193d1b961dbSMatan Azrad 		fclose(fp);
194d1b961dbSMatan Azrad 	if (fd != -1)
195d1b961dbSMatan Azrad 		close(fd);
196d1b961dbSMatan Azrad 	return err;
197d1b961dbSMatan Azrad }
198d1b961dbSMatan Azrad 
199d1b961dbSMatan Azrad static int
200a46f8d58SGaetan Rivet fs_parse_device_param(struct rte_eth_dev *dev, const char *param,
201a46f8d58SGaetan Rivet 		uint8_t head)
202a46f8d58SGaetan Rivet {
203a46f8d58SGaetan Rivet 	struct fs_priv *priv;
204a46f8d58SGaetan Rivet 	struct sub_device *sdev;
205a46f8d58SGaetan Rivet 	char *args = NULL;
206a46f8d58SGaetan Rivet 	size_t a, b;
207a46f8d58SGaetan Rivet 	int ret;
208a46f8d58SGaetan Rivet 
209a46f8d58SGaetan Rivet 	priv = PRIV(dev);
210a46f8d58SGaetan Rivet 	a = 0;
211a46f8d58SGaetan Rivet 	b = 0;
212a46f8d58SGaetan Rivet 	ret = 0;
213a46f8d58SGaetan Rivet 	while  (param[b] != '(' &&
214a46f8d58SGaetan Rivet 		param[b] != '\0')
215a46f8d58SGaetan Rivet 		b++;
216a46f8d58SGaetan Rivet 	a = b;
217a46f8d58SGaetan Rivet 	b += closing_paren(&param[b]);
218a46f8d58SGaetan Rivet 	if (a == b) {
219a46f8d58SGaetan Rivet 		ERROR("Dangling parenthesis");
220a46f8d58SGaetan Rivet 		return -EINVAL;
221a46f8d58SGaetan Rivet 	}
222a46f8d58SGaetan Rivet 	a += 1;
223a46f8d58SGaetan Rivet 	args = strndup(&param[a], b - a);
224a46f8d58SGaetan Rivet 	if (args == NULL) {
225a46f8d58SGaetan Rivet 		ERROR("Not enough memory for parameter parsing");
226a46f8d58SGaetan Rivet 		return -ENOMEM;
227a46f8d58SGaetan Rivet 	}
228a46f8d58SGaetan Rivet 	sdev = &priv->subs[head];
229a46f8d58SGaetan Rivet 	if (strncmp(param, "dev", 3) == 0) {
230a46f8d58SGaetan Rivet 		ret = fs_parse_device(sdev, args);
231a46f8d58SGaetan Rivet 		if (ret)
232a46f8d58SGaetan Rivet 			goto free_args;
233a0194d82SGaetan Rivet 	} else if (strncmp(param, "exec", 4) == 0) {
234a0194d82SGaetan Rivet 		ret = fs_execute_cmd(sdev, args);
235a0194d82SGaetan Rivet 		if (ret == -ENODEV) {
236a0194d82SGaetan Rivet 			DEBUG("Reading device info from command line failed");
237a0194d82SGaetan Rivet 			ret = 0;
238a0194d82SGaetan Rivet 		}
239a0194d82SGaetan Rivet 		if (ret)
240a0194d82SGaetan Rivet 			goto free_args;
241d1b961dbSMatan Azrad 	} else if (strncmp(param, "fd(", 3) == 0) {
242d1b961dbSMatan Azrad 		ret = fs_read_fd(sdev, args);
243d1b961dbSMatan Azrad 		if (ret == -ENODEV) {
244d1b961dbSMatan Azrad 			DEBUG("Reading device info from FD failed");
245d1b961dbSMatan Azrad 			ret = 0;
246d1b961dbSMatan Azrad 		}
247d1b961dbSMatan Azrad 		if (ret)
248d1b961dbSMatan Azrad 			goto free_args;
249a46f8d58SGaetan Rivet 	} else {
250a46f8d58SGaetan Rivet 		ERROR("Unrecognized device type: %.*s", (int)b, param);
2512ddf2d7aSChengwen Feng 		ret = -EINVAL;
252a46f8d58SGaetan Rivet 	}
253a46f8d58SGaetan Rivet free_args:
254a46f8d58SGaetan Rivet 	free(args);
255a46f8d58SGaetan Rivet 	return ret;
256a46f8d58SGaetan Rivet }
257a46f8d58SGaetan Rivet 
258a46f8d58SGaetan Rivet static int
259a46f8d58SGaetan Rivet fs_parse_sub_devices(parse_cb *cb,
260a46f8d58SGaetan Rivet 		struct rte_eth_dev *dev, const char *params)
261a46f8d58SGaetan Rivet {
262a46f8d58SGaetan Rivet 	size_t a, b;
263a46f8d58SGaetan Rivet 	uint8_t head;
264a46f8d58SGaetan Rivet 	int ret;
265a46f8d58SGaetan Rivet 
266a46f8d58SGaetan Rivet 	a = 0;
267a46f8d58SGaetan Rivet 	head = 0;
268a46f8d58SGaetan Rivet 	ret = 0;
269a46f8d58SGaetan Rivet 	while (params[a] != '\0') {
270a46f8d58SGaetan Rivet 		b = a;
271a46f8d58SGaetan Rivet 		while (params[b] != '(' &&
272a46f8d58SGaetan Rivet 		       params[b] != ',' &&
273a46f8d58SGaetan Rivet 		       params[b] != '\0')
274a46f8d58SGaetan Rivet 			b++;
275a46f8d58SGaetan Rivet 		if (b == a) {
276a46f8d58SGaetan Rivet 			ERROR("Invalid parameter");
277a46f8d58SGaetan Rivet 			return -EINVAL;
278a46f8d58SGaetan Rivet 		}
279a46f8d58SGaetan Rivet 		if (params[b] == ',') {
280a46f8d58SGaetan Rivet 			a = b + 1;
281a46f8d58SGaetan Rivet 			continue;
282a46f8d58SGaetan Rivet 		}
283a46f8d58SGaetan Rivet 		if (params[b] == '(') {
284a46f8d58SGaetan Rivet 			size_t start = b;
285a46f8d58SGaetan Rivet 
286a46f8d58SGaetan Rivet 			b += closing_paren(&params[b]);
287a46f8d58SGaetan Rivet 			if (b == start) {
288a46f8d58SGaetan Rivet 				ERROR("Dangling parenthesis");
289a46f8d58SGaetan Rivet 				return -EINVAL;
290a46f8d58SGaetan Rivet 			}
291a46f8d58SGaetan Rivet 			ret = (*cb)(dev, &params[a], head);
292a46f8d58SGaetan Rivet 			if (ret)
293a46f8d58SGaetan Rivet 				return ret;
294a46f8d58SGaetan Rivet 			head += 1;
295a46f8d58SGaetan Rivet 			b += 1;
296a46f8d58SGaetan Rivet 			if (params[b] == '\0')
297a46f8d58SGaetan Rivet 				return 0;
298a46f8d58SGaetan Rivet 		}
299a46f8d58SGaetan Rivet 		a = b + 1;
300a46f8d58SGaetan Rivet 	}
301a46f8d58SGaetan Rivet 	return 0;
302a46f8d58SGaetan Rivet }
303a46f8d58SGaetan Rivet 
304a46f8d58SGaetan Rivet static int
305a46f8d58SGaetan Rivet fs_remove_sub_devices_definition(char params[DEVARGS_MAXLEN])
306a46f8d58SGaetan Rivet {
307a46f8d58SGaetan Rivet 	char buffer[DEVARGS_MAXLEN] = {0};
308a46f8d58SGaetan Rivet 	size_t a, b;
309a46f8d58SGaetan Rivet 	int i;
310a46f8d58SGaetan Rivet 
311a46f8d58SGaetan Rivet 	a = 0;
312a46f8d58SGaetan Rivet 	i = 0;
313a46f8d58SGaetan Rivet 	while (params[a] != '\0') {
314a46f8d58SGaetan Rivet 		b = a;
315a46f8d58SGaetan Rivet 		while (params[b] != '(' &&
316a46f8d58SGaetan Rivet 		       params[b] != ',' &&
317a46f8d58SGaetan Rivet 		       params[b] != '\0')
318a46f8d58SGaetan Rivet 			b++;
319a46f8d58SGaetan Rivet 		if (b == a) {
320a46f8d58SGaetan Rivet 			ERROR("Invalid parameter");
321a46f8d58SGaetan Rivet 			return -EINVAL;
322a46f8d58SGaetan Rivet 		}
323852be652SMatan Azrad 		if (params[b] == ',' || params[b] == '\0') {
324852be652SMatan Azrad 			size_t len = b - a;
325852be652SMatan Azrad 
326852be652SMatan Azrad 			if (i > 0)
327852be652SMatan Azrad 				len += 1;
328852be652SMatan Azrad 			snprintf(&buffer[i], len + 1, "%s%s",
329852be652SMatan Azrad 					i ? "," : "", &params[a]);
330852be652SMatan Azrad 			i += len;
331852be652SMatan Azrad 		} else if (params[b] == '(') {
332a46f8d58SGaetan Rivet 			size_t start = b;
333852be652SMatan Azrad 
334a46f8d58SGaetan Rivet 			b += closing_paren(&params[b]);
335a46f8d58SGaetan Rivet 			if (b == start)
336a46f8d58SGaetan Rivet 				return -EINVAL;
337a46f8d58SGaetan Rivet 			b += 1;
338a46f8d58SGaetan Rivet 			if (params[b] == '\0')
339a46f8d58SGaetan Rivet 				goto out;
340a46f8d58SGaetan Rivet 		}
341a46f8d58SGaetan Rivet 		a = b + 1;
342a46f8d58SGaetan Rivet 	}
343a46f8d58SGaetan Rivet out:
344c022cb40SBruce Richardson 	strlcpy(params, buffer, DEVARGS_MAXLEN);
345a46f8d58SGaetan Rivet 	return 0;
346a46f8d58SGaetan Rivet }
347a46f8d58SGaetan Rivet 
348a46f8d58SGaetan Rivet static int
349ebea83f8SGaetan Rivet fs_get_u64_arg(const char *key __rte_unused,
350ebea83f8SGaetan Rivet 		const char *value, void *out)
351ebea83f8SGaetan Rivet {
352ebea83f8SGaetan Rivet 	uint64_t *u64 = out;
353ebea83f8SGaetan Rivet 	char *endptr = NULL;
354ebea83f8SGaetan Rivet 
355ebea83f8SGaetan Rivet 	if ((value == NULL) || (out == NULL))
356ebea83f8SGaetan Rivet 		return -EINVAL;
357ebea83f8SGaetan Rivet 	errno = 0;
358ebea83f8SGaetan Rivet 	*u64 = strtoull(value, &endptr, 0);
359ebea83f8SGaetan Rivet 	if (errno != 0)
360ebea83f8SGaetan Rivet 		return -errno;
361ebea83f8SGaetan Rivet 	if (endptr == value)
362ebea83f8SGaetan Rivet 		return -1;
363ebea83f8SGaetan Rivet 	return 0;
364ebea83f8SGaetan Rivet }
365ebea83f8SGaetan Rivet 
366ebea83f8SGaetan Rivet static int
367a46f8d58SGaetan Rivet fs_get_mac_addr_arg(const char *key __rte_unused,
368a46f8d58SGaetan Rivet 		const char *value, void *out)
369a46f8d58SGaetan Rivet {
3706d13ea8eSOlivier Matz 	struct rte_ether_addr *ea = out;
371a46f8d58SGaetan Rivet 
372a46f8d58SGaetan Rivet 	if ((value == NULL) || (out == NULL))
373a46f8d58SGaetan Rivet 		return -EINVAL;
3741cf34a4eSStephen Hemminger 
3751cf34a4eSStephen Hemminger 	return rte_ether_unformat_addr(value, ea);
376a46f8d58SGaetan Rivet }
377a46f8d58SGaetan Rivet 
378a46f8d58SGaetan Rivet int
379a46f8d58SGaetan Rivet failsafe_args_parse(struct rte_eth_dev *dev, const char *params)
380a46f8d58SGaetan Rivet {
381a46f8d58SGaetan Rivet 	struct fs_priv *priv;
382a46f8d58SGaetan Rivet 	char mut_params[DEVARGS_MAXLEN] = "";
383a46f8d58SGaetan Rivet 	struct rte_kvargs *kvlist = NULL;
384a46f8d58SGaetan Rivet 	unsigned int arg_count;
385a46f8d58SGaetan Rivet 	size_t n;
386a46f8d58SGaetan Rivet 	int ret;
387a46f8d58SGaetan Rivet 
388a46f8d58SGaetan Rivet 	priv = PRIV(dev);
389a46f8d58SGaetan Rivet 	ret = 0;
390a46f8d58SGaetan Rivet 	priv->subs_tx = FAILSAFE_MAX_ETHPORTS;
391a46f8d58SGaetan Rivet 	/* default parameters */
392c022cb40SBruce Richardson 	n = strlcpy(mut_params, params, sizeof(mut_params));
393a46f8d58SGaetan Rivet 	if (n >= sizeof(mut_params)) {
394a46f8d58SGaetan Rivet 		ERROR("Parameter string too long (>=%zu)",
395a46f8d58SGaetan Rivet 				sizeof(mut_params));
396a46f8d58SGaetan Rivet 		return -ENOMEM;
397a46f8d58SGaetan Rivet 	}
398a46f8d58SGaetan Rivet 	ret = fs_parse_sub_devices(fs_parse_device_param,
399a46f8d58SGaetan Rivet 				   dev, params);
400a46f8d58SGaetan Rivet 	if (ret < 0)
401a46f8d58SGaetan Rivet 		return ret;
402a46f8d58SGaetan Rivet 	ret = fs_remove_sub_devices_definition(mut_params);
403a46f8d58SGaetan Rivet 	if (ret < 0)
404a46f8d58SGaetan Rivet 		return ret;
405a46f8d58SGaetan Rivet 	if (strnlen(mut_params, sizeof(mut_params)) > 0) {
406a46f8d58SGaetan Rivet 		kvlist = rte_kvargs_parse(mut_params,
407a46f8d58SGaetan Rivet 				pmd_failsafe_init_parameters);
408a46f8d58SGaetan Rivet 		if (kvlist == NULL) {
409*f665790aSDavid Marchand 			ERROR("Error parsing parameters, usage:"
410a46f8d58SGaetan Rivet 				PMD_FAILSAFE_PARAM_STRING);
411a46f8d58SGaetan Rivet 			return -1;
412a46f8d58SGaetan Rivet 		}
413ebea83f8SGaetan Rivet 		/* PLUG_IN event poll timer */
414ebea83f8SGaetan Rivet 		arg_count = rte_kvargs_count(kvlist,
415ebea83f8SGaetan Rivet 				PMD_FAILSAFE_HOTPLUG_POLL_KVARG);
416ebea83f8SGaetan Rivet 		if (arg_count == 1) {
417ebea83f8SGaetan Rivet 			ret = rte_kvargs_process(kvlist,
418ebea83f8SGaetan Rivet 					PMD_FAILSAFE_HOTPLUG_POLL_KVARG,
419520dd992SFerruh Yigit 					&fs_get_u64_arg, &failsafe_hotplug_poll);
420ebea83f8SGaetan Rivet 			if (ret < 0)
421ebea83f8SGaetan Rivet 				goto free_kvlist;
422ebea83f8SGaetan Rivet 		}
423a46f8d58SGaetan Rivet 		/* MAC addr */
424a46f8d58SGaetan Rivet 		arg_count = rte_kvargs_count(kvlist,
425a46f8d58SGaetan Rivet 				PMD_FAILSAFE_MAC_KVARG);
426a46f8d58SGaetan Rivet 		if (arg_count > 0) {
427a46f8d58SGaetan Rivet 			ret = rte_kvargs_process(kvlist,
428a46f8d58SGaetan Rivet 					PMD_FAILSAFE_MAC_KVARG,
429a46f8d58SGaetan Rivet 					&fs_get_mac_addr_arg,
430a46f8d58SGaetan Rivet 					&dev->data->mac_addrs[0]);
431a46f8d58SGaetan Rivet 			if (ret < 0)
432a46f8d58SGaetan Rivet 				goto free_kvlist;
433852be652SMatan Azrad 
434520dd992SFerruh Yigit 			failsafe_mac_from_arg = 1;
435a46f8d58SGaetan Rivet 		}
436a46f8d58SGaetan Rivet 	}
437ebea83f8SGaetan Rivet 	PRIV(dev)->state = DEV_PARSED;
438a46f8d58SGaetan Rivet free_kvlist:
439a46f8d58SGaetan Rivet 	rte_kvargs_free(kvlist);
440a46f8d58SGaetan Rivet 	return ret;
441a46f8d58SGaetan Rivet }
442a46f8d58SGaetan Rivet 
443a46f8d58SGaetan Rivet void
444a46f8d58SGaetan Rivet failsafe_args_free(struct rte_eth_dev *dev)
445a46f8d58SGaetan Rivet {
446a46f8d58SGaetan Rivet 	struct sub_device *sdev;
447a46f8d58SGaetan Rivet 	uint8_t i;
448a46f8d58SGaetan Rivet 
449a46f8d58SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
4509720e325SAdrien Mazarguil 		free(sdev->cmdline);
451a0194d82SGaetan Rivet 		sdev->cmdline = NULL;
452d1b961dbSMatan Azrad 		free(sdev->fd_str);
453d1b961dbSMatan Azrad 		sdev->fd_str = NULL;
45464051bb1SXueming Li 		rte_devargs_reset(&sdev->devargs);
455a46f8d58SGaetan Rivet 	}
456a46f8d58SGaetan Rivet }
457a46f8d58SGaetan Rivet 
458a46f8d58SGaetan Rivet static int
459a46f8d58SGaetan Rivet fs_count_device(struct rte_eth_dev *dev, const char *param,
460a46f8d58SGaetan Rivet 		uint8_t head __rte_unused)
461a46f8d58SGaetan Rivet {
462a46f8d58SGaetan Rivet 	size_t b = 0;
463a46f8d58SGaetan Rivet 
464a46f8d58SGaetan Rivet 	while  (param[b] != '(' &&
465a46f8d58SGaetan Rivet 		param[b] != '\0')
466a46f8d58SGaetan Rivet 		b++;
467a0194d82SGaetan Rivet 	if (strncmp(param, "dev", b) != 0 &&
468d1b961dbSMatan Azrad 	    strncmp(param, "exec", b) != 0 &&
469d1b961dbSMatan Azrad 	    strncmp(param, "fd(", b) != 0) {
470a46f8d58SGaetan Rivet 		ERROR("Unrecognized device type: %.*s", (int)b, param);
471a46f8d58SGaetan Rivet 		return -EINVAL;
472a46f8d58SGaetan Rivet 	}
473a46f8d58SGaetan Rivet 	PRIV(dev)->subs_tail += 1;
474a46f8d58SGaetan Rivet 	return 0;
475a46f8d58SGaetan Rivet }
476a46f8d58SGaetan Rivet 
477a46f8d58SGaetan Rivet int
478a46f8d58SGaetan Rivet failsafe_args_count_subdevice(struct rte_eth_dev *dev,
479a46f8d58SGaetan Rivet 			const char *params)
480a46f8d58SGaetan Rivet {
481a46f8d58SGaetan Rivet 	return fs_parse_sub_devices(fs_count_device,
482a46f8d58SGaetan Rivet 				    dev, params);
483a46f8d58SGaetan Rivet }
484a0194d82SGaetan Rivet 
485598fb8aeSGaetan Rivet static int
486598fb8aeSGaetan Rivet fs_parse_sub_device(struct sub_device *sdev)
487598fb8aeSGaetan Rivet {
488598fb8aeSGaetan Rivet 	struct rte_devargs *da;
489598fb8aeSGaetan Rivet 	char devstr[DEVARGS_MAXLEN] = "";
490598fb8aeSGaetan Rivet 
491598fb8aeSGaetan Rivet 	da = &sdev->devargs;
492598fb8aeSGaetan Rivet 	snprintf(devstr, sizeof(devstr), "%s,%s", da->name, da->args);
493598fb8aeSGaetan Rivet 	return fs_parse_device(sdev, devstr);
494598fb8aeSGaetan Rivet }
495598fb8aeSGaetan Rivet 
496a0194d82SGaetan Rivet int
497a0194d82SGaetan Rivet failsafe_args_parse_subs(struct rte_eth_dev *dev)
498a0194d82SGaetan Rivet {
499a0194d82SGaetan Rivet 	struct sub_device *sdev;
500a0194d82SGaetan Rivet 	uint8_t i;
501a0194d82SGaetan Rivet 	int ret = 0;
502a0194d82SGaetan Rivet 
503a0194d82SGaetan Rivet 	FOREACH_SUBDEV(sdev, i, dev) {
504a0194d82SGaetan Rivet 		if (sdev->state >= DEV_PARSED)
505a0194d82SGaetan Rivet 			continue;
506a0194d82SGaetan Rivet 		if (sdev->cmdline)
507a0194d82SGaetan Rivet 			ret = fs_execute_cmd(sdev, sdev->cmdline);
508d1b961dbSMatan Azrad 		else if (sdev->fd_str)
509d1b961dbSMatan Azrad 			ret = fs_read_fd(sdev, sdev->fd_str);
510598fb8aeSGaetan Rivet 		else
511598fb8aeSGaetan Rivet 			ret = fs_parse_sub_device(sdev);
512a0194d82SGaetan Rivet 		if (ret == 0)
513a0194d82SGaetan Rivet 			sdev->state = DEV_PARSED;
514a0194d82SGaetan Rivet 	}
515a0194d82SGaetan Rivet 	return 0;
516a0194d82SGaetan Rivet }
517