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