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