xref: /dpdk/lib/eal/common/eal_common_devargs.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2014 6WIND S.A.
3  */
4 
5 /* This file manages the list of devices and their arguments, as given
6  * by the user at startup
7  */
8 
9 #include <stdio.h>
10 #include <string.h>
11 #include <stdarg.h>
12 
13 #include <rte_bus.h>
14 #include <rte_class.h>
15 #include <rte_compat.h>
16 #include <rte_dev.h>
17 #include <rte_devargs.h>
18 #include <rte_errno.h>
19 #include <rte_kvargs.h>
20 #include <rte_log.h>
21 #include <rte_tailq.h>
22 #include <rte_string_fns.h>
23 #include "eal_private.h"
24 
25 /** user device double-linked queue type definition */
26 TAILQ_HEAD(rte_devargs_list, rte_devargs);
27 
28 /** Global list of user devices */
29 static struct rte_devargs_list devargs_list =
30 	TAILQ_HEAD_INITIALIZER(devargs_list);
31 
32 /* Resolve devargs name from bus arguments. */
33 static int
34 devargs_bus_parse_default(struct rte_devargs *devargs,
35 			  struct rte_kvargs *bus_args)
36 {
37 	const char *name;
38 
39 	/* Parse devargs name from bus key-value list. */
40 	name = rte_kvargs_get(bus_args, "name");
41 	if (name == NULL) {
42 		RTE_LOG(DEBUG, EAL, "devargs name not found: %s\n",
43 			devargs->data);
44 		return 0;
45 	}
46 	if (rte_strscpy(devargs->name, name, sizeof(devargs->name)) < 0) {
47 		RTE_LOG(ERR, EAL, "devargs name too long: %s\n",
48 			devargs->data);
49 		return -E2BIG;
50 	}
51 	return 0;
52 }
53 
54 int
55 rte_devargs_layers_parse(struct rte_devargs *devargs,
56 			 const char *devstr)
57 {
58 	struct {
59 		const char *key;
60 		const char *str;
61 		struct rte_kvargs *kvlist;
62 	} layers[] = {
63 		{ RTE_DEVARGS_KEY_BUS "=",    NULL, NULL, },
64 		{ RTE_DEVARGS_KEY_CLASS "=",  NULL, NULL, },
65 		{ RTE_DEVARGS_KEY_DRIVER "=", NULL, NULL, },
66 	};
67 	struct rte_kvargs_pair *kv = NULL;
68 	struct rte_kvargs *bus_kvlist = NULL;
69 	char *s;
70 	size_t nblayer = 0;
71 	size_t i;
72 	int ret = 0;
73 	bool allocated_data = false;
74 
75 	/* If the devargs points the devstr
76 	 * as source data, then it should not allocate
77 	 * anything and keep referring only to it.
78 	 */
79 	if (devargs->data != devstr) {
80 		devargs->data = strdup(devstr);
81 		if (devargs->data == NULL) {
82 			RTE_LOG(ERR, EAL, "OOM\n");
83 			ret = -ENOMEM;
84 			goto get_out;
85 		}
86 		allocated_data = true;
87 	}
88 	s = devargs->data;
89 
90 	while (s != NULL) {
91 		if (nblayer > RTE_DIM(layers)) {
92 			ret = -E2BIG;
93 			goto get_out;
94 		}
95 		layers[nblayer].str = s;
96 
97 		/* Locate next layer starts with valid layer key. */
98 		while (s != NULL) {
99 			s = strchr(s, '/');
100 			if (s == NULL)
101 				break;
102 			for (i = 0; i < RTE_DIM(layers); i++) {
103 				if (strncmp(s + 1, layers[i].key,
104 					    strlen(layers[i].key)) == 0) {
105 					*s = '\0';
106 					break;
107 				}
108 			}
109 			s++;
110 			if (i < RTE_DIM(layers))
111 				break;
112 		}
113 
114 		layers[nblayer].kvlist = rte_kvargs_parse
115 				(layers[nblayer].str, NULL);
116 		if (layers[nblayer].kvlist == NULL) {
117 			ret = -EINVAL;
118 			goto get_out;
119 		}
120 
121 		nblayer++;
122 	}
123 
124 	/* Parse each sub-list. */
125 	for (i = 0; i < RTE_DIM(layers); i++) {
126 		if (layers[i].kvlist == NULL)
127 			continue;
128 		kv = &layers[i].kvlist->pairs[0];
129 		if (kv->key == NULL)
130 			continue;
131 		if (strcmp(kv->key, RTE_DEVARGS_KEY_BUS) == 0) {
132 			bus_kvlist = layers[i].kvlist;
133 			devargs->bus_str = layers[i].str;
134 			devargs->bus = rte_bus_find_by_name(kv->value);
135 			if (devargs->bus == NULL) {
136 				RTE_LOG(ERR, EAL, "Could not find bus \"%s\"\n",
137 					kv->value);
138 				ret = -EFAULT;
139 				goto get_out;
140 			}
141 		} else if (strcmp(kv->key, RTE_DEVARGS_KEY_CLASS) == 0) {
142 			devargs->cls_str = layers[i].str;
143 			devargs->cls = rte_class_find_by_name(kv->value);
144 			if (devargs->cls == NULL) {
145 				RTE_LOG(ERR, EAL, "Could not find class \"%s\"\n",
146 					kv->value);
147 				ret = -EFAULT;
148 				goto get_out;
149 			}
150 		} else if (strcmp(kv->key, RTE_DEVARGS_KEY_DRIVER) == 0) {
151 			devargs->drv_str = layers[i].str;
152 			continue;
153 		}
154 	}
155 
156 	/* Resolve devargs name. */
157 	if (devargs->bus != NULL && devargs->bus->devargs_parse != NULL)
158 		ret = devargs->bus->devargs_parse(devargs);
159 	else if (bus_kvlist != NULL)
160 		ret = devargs_bus_parse_default(devargs, bus_kvlist);
161 
162 get_out:
163 	for (i = 0; i < RTE_DIM(layers); i++) {
164 		if (layers[i].kvlist)
165 			rte_kvargs_free(layers[i].kvlist);
166 	}
167 	if (ret != 0) {
168 		if (allocated_data) {
169 			/* Free duplicated data. */
170 			free(devargs->data);
171 			devargs->data = NULL;
172 		}
173 		rte_errno = -ret;
174 	}
175 	return ret;
176 }
177 
178 static int
179 bus_name_cmp(const struct rte_bus *bus, const void *name)
180 {
181 	return strncmp(bus->name, name, strlen(bus->name));
182 }
183 
184 int
185 rte_devargs_parse(struct rte_devargs *da, const char *dev)
186 {
187 	struct rte_bus *bus = NULL;
188 	const char *devname;
189 	const size_t maxlen = sizeof(da->name);
190 	size_t i;
191 
192 	if (da == NULL)
193 		return -EINVAL;
194 
195 	/* First parse according global device syntax. */
196 	if (rte_devargs_layers_parse(da, dev) == 0) {
197 		if (da->bus != NULL || da->cls != NULL)
198 			return 0;
199 		rte_devargs_reset(da);
200 	}
201 
202 	/* Otherwise fallback to legacy syntax: */
203 
204 	/* Retrieve eventual bus info */
205 	do {
206 		devname = dev;
207 		bus = rte_bus_find(bus, bus_name_cmp, dev);
208 		if (bus == NULL)
209 			break;
210 		devname = dev + strlen(bus->name) + 1;
211 		if (rte_bus_find_by_device_name(devname) == bus)
212 			break;
213 	} while (1);
214 	/* Store device name */
215 	i = 0;
216 	while (devname[i] != '\0' && devname[i] != ',') {
217 		da->name[i] = devname[i];
218 		i++;
219 		if (i == maxlen) {
220 			RTE_LOG(WARNING, EAL, "Parsing \"%s\": device name should be shorter than %zu\n",
221 				dev, maxlen);
222 			da->name[i - 1] = '\0';
223 			return -EINVAL;
224 		}
225 	}
226 	da->name[i] = '\0';
227 	if (bus == NULL) {
228 		bus = rte_bus_find_by_device_name(da->name);
229 		if (bus == NULL) {
230 			RTE_LOG(ERR, EAL, "failed to parse device \"%s\"\n",
231 				da->name);
232 			return -EFAULT;
233 		}
234 	}
235 	da->bus = bus;
236 	/* Parse eventual device arguments */
237 	if (devname[i] == ',')
238 		da->data = strdup(&devname[i + 1]);
239 	else
240 		da->data = strdup("");
241 	if (da->data == NULL) {
242 		RTE_LOG(ERR, EAL, "not enough memory to parse arguments\n");
243 		return -ENOMEM;
244 	}
245 	da->drv_str = da->data;
246 	return 0;
247 }
248 
249 int
250 rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
251 {
252 	va_list ap;
253 	int len;
254 	char *dev;
255 	int ret;
256 
257 	if (da == NULL)
258 		return -EINVAL;
259 
260 	va_start(ap, format);
261 	len = vsnprintf(NULL, 0, format, ap);
262 	va_end(ap);
263 	if (len < 0)
264 		return -EINVAL;
265 
266 	len += 1;
267 	dev = calloc(1, (size_t)len);
268 	if (dev == NULL) {
269 		RTE_LOG(ERR, EAL, "not enough memory to parse device\n");
270 		return -ENOMEM;
271 	}
272 
273 	va_start(ap, format);
274 	vsnprintf(dev, (size_t)len, format, ap);
275 	va_end(ap);
276 
277 	ret = rte_devargs_parse(da, dev);
278 
279 	free(dev);
280 	return ret;
281 }
282 
283 void
284 rte_devargs_reset(struct rte_devargs *da)
285 {
286 	if (da == NULL)
287 		return;
288 	if (da->data)
289 		free(da->data);
290 	da->data = NULL;
291 }
292 
293 int
294 rte_devargs_insert(struct rte_devargs **da)
295 {
296 	struct rte_devargs *listed_da;
297 	void *tmp;
298 
299 	if (*da == NULL || (*da)->bus == NULL)
300 		return -1;
301 
302 	RTE_TAILQ_FOREACH_SAFE(listed_da, &devargs_list, next, tmp) {
303 		if (listed_da == *da)
304 			/* devargs already in the list */
305 			return 0;
306 		if (strcmp(listed_da->bus->name, (*da)->bus->name) == 0 &&
307 				strcmp(listed_da->name, (*da)->name) == 0) {
308 			/* device already in devargs list, must be updated */
309 			(*da)->next = listed_da->next;
310 			rte_devargs_reset(listed_da);
311 			*listed_da = **da;
312 			/* replace provided devargs with found one */
313 			free(*da);
314 			*da = listed_da;
315 			return 0;
316 		}
317 	}
318 	/* new device in the list */
319 	TAILQ_INSERT_TAIL(&devargs_list, *da, next);
320 	return 0;
321 }
322 
323 /* store in allowed list parameter for later parsing */
324 int
325 rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
326 {
327 	struct rte_devargs *devargs = NULL;
328 	struct rte_bus *bus = NULL;
329 	const char *dev = devargs_str;
330 
331 	/* use calloc instead of rte_zmalloc as it's called early at init */
332 	devargs = calloc(1, sizeof(*devargs));
333 	if (devargs == NULL)
334 		goto fail;
335 
336 	if (rte_devargs_parse(devargs, dev))
337 		goto fail;
338 	devargs->type = devtype;
339 	bus = devargs->bus;
340 	if (devargs->type == RTE_DEVTYPE_BLOCKED)
341 		devargs->policy = RTE_DEV_BLOCKED;
342 	if (bus->conf.scan_mode == RTE_BUS_SCAN_UNDEFINED) {
343 		if (devargs->policy == RTE_DEV_ALLOWED)
344 			bus->conf.scan_mode = RTE_BUS_SCAN_ALLOWLIST;
345 		else if (devargs->policy == RTE_DEV_BLOCKED)
346 			bus->conf.scan_mode = RTE_BUS_SCAN_BLOCKLIST;
347 	}
348 	TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
349 	return 0;
350 
351 fail:
352 	if (devargs) {
353 		rte_devargs_reset(devargs);
354 		free(devargs);
355 	}
356 
357 	return -1;
358 }
359 
360 int
361 rte_devargs_remove(struct rte_devargs *devargs)
362 {
363 	struct rte_devargs *d;
364 	void *tmp;
365 
366 	if (devargs == NULL || devargs->bus == NULL)
367 		return -1;
368 
369 	RTE_TAILQ_FOREACH_SAFE(d, &devargs_list, next, tmp) {
370 		if (strcmp(d->bus->name, devargs->bus->name) == 0 &&
371 		    strcmp(d->name, devargs->name) == 0) {
372 			TAILQ_REMOVE(&devargs_list, d, next);
373 			rte_devargs_reset(d);
374 			free(d);
375 			return 0;
376 		}
377 	}
378 	return 1;
379 }
380 
381 /* count the number of devices of a specified type */
382 unsigned int
383 rte_devargs_type_count(enum rte_devtype devtype)
384 {
385 	struct rte_devargs *devargs;
386 	unsigned int count = 0;
387 
388 	TAILQ_FOREACH(devargs, &devargs_list, next) {
389 		if (devargs->type != devtype)
390 			continue;
391 		count++;
392 	}
393 	return count;
394 }
395 
396 /* dump the user devices on the console */
397 void
398 rte_devargs_dump(FILE *f)
399 {
400 	struct rte_devargs *devargs;
401 
402 	fprintf(f, "User device list:\n");
403 	TAILQ_FOREACH(devargs, &devargs_list, next) {
404 		fprintf(f, "  [%s]: %s %s\n",
405 			(devargs->bus ? devargs->bus->name : "??"),
406 			devargs->name, devargs->args);
407 	}
408 }
409 
410 /* bus-aware rte_devargs iterator. */
411 struct rte_devargs *
412 rte_devargs_next(const char *busname, const struct rte_devargs *start)
413 {
414 	struct rte_devargs *da;
415 
416 	if (start != NULL)
417 		da = TAILQ_NEXT(start, next);
418 	else
419 		da = TAILQ_FIRST(&devargs_list);
420 	while (da != NULL) {
421 		if (busname == NULL ||
422 		    (strcmp(busname, da->bus->name) == 0))
423 			return da;
424 		da = TAILQ_NEXT(da, next);
425 	}
426 	return NULL;
427 }
428