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