dpdk/lib/eal/common/eal_common_devargs.c
<<
>>
Prefs
   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 */
  25TAILQ_HEAD(rte_devargs_list, rte_devargs);
  26
  27/** Global list of user devices */
  28static struct rte_devargs_list devargs_list =
  29        TAILQ_HEAD_INITIALIZER(devargs_list);
  30
  31/* Resolve devargs name from bus arguments. */
  32static int
  33devargs_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
  53int
  54rte_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
 161get_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
 176static int
 177bus_name_cmp(const struct rte_bus *bus, const void *name)
 178{
 179        return strncmp(bus->name, name, strlen(bus->name));
 180}
 181
 182int
 183rte_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        memset(da, 0, sizeof(*da));
 193
 194        /* First parse according global device syntax. */
 195        if (rte_devargs_layers_parse(da, dev) == 0) {
 196                if (da->bus != NULL || da->cls != NULL)
 197                        return 0;
 198                rte_devargs_reset(da);
 199        }
 200
 201        /* Otherwise fallback to legacy syntax: */
 202
 203        /* Retrieve eventual bus info */
 204        do {
 205                devname = dev;
 206                bus = rte_bus_find(bus, bus_name_cmp, dev);
 207                if (bus == NULL)
 208                        break;
 209                devname = dev + strlen(bus->name) + 1;
 210                if (rte_bus_find_by_device_name(devname) == bus)
 211                        break;
 212        } while (1);
 213        /* Store device name */
 214        i = 0;
 215        while (devname[i] != '\0' && devname[i] != ',') {
 216                da->name[i] = devname[i];
 217                i++;
 218                if (i == maxlen) {
 219                        RTE_LOG(WARNING, EAL, "Parsing \"%s\": device name should be shorter than %zu\n",
 220                                dev, maxlen);
 221                        da->name[i - 1] = '\0';
 222                        return -EINVAL;
 223                }
 224        }
 225        da->name[i] = '\0';
 226        if (bus == NULL) {
 227                bus = rte_bus_find_by_device_name(da->name);
 228                if (bus == NULL) {
 229                        RTE_LOG(ERR, EAL, "failed to parse device \"%s\"\n",
 230                                da->name);
 231                        return -EFAULT;
 232                }
 233        }
 234        da->bus = bus;
 235        /* Parse eventual device arguments */
 236        if (devname[i] == ',')
 237                da->data = strdup(&devname[i + 1]);
 238        else
 239                da->data = strdup("");
 240        if (da->data == NULL) {
 241                RTE_LOG(ERR, EAL, "not enough memory to parse arguments\n");
 242                return -ENOMEM;
 243        }
 244        da->drv_str = da->data;
 245        return 0;
 246}
 247
 248int
 249rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
 250{
 251        va_list ap;
 252        int len;
 253        char *dev;
 254        int ret;
 255
 256        if (da == NULL)
 257                return -EINVAL;
 258
 259        va_start(ap, format);
 260        len = vsnprintf(NULL, 0, format, ap);
 261        va_end(ap);
 262        if (len < 0)
 263                return -EINVAL;
 264
 265        len += 1;
 266        dev = calloc(1, (size_t)len);
 267        if (dev == NULL) {
 268                RTE_LOG(ERR, EAL, "not enough memory to parse device\n");
 269                return -ENOMEM;
 270        }
 271
 272        va_start(ap, format);
 273        vsnprintf(dev, (size_t)len, format, ap);
 274        va_end(ap);
 275
 276        ret = rte_devargs_parse(da, dev);
 277
 278        free(dev);
 279        return ret;
 280}
 281
 282void
 283rte_devargs_reset(struct rte_devargs *da)
 284{
 285        if (da == NULL)
 286                return;
 287        free(da->data);
 288        da->data = NULL;
 289}
 290
 291int
 292rte_devargs_insert(struct rte_devargs **da)
 293{
 294        struct rte_devargs *listed_da;
 295        void *tmp;
 296
 297        if (*da == NULL || (*da)->bus == NULL)
 298                return -1;
 299
 300        RTE_TAILQ_FOREACH_SAFE(listed_da, &devargs_list, next, tmp) {
 301                if (listed_da == *da)
 302                        /* devargs already in the list */
 303                        return 0;
 304                if (strcmp(listed_da->bus->name, (*da)->bus->name) == 0 &&
 305                                strcmp(listed_da->name, (*da)->name) == 0) {
 306                        /* device already in devargs list, must be updated */
 307                        (*da)->next = listed_da->next;
 308                        rte_devargs_reset(listed_da);
 309                        *listed_da = **da;
 310                        /* replace provided devargs with found one */
 311                        free(*da);
 312                        *da = listed_da;
 313                        return 0;
 314                }
 315        }
 316        /* new device in the list */
 317        TAILQ_INSERT_TAIL(&devargs_list, *da, next);
 318        return 0;
 319}
 320
 321/* store in allowed list parameter for later parsing */
 322int
 323rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 324{
 325        struct rte_devargs *devargs = NULL;
 326        struct rte_bus *bus = NULL;
 327        const char *dev = devargs_str;
 328
 329        /* use calloc instead of rte_zmalloc as it's called early at init */
 330        devargs = calloc(1, sizeof(*devargs));
 331        if (devargs == NULL)
 332                goto fail;
 333
 334        if (rte_devargs_parse(devargs, dev))
 335                goto fail;
 336        devargs->type = devtype;
 337        bus = devargs->bus;
 338        if (devargs->type == RTE_DEVTYPE_BLOCKED)
 339                devargs->policy = RTE_DEV_BLOCKED;
 340        if (bus->conf.scan_mode == RTE_BUS_SCAN_UNDEFINED) {
 341                if (devargs->policy == RTE_DEV_ALLOWED)
 342                        bus->conf.scan_mode = RTE_BUS_SCAN_ALLOWLIST;
 343                else if (devargs->policy == RTE_DEV_BLOCKED)
 344                        bus->conf.scan_mode = RTE_BUS_SCAN_BLOCKLIST;
 345        }
 346        TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
 347        return 0;
 348
 349fail:
 350        if (devargs) {
 351                rte_devargs_reset(devargs);
 352                free(devargs);
 353        }
 354
 355        return -1;
 356}
 357
 358int
 359rte_devargs_remove(struct rte_devargs *devargs)
 360{
 361        struct rte_devargs *d;
 362        void *tmp;
 363
 364        if (devargs == NULL || devargs->bus == NULL)
 365                return -1;
 366
 367        RTE_TAILQ_FOREACH_SAFE(d, &devargs_list, next, tmp) {
 368                if (strcmp(d->bus->name, devargs->bus->name) == 0 &&
 369                    strcmp(d->name, devargs->name) == 0) {
 370                        TAILQ_REMOVE(&devargs_list, d, next);
 371                        rte_devargs_reset(d);
 372                        free(d);
 373                        return 0;
 374                }
 375        }
 376        return 1;
 377}
 378
 379/* count the number of devices of a specified type */
 380unsigned int
 381rte_devargs_type_count(enum rte_devtype devtype)
 382{
 383        struct rte_devargs *devargs;
 384        unsigned int count = 0;
 385
 386        TAILQ_FOREACH(devargs, &devargs_list, next) {
 387                if (devargs->type != devtype)
 388                        continue;
 389                count++;
 390        }
 391        return count;
 392}
 393
 394/* dump the user devices on the console */
 395void
 396rte_devargs_dump(FILE *f)
 397{
 398        struct rte_devargs *devargs;
 399
 400        fprintf(f, "User device list:\n");
 401        TAILQ_FOREACH(devargs, &devargs_list, next) {
 402                fprintf(f, "  [%s]: %s %s\n",
 403                        (devargs->bus ? devargs->bus->name : "??"),
 404                        devargs->name, devargs->args);
 405        }
 406}
 407
 408/* bus-aware rte_devargs iterator. */
 409struct rte_devargs *
 410rte_devargs_next(const char *busname, const struct rte_devargs *start)
 411{
 412        struct rte_devargs *da;
 413
 414        if (start != NULL)
 415                da = TAILQ_NEXT(start, next);
 416        else
 417                da = TAILQ_FIRST(&devargs_list);
 418        while (da != NULL) {
 419                if (busname == NULL ||
 420                    (strcmp(busname, da->bus->name) == 0))
 421                        return da;
 422                da = TAILQ_NEXT(da, next);
 423        }
 424        return NULL;
 425}
 426