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 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 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 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 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 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 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 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 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 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 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 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 * 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