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 <stdlib.h>
11 #include <string.h>
12 #include <stdarg.h>
13
14 #include <bus_driver.h>
15 #include <rte_class.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
devargs_bus_parse_default(struct rte_devargs * devargs,struct rte_kvargs * bus_args)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 EAL_LOG(DEBUG, "devargs name not found: %s",
43 devargs->data);
44 return 0;
45 }
46 if (rte_strscpy(devargs->name, name, sizeof(devargs->name)) < 0) {
47 EAL_LOG(ERR, "devargs name too long: %s",
48 devargs->data);
49 return -E2BIG;
50 }
51 return 0;
52 }
53
54 int
rte_devargs_layers_parse(struct rte_devargs * devargs,const char * devstr)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 EAL_LOG(ERR, "OOM");
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 EAL_LOG(ERR, "Could not find bus \"%s\"",
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 EAL_LOG(ERR, "Could not find class \"%s\"",
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 rte_kvargs_free(layers[i].kvlist);
165 }
166 if (ret != 0) {
167 if (allocated_data) {
168 /* Free duplicated data. */
169 free(devargs->data);
170 devargs->data = NULL;
171 }
172 rte_errno = -ret;
173 }
174 return ret;
175 }
176
177 static int
bus_name_cmp(const struct rte_bus * bus,const void * name)178 bus_name_cmp(const struct rte_bus *bus, const void *name)
179 {
180 return strncmp(bus->name, name, strlen(bus->name));
181 }
182
183 int
rte_devargs_parse(struct rte_devargs * da,const char * dev)184 rte_devargs_parse(struct rte_devargs *da, const char *dev)
185 {
186 struct rte_bus *bus = NULL;
187 const char *devname;
188 const size_t maxlen = sizeof(da->name);
189 size_t i;
190
191 if (da == NULL)
192 return -EINVAL;
193 memset(da, 0, sizeof(*da));
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 EAL_LOG(WARNING, "Parsing \"%s\": device name should be shorter than %zu",
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 EAL_LOG(ERR, "failed to parse device \"%s\"",
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 EAL_LOG(ERR, "not enough memory to parse arguments");
243 return -ENOMEM;
244 }
245 da->drv_str = da->data;
246 return 0;
247 }
248
249 int
rte_devargs_parsef(struct rte_devargs * da,const char * format,...)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 EAL_LOG(ERR, "not enough memory to parse device");
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
rte_devargs_reset(struct rte_devargs * da)284 rte_devargs_reset(struct rte_devargs *da)
285 {
286 if (da == NULL)
287 return;
288 free(da->data);
289 da->data = NULL;
290 }
291
292 int
rte_devargs_insert(struct rte_devargs ** da)293 rte_devargs_insert(struct rte_devargs **da)
294 {
295 struct rte_devargs *listed_da;
296 void *tmp;
297
298 if (*da == NULL || (*da)->bus == NULL)
299 return -1;
300
301 RTE_TAILQ_FOREACH_SAFE(listed_da, &devargs_list, next, tmp) {
302 if (listed_da == *da)
303 /* devargs already in the list */
304 return 0;
305 if (strcmp(listed_da->bus->name, (*da)->bus->name) == 0 &&
306 strcmp(listed_da->name, (*da)->name) == 0) {
307 /* device already in devargs list, must be updated */
308 (*da)->next = listed_da->next;
309 rte_devargs_reset(listed_da);
310 *listed_da = **da;
311 /* replace provided devargs with found one */
312 free(*da);
313 *da = listed_da;
314 return 0;
315 }
316 }
317 /* new device in the list */
318 TAILQ_INSERT_TAIL(&devargs_list, *da, next);
319 return 0;
320 }
321
322 /* store in allowed list parameter for later parsing */
323 int
rte_devargs_add(enum rte_devtype devtype,const char * devargs_str)324 rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
325 {
326 struct rte_devargs *devargs = NULL;
327 struct rte_bus *bus = NULL;
328 const char *dev = devargs_str;
329
330 /* use calloc instead of rte_zmalloc as it's called early at init */
331 devargs = calloc(1, sizeof(*devargs));
332 if (devargs == NULL)
333 goto fail;
334
335 if (rte_devargs_parse(devargs, dev))
336 goto fail;
337 devargs->type = devtype;
338 bus = devargs->bus;
339 if (devargs->type == RTE_DEVTYPE_BLOCKED)
340 devargs->policy = RTE_DEV_BLOCKED;
341 if (bus->conf.scan_mode == RTE_BUS_SCAN_UNDEFINED) {
342 if (devargs->policy == RTE_DEV_ALLOWED)
343 bus->conf.scan_mode = RTE_BUS_SCAN_ALLOWLIST;
344 else if (devargs->policy == RTE_DEV_BLOCKED)
345 bus->conf.scan_mode = RTE_BUS_SCAN_BLOCKLIST;
346 }
347 TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
348 return 0;
349
350 fail:
351 if (devargs) {
352 rte_devargs_reset(devargs);
353 free(devargs);
354 }
355
356 return -1;
357 }
358
359 int
rte_devargs_remove(struct rte_devargs * devargs)360 rte_devargs_remove(struct rte_devargs *devargs)
361 {
362 struct rte_devargs *d;
363 void *tmp;
364
365 if (devargs == NULL || devargs->bus == NULL)
366 return -1;
367
368 RTE_TAILQ_FOREACH_SAFE(d, &devargs_list, next, tmp) {
369 if (strcmp(d->bus->name, devargs->bus->name) == 0 &&
370 strcmp(d->name, devargs->name) == 0) {
371 TAILQ_REMOVE(&devargs_list, d, next);
372 rte_devargs_reset(d);
373 free(d);
374 return 0;
375 }
376 }
377 return 1;
378 }
379
380 /* count the number of devices of a specified type */
381 unsigned int
rte_devargs_type_count(enum rte_devtype devtype)382 rte_devargs_type_count(enum rte_devtype devtype)
383 {
384 struct rte_devargs *devargs;
385 unsigned int count = 0;
386
387 TAILQ_FOREACH(devargs, &devargs_list, next) {
388 if (devargs->type != devtype)
389 continue;
390 count++;
391 }
392 return count;
393 }
394
395 /* dump the user devices on the console */
396 void
rte_devargs_dump(FILE * f)397 rte_devargs_dump(FILE *f)
398 {
399 struct rte_devargs *devargs;
400
401 fprintf(f, "User device list:\n");
402 TAILQ_FOREACH(devargs, &devargs_list, next) {
403 fprintf(f, " [%s]: %s %s\n",
404 (devargs->bus ? devargs->bus->name : "??"),
405 devargs->name, devargs->args);
406 }
407 }
408
409 /* bus-aware rte_devargs iterator. */
410 struct rte_devargs *
rte_devargs_next(const char * busname,const struct rte_devargs * start)411 rte_devargs_next(const char *busname, const struct rte_devargs *start)
412 {
413 struct rte_devargs *da;
414
415 if (start != NULL)
416 da = TAILQ_NEXT(start, next);
417 else
418 da = TAILQ_FIRST(&devargs_list);
419 while (da != NULL) {
420 if (busname == NULL ||
421 (strcmp(busname, da->bus->name) == 0))
422 return da;
423 da = TAILQ_NEXT(da, next);
424 }
425 return NULL;
426 }
427