Parse a device description.
Split this description in their relevant part for each layers.
No dynamic allocation is performed.

Signed-off-by: Gaetan Rivet <gaetan.ri...@6wind.com>
---
 lib/Makefile                            |   1 +
 lib/librte_eal/bsdapp/eal/Makefile      |   1 +
 lib/librte_eal/common/eal_common_dev.c  | 148 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  24 ++++++
 lib/librte_eal/linuxapp/eal/Makefile    |   1 +
 lib/librte_eal/rte_eal_version.map      |   1 +
 6 files changed, 176 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index fc7a55a37..1b17526f7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 DIRS-y += librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
 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
diff --git a/lib/librte_eal/bsdapp/eal/Makefile 
b/lib/librte_eal/bsdapp/eal/Makefile
index c7d5abcd9..c13b08ed1 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3
 LDLIBS += -lexecinfo
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
 
 EXPORT_MAP := ../../rte_eal_version.map
 
diff --git a/lib/librte_eal/common/eal_common_dev.c 
b/lib/librte_eal/common/eal_common_dev.c
index cd071442f..1a671758a 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -10,9 +10,12 @@
 
 #include <rte_compat.h>
 #include <rte_bus.h>
+#include <rte_class.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 
 #include "eal_private.h"
@@ -207,3 +210,148 @@ rte_eal_hotplug_remove(const char *busname, const char 
*devname)
        rte_eal_devargs_remove(busname, devname);
        return ret;
 }
+
+static size_t
+dev_layer_count(const char *s)
+{
+       size_t i = s ? 1 : 0;
+
+       while (s != NULL && s[0] != '\0') {
+               i += s[0] == '/';
+               s++;
+       }
+       return i;
+}
+
+__rte_experimental
+int
+rte_dev_iterator_init(struct rte_dev_iterator *it,
+                     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;
+
+       /* Having both busstr and clsstr NULL is illegal,
+        * marking this iterator as invalid unless
+        * everything goes well.
+        */
+       it->busstr = NULL;
+       it->clsstr = NULL;
+       /* Split each sub-lists. */
+       nblayer = dev_layer_count(devstr);
+       if (nblayer > RTE_DIM(layers)) {
+               RTE_LOG(ERR, EAL, "Invalid query: too many layers (%zu)\n",
+                       nblayer);
+               rte_errno = EINVAL;
+               goto get_out;
+       }
+       while (s != NULL) {
+               char *copy;
+               char *end;
+
+               if (strncmp(layers[i].key, s,
+                           strlen(layers[i].key)))
+                       goto next_layer;
+               layers[i].str = s;
+               copy = strdup(s);
+               if (copy == NULL) {
+                       RTE_LOG(ERR, EAL, "OOM\n");
+                       rte_errno = ENOMEM;
+                       goto get_out;
+               }
+               end = strchr(copy, '/');
+               end = end ? end : strchr(copy, '\0');
+               end[0] = '\0';
+               layers[i].kvlist = rte_kvargs_parse(copy, NULL);
+               free(copy);
+               if (layers[i].kvlist == NULL) {
+                       RTE_LOG(ERR, EAL, "Could not parse %s\n", s);
+                       rte_errno = 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);
+                       rte_errno = 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);
+                               rte_errno = 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);
+                               rte_errno = EFAULT;
+                               goto get_out;
+                       }
+               } else if (strcmp(kv->key, "driver") == 0) {
+                       /* Ignore */
+                       continue;
+               }
+       }
+       /* The string should have at least
+        * one layer specified.
+        */
+       if (bus == NULL && cls == NULL) {
+               RTE_LOG(ERR, EAL,
+                       "Either bus or class must be specified.\n");
+               rte_errno = EINVAL;
+               goto get_out;
+       }
+       if (bus != NULL && bus->dev_iterate == NULL) {
+               RTE_LOG(ERR, EAL, "Bus %s not supported\n", bus->name);
+               rte_errno = ENOTSUP;
+               goto get_out;
+       }
+       if (cls != NULL && cls->dev_iterate == NULL) {
+               RTE_LOG(ERR, EAL, "Class %s not supported\n", cls->name);
+               rte_errno = ENOTSUP;
+               goto get_out;
+       }
+       /* Fill iterator fields. */
+       if (bus != NULL)
+               it->busstr = layers[0].str;
+       if (cls != NULL)
+               it->clsstr = layers[1].str;
+       it->devstr = devstr;
+       it->bus = bus;
+       it->cls = cls;
+       it->device = NULL;
+       it->class_device = NULL;
+get_out:
+       for (i = 0; i < RTE_DIM(layers); i++) {
+               if (layers[i].kvlist)
+                       rte_kvargs_free(layers[i].kvlist);
+       }
+       return -rte_errno;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h 
b/lib/librte_eal/common/include/rte_dev.h
index 937ff6079..f84128e5c 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -310,6 +310,30 @@ typedef void *(*rte_dev_iterate_t)(const void *start,
                                   const char *devstr,
                                   const struct rte_dev_iterator *it);
 
+/**
+ * Initializes a device iterator.
+ *
+ * This iterator allows accessing a list of devices matching a criteria.
+ * The device matching is made among all buses and classes currently 
registered,
+ * filtered by the device description given as parameter.
+ *
+ * This function will not allocate any memory. It is safe to stop the
+ * iteration at any moment and let the iterator go out of context.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @param str
+ *   Device description string.
+ *
+ * @return
+ *   0 on successful initialization.
+ *   <0 on error.
+ */
+__rte_experimental
+int
+rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/linuxapp/eal/Makefile 
b/lib/librte_eal/linuxapp/eal/Makefile
index 06ab30cad..6fb67bf7f 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -27,6 +27,7 @@ LDLIBS += -lrt
 ifeq ($(CONFIG_RTE_EAL_NUMA_AWARE_HUGEPAGES),y)
 LDLIBS += -lnuma
 endif
+LDLIBS += -lrte_kvargs
 
 # specific to linuxapp exec-env
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) := eal.c
diff --git a/lib/librte_eal/rte_eal_version.map 
b/lib/librte_eal/rte_eal_version.map
index afe6ce1b9..cad24376f 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -220,6 +220,7 @@ EXPERIMENTAL {
        rte_eal_devargs_remove;
        rte_class_register;
        rte_class_unregister;
+       rte_dev_iterator_init;
        rte_eal_hotplug_add;
        rte_eal_hotplug_remove;
        rte_eal_mbuf_user_pool_ops;
-- 
2.11.0

Reply via email to