devargs: add function to parse device layers
authorGaetan Rivet <gaetan.rivet@6wind.com>
Wed, 11 Jul 2018 21:44:58 +0000 (23:44 +0200)
committerThomas Monjalon <thomas@monjalon.net>
Sun, 15 Jul 2018 21:43:34 +0000 (23:43 +0200)
This function is private to the EAL.
It is used to parse each layers in a device description string,
and store the result in an rte_devargs structure.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
lib/Makefile
lib/librte_eal/bsdapp/eal/Makefile
lib/librte_eal/bsdapp/eal/meson.build
lib/librte_eal/common/eal_common_devargs.c
lib/librte_eal/common/eal_private.h
lib/librte_eal/common/include/rte_devargs.h
lib/librte_eal/linuxapp/eal/Makefile
lib/librte_eal/linuxapp/eal/meson.build

index 8a65525..afa604e 100644 (file)
@@ -7,6 +7,7 @@ DIRS-y += librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
 DEPDIRS-librte_kvargs := librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
+DEPDIRS-librte_eal := librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_RING) += librte_ring
index 48f85f5..be68407 100644 (file)
@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3
 LDLIBS += -lexecinfo
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
 
 EXPORT_MAP := ../../rte_eal_version.map
 
index 47e16a6..3945b52 100644 (file)
@@ -16,3 +16,5 @@ env_sources = files('eal_alarm.c',
                'eal_memory.c',
                'eal_dev.c'
 )
+
+deps += ['kvargs']
index f84f3d2..a22a200 100644 (file)
 #include <string.h>
 #include <stdarg.h>
 
+#include <rte_bus.h>
+#include <rte_class.h>
 #include <rte_compat.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_tailq.h>
 #include "eal_private.h"
@@ -57,6 +61,146 @@ rte_eal_parse_devargs_str(const char *devargs_str,
        return 0;
 }
 
+static size_t
+devargs_layer_count(const char *s)
+{
+       size_t i = s ? 1 : 0;
+
+       while (s != NULL && s[0] != '\0') {
+               i += s[0] == '/';
+               s++;
+       }
+       return i;
+}
+
+int
+rte_devargs_layers_parse(struct rte_devargs *devargs,
+                        const char *devstr)
+{
+       struct {
+               const char *key;
+               const char *str;
+               struct rte_kvargs *kvlist;
+       } layers[] = {
+               { "bus=",    NULL, NULL, },
+               { "class=",  NULL, NULL, },
+               { "driver=", NULL, NULL, },
+       };
+       struct rte_kvargs_pair *kv = NULL;
+       struct rte_class *cls = NULL;
+       struct rte_bus *bus = NULL;
+       const char *s = devstr;
+       size_t nblayer;
+       size_t i = 0;
+       int ret = 0;
+
+       /* Split each sub-lists. */
+       nblayer = devargs_layer_count(devstr);
+       if (nblayer > RTE_DIM(layers)) {
+               RTE_LOG(ERR, EAL, "Invalid format: too many layers (%zu)\n",
+                       nblayer);
+               ret = -E2BIG;
+               goto get_out;
+       }
+
+       /* If the devargs points the devstr
+        * as source data, then it should not allocate
+        * anything and keep referring only to it.
+        */
+       if (devargs->data != devstr) {
+               devargs->data = strdup(devstr);
+               if (devargs->data == NULL) {
+                       RTE_LOG(ERR, EAL, "OOM\n");
+                       ret = -ENOMEM;
+                       goto get_out;
+               }
+               s = devargs->data;
+       }
+
+       while (s != NULL) {
+               if (strncmp(layers[i].key, s,
+                           strlen(layers[i].key)) &&
+                   /* The last layer is free-form.
+                    * The "driver" key is not required (but accepted).
+                    */
+                   i != RTE_DIM(layers) - 1)
+                       goto next_layer;
+               layers[i].str = s;
+               layers[i].kvlist = rte_kvargs_parse_delim(s, NULL, "/");
+               if (layers[i].kvlist == NULL) {
+                       RTE_LOG(ERR, EAL, "Could not parse %s\n", s);
+                       ret = -EINVAL;
+                       goto get_out;
+               }
+               s = strchr(s, '/');
+               if (s != NULL)
+                       s++;
+next_layer:
+               if (i >= RTE_DIM(layers)) {
+                       RTE_LOG(ERR, EAL, "Unrecognized layer %s\n", s);
+                       ret = -EINVAL;
+                       goto get_out;
+               }
+               i++;
+       }
+
+       /* Parse each sub-list. */
+       for (i = 0; i < RTE_DIM(layers); i++) {
+               if (layers[i].kvlist == NULL)
+                       continue;
+               kv = &layers[i].kvlist->pairs[0];
+               if (strcmp(kv->key, "bus") == 0) {
+                       bus = rte_bus_find_by_name(kv->value);
+                       if (bus == NULL) {
+                               RTE_LOG(ERR, EAL, "Could not find bus \"%s\"\n",
+                                       kv->value);
+                               ret = -EFAULT;
+                               goto get_out;
+                       }
+               } else if (strcmp(kv->key, "class") == 0) {
+                       cls = rte_class_find_by_name(kv->value);
+                       if (cls == NULL) {
+                               RTE_LOG(ERR, EAL, "Could not find class \"%s\"\n",
+                                       kv->value);
+                               ret = -EFAULT;
+                               goto get_out;
+                       }
+               } else if (strcmp(kv->key, "driver") == 0) {
+                       /* Ignore */
+                       continue;
+               }
+       }
+
+       /* Fill devargs fields. */
+       devargs->bus_str = layers[0].str;
+       devargs->cls_str = layers[1].str;
+       devargs->drv_str = layers[2].str;
+       devargs->bus = bus;
+       devargs->cls = cls;
+
+       /* If we own the data, clean up a bit
+        * the several layers string, to ease
+        * their parsing afterward.
+        */
+       if (devargs->data != devstr) {
+               char *s = (void *)(intptr_t)(devargs->data);
+
+               while ((s = strchr(s, '/'))) {
+                       *s = '\0';
+                       s++;
+               }
+       }
+
+get_out:
+       for (i = 0; i < RTE_DIM(layers); i++) {
+               if (layers[i].kvlist)
+                       rte_kvargs_free(layers[i].kvlist);
+       }
+       if (ret != 0)
+               rte_errno = -ret;
+       return ret;
+}
+
 static int
 bus_name_cmp(const struct rte_bus *bus, const void *name)
 {
index b742f4c..4f809a8 100644 (file)
@@ -270,4 +270,38 @@ int rte_mp_channel_init(void);
  */
 void dev_callback_process(char *device_name, enum rte_dev_event_type event);
 
+/**
+ * @internal
+ * Parse a device string and store its information in an
+ * rte_devargs structure.
+ *
+ * A device description is split by layers of abstraction of the device:
+ * bus, class and driver. Each layer will offer a set of properties that
+ * can be applied either to configure or recognize a device.
+ *
+ * This function will parse those properties and prepare the rte_devargs
+ * to be given to each layers for processing.
+ *
+ * Note: if the "data" field of the devargs points to devstr,
+ * then no dynamic allocation is performed and the rte_devargs
+ * can be safely discarded.
+ *
+ * Otherwise ``data`` will hold a workable copy of devstr, that will be
+ * used by layers descriptors within rte_devargs. In this case,
+ * any rte_devargs should be cleaned-up before being freed.
+ *
+ * @param da
+ *   rte_devargs structure to fill.
+ *
+ * @param devstr
+ *   Device string.
+ *
+ * @return
+ *   0 on success.
+ *   Negative errno values on error (rte_errno is set).
+ */
+int
+rte_devargs_layers_parse(struct rte_devargs *devargs,
+                        const char *devstr);
+
 #endif /* _EAL_PRIVATE_H_ */
index 6c3b632..097a4ce 100644 (file)
@@ -51,12 +51,19 @@ struct rte_devargs {
        enum rte_devtype type;
        /** Device policy. */
        enum rte_dev_policy policy;
-       /** Bus handle for the device. */
-       struct rte_bus *bus;
        /** Name of the device. */
        char name[RTE_DEV_NAME_MAX_LEN];
+       RTE_STD_C11
+       union {
        /** Arguments string as given by user or "" for no argument. */
-       char *args;
+               char *args;
+               const char *drv_str;
+       };
+       struct rte_bus *bus; /**< bus handle. */
+       struct rte_class *cls; /**< class handle. */
+       const char *bus_str; /**< bus-related part of device string. */
+       const char *cls_str; /**< class-related part of device string. */
+       const char *data; /**< Device string storage. */
 };
 
 /**
index 14bad16..b483528 100644 (file)
@@ -24,6 +24,7 @@ LDLIBS += -ldl
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
 LDLIBS += -lrt
+LDLIBS += -lrte_kvargs
 ifeq ($(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),y)
 LDLIBS += -lnuma
 endif
index cce3771..6e31c2a 100644 (file)
@@ -23,6 +23,7 @@ env_sources = files('eal_alarm.c',
                'eal_dev.c',
 )
 
+deps += ['kvargs']
 if has_libnuma == 1
        dpdk_conf.set10('RTE_EAL_NUMA_AWARE_HUGEPAGES', true)
 endif