DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH v1 00/18] Device querying
@ 2018-03-15 17:49 Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 01/18] eal: introduce dtor macros Gaetan Rivet
                   ` (25 more replies)
  0 siblings, 26 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

Gaetan Rivet (18):
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  eal: add lightweight kvarg parsing utility
  eal/dev: add device iterator interface
  eal/dev: implement device iteration initialization
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  bus/pci: fix find device implementation
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: fix find device implementation
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                     |  52 +++++++++
 drivers/bus/pci/Makefile                   |   2 +-
 drivers/bus/pci/pci_common.c               |  97 ++++++++++++++--
 drivers/bus/pci/rte_bus_pci.h              |   3 +
 drivers/bus/vdev/Makefile                  |   2 +-
 drivers/bus/vdev/rte_bus_vdev.h            |   3 +
 drivers/bus/vdev/vdev.c                    |  86 +++++++++++++-
 lib/Makefile                               |   2 +-
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 ++++++++++
 lib/librte_eal/common/eal_common_dev.c     | 177 +++++++++++++++++++++++++++++
 lib/librte_eal/common/eal_private.h        |  34 ++++++
 lib/librte_eal/common/include/rte_bus.h    |   1 +
 lib/librte_eal/common/include/rte_class.h  | 127 +++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |  23 ++++
 lib/librte_eal/common/include/rte_dev.h    |  84 ++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   4 +
 lib/librte_ether/Makefile                  |   3 +-
 lib/librte_ether/rte_class_eth.c           | 100 ++++++++++++++++
 21 files changed, 847 insertions(+), 19 deletions(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ether/rte_class_eth.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 01/18] eal: introduce dtor macros
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 02/18] eal: introduce device class abstraction Gaetan Rivet
                   ` (24 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index c7803e41c..500fc3adb 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)
 static void __attribute__((constructor(prio), used)) func(void)
 
 /**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+static void __attribute__((destructor, used)) func(void)
+
+/**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(prio), used)) func(void)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 02/18] eal: introduce device class abstraction
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 01/18] eal: introduce dtor macros Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 03/18] eal/class: register destructor Gaetan Rivet
                   ` (23 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile        |   1 +
 lib/librte_eal/common/Makefile            |   2 +-
 lib/librte_eal/common/eal_common_class.c  |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h | 121 ++++++++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile      |   1 +
 lib/librte_eal/rte_eal_version.map        |   2 +
 6 files changed, 188 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index dd455e671..17ff1ac45 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index ea824a3a8..211b21b4b 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..beb0ba86c
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_bus structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, 120); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7e5bbe889..a3edbbe76 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index d12360235..910cb23c9 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -215,6 +215,8 @@ EXPERIMENTAL {
 	global:
 
 	rte_eal_cleanup;
+	rte_class_register;
+	rte_class_unregister;
 	rte_eal_devargs_insert;
 	rte_eal_devargs_parse;
 	rte_eal_devargs_remove;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 03/18] eal/class: register destructor
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 01/18] eal: introduce dtor macros Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 02/18] eal: introduce device class abstraction Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 04/18] eal: add lightweight kvarg parsing utility Gaetan Rivet
                   ` (22 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index beb0ba86c..a2e5f5551 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, 120); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 04/18] eal: add lightweight kvarg parsing utility
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (2 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 03/18] eal/class: register destructor Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 05/18] eal/dev: add device iterator interface Gaetan Rivet
                   ` (21 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This library offers a quick way to parse parameters passed with a
key=value syntax.

A single function is needed and finds the relevant element within the
text. No dynamic allocation is performed. It is possible to chain the
parsing of each pairs for quickly scanning a list.

This utility is private to the EAL and should allow avoiding having to
move around the more complete librte_kvargs.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c | 38 ++++++++++++++++++++++++++++++++++
 lib/librte_eal/common/eal_private.h    | 34 ++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index cd071442f..4032f1bd8 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -13,10 +13,48 @@
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
+#include <rte_errno.h>
 #include <rte_log.h>
 
 #include "eal_private.h"
 
+/* EAL-private function. */
+int
+rte_parse_kv(const char *str, struct rte_kvarg *kv)
+{
+	const char *equal;
+	const char *end;
+
+	if (str == NULL || str[0] == '\0')
+		return 1;
+	equal = strchr(str, '=');
+	if (equal == NULL) {
+		rte_errno = EINVAL;
+		return -1;
+	}
+	end = strchr(equal + 1, ',');
+	end = end ? end : strchr(equal + 1, '/');
+	end = end ? end : strchr(equal + 1, '\0');
+	if (end == NULL) {
+		rte_errno = ENODEV;
+		return -1;
+	}
+	if (kv == NULL)
+		return 0;
+	snprintf(kv->data, sizeof(kv->data), "%s", str);
+	kv->key = &kv->data[0];
+	strchr(kv->data, end[0])[0] = '\0';
+	if (strchr(kv->data, '=')) {
+		kv->value = strchr(kv->data, '=') + 1;
+		strchr(kv->data, '=')[0] = '\0';
+	}
+	if (end[0] == '\0')
+		kv->next = NULL;
+	else
+		kv->next = end + 1;
+	return 0;
+}
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 0b2877000..d2774a3ad 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -205,4 +205,38 @@ struct rte_bus *rte_bus_find_by_device_name(const char *str);
 
 int rte_mp_channel_init(void);
 
+/*
+ * Lightweight kvarg parsing library.
+ */
+
+#define RTE_MAX_KVARG_LEN 64
+
+/**
+ * Kvarg representation.
+ */
+struct rte_kvarg {
+	char *key; /**< points the key in the data. */
+	char *value; /**< points the value in the data. */
+	const char *next; /**< next token to parse, if any. */
+	char data[RTE_MAX_KVARG_LEN + 1]; /**< local copy of key and value. */
+};
+
+/**
+ * Parse one kvarg.
+ *
+ * The key-value pair must be shorter than the rte_kvarg data size.
+ *
+ * @param[in] str
+ *   text to parse.
+ *
+ * @param[out] kv
+ *   kvarg structure to fill.
+ *
+ * @return
+ *   0 if parsing succeeded.
+ *   >0 if there was nothing to parse.
+ *   <0 on error, rte_errno is set.
+ */
+int rte_parse_kv(const char *str, struct rte_kvarg *kv);
+
 #endif /* _EAL_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 05/18] eal/dev: add device iterator interface
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (3 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 04/18] eal: add lightweight kvarg parsing utility Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 06/18] eal/dev: implement device iteration initialization Gaetan Rivet
                   ` (20 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction them performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and storing the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 36 +++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index b688f1efd..d272d7191 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -263,6 +263,42 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	/* Bus context. */
+	struct rte_bus *bus; /**< bus handle. */
+	const char *busstr; /**< bus-related part of device string. */
+	struct rte_device *device; /**< current position. */
+	/* Class context. */
+	struct rte_class *cls; /**< class handle. */
+	const char *clsstr; /**< class-related part of device string. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Iterate over a set of devices, defined in comprehension by
+ * the given iterator.
+ *
+ * This function must update the internal rte_dev_iterator ``device``
+ * field. The ``context`` field can be used as an additional generic context
+ * when the current ``rte_device`` is insufficient.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element when the stopping
+ *   condition became valid.
+ */
+typedef struct rte_device *(*rte_dev_iterate_t)(struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 06/18] eal/dev: implement device iteration initialization
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (4 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 05/18] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 07/18] eal/class: add device iteration Gaetan Rivet
                   ` (19 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Parse a device description.

Split this description in their relevant part for both abstraction
layer.

No dynamic allocation is performed.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 23 +++++++++++++
 lib/librte_eal/rte_eal_version.map      |  1 +
 3 files changed, 82 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 4032f1bd8..bdab1423a 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -10,6 +10,7 @@
 
 #include <rte_compat.h>
 #include <rte_bus.h>
+#include <rte_class.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
@@ -245,3 +246,60 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)
 	rte_eal_devargs_remove(busname, devname);
 	return ret;
 }
+
+int __rte_experimental
+rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
+{
+	struct rte_bus *bus = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_kvarg kv;
+
+	/* Having both busstr and clsstr NULL is illegal,
+	 * marking this iterator as invalid unless
+	 * everything goes well.
+	 */
+	it->busstr = NULL;
+	it->clsstr = NULL;
+	/* Safety checks and prep-work */
+	if (rte_parse_kv(str, &kv)) {
+		RTE_LOG(ERR, EAL, "Could not parse: %s\n", str);
+		return -1;
+	}
+	it->device = NULL;
+	it->class_device = NULL;
+	if (strcmp(kv.key, "bus") == 0) {
+		char *slash;
+
+		bus = rte_bus_find_by_name(kv.value);
+		it->busstr = str;
+		slash = strchr(str, '/');
+		if (slash != NULL) {
+			if (rte_parse_kv(slash + 1, &kv))
+				return -1;
+			cls = rte_class_find_by_name(kv.value);
+			it->clsstr = slash + 1;
+		}
+	} else if (strcmp(kv.key, "class") == 0) {
+		cls = rte_class_find_by_name(kv.value);
+		it->clsstr = str;
+	} else {
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+	/* The string should have at least
+	 * one layer specified.
+	 */
+	if (bus == NULL && cls == NULL) {
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+	if ((bus != NULL && bus->dev_iterate == NULL) ||
+	    (cls != NULL && cls->dev_iterate == NULL)) {
+		rte_errno = ENOTSUP;
+		return -rte_errno;
+	}
+	it->devstr = str;
+	it->bus = bus;
+	it->cls = cls;
+	return 0;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index d272d7191..9b53f0ad3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -299,6 +299,29 @@ struct rte_dev_iterator {
  */
 typedef struct rte_device *(*rte_dev_iterate_t)(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.
+ */
+int __rte_experimental
+rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 910cb23c9..921da3075 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -228,6 +228,7 @@ EXPERIMENTAL {
 	rte_mp_sendmsg;
 	rte_mp_request;
 	rte_mp_reply;
+	rte_dev_iterator_init;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 07/18] eal/class: add device iteration
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (5 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 06/18] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 08/18] eal/bus: " Gaetan Rivet
                   ` (18 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index a2e5f5551..47ebaba31 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 08/18] eal/bus: add device iteration
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (6 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 07/18] eal/class: add device iteration Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 09/18] eal/dev: implement " Gaetan Rivet
                   ` (17 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 6fb08341a..46911afa7 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 09/18] eal/dev: implement device iteration
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (7 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 08/18] eal/bus: " Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 10/18] ethdev: register ether layer as a class Gaetan Rivet
                   ` (16 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 81 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 25 ++++++++++
 lib/librte_eal/rte_eal_version.map      |  1 +
 3 files changed, 107 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index bdab1423a..159fdcf73 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -303,3 +303,84 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
 	it->cls = cls;
 	return 0;
 }
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *_it)
+{
+	const struct rte_dev_iterator *cit = _it;
+	struct rte_dev_iterator *it;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	/* We need a mutable iterator. */
+	it = (void *)(intptr_t)cit;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	return cls->dev_iterate(it) == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *_it)
+{
+	const struct rte_dev_iterator *cit = _it;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	/* We need a mutable iterator. */
+	it = (void *)(intptr_t)cit;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	if (it->clsstr == NULL)
+		return bus->dev_iterate(it) == NULL;
+	/* clsstr != NULL */
+	if (it->device == NULL)
+next_dev_on_bus:
+		bus->dev_iterate(it);
+	if (it->device == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, it);
+	if (cls != NULL) {
+		it->cls = cls;
+		return 0;
+	}
+	goto next_dev_on_bus;
+}
+__rte_experimental struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp, it))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			return it->device;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+	return NULL;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 9b53f0ad3..11a6d786c 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -322,6 +322,31 @@ typedef struct rte_device *(*rte_dev_iterate_t)(struct rte_dev_iterator *it);
 int __rte_experimental
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+struct rte_device * __rte_experimental
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 921da3075..925efcb6d 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	rte_mp_request;
 	rte_mp_reply;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 10/18] ethdev: register ether layer as a class
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (8 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 09/18] eal/dev: implement " Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 11/18] ethdev: add device matching field name Gaetan Rivet
                   ` (15 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                     |  2 +-
 lib/librte_ether/Makefile        |  3 +-
 lib/librte_ether/rte_class_eth.c | 86 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 89 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_ether/rte_class_eth.c

diff --git a/lib/Makefile b/lib/Makefile
index ec965a606..6bb6a8bed 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -20,7 +20,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf
+DEPDIRS-librte_ether += librte_mbuf librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 3ca5782bb..a1a0393de 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 8
 
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
new file mode 100644
index 000000000..bfa821d09
--- /dev/null
+++ b/lib/librte_ether/rte_class_eth.c
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+
+static int
+eth_dev_match(struct rte_eth_dev *edev,
+	      struct rte_kvargs *kvlist)
+{
+	(void) kvlist;
+	(void) edev;
+	return 0;
+}
+
+static struct rte_device *
+eth_dev_iterate(struct rte_dev_iterator *it)
+{
+	struct rte_eth_dev *start = it->class_device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+	struct rte_device *dev = NULL;
+	char *str = NULL;
+	uint16_t p = 0;
+
+	if (it->clsstr != NULL) {
+		char *slash;
+
+		str = strdup(it->clsstr);
+		if (str == NULL) {
+			RTE_LOG(ERR, EAL, "cannot allocate string copy\n");
+			rte_errno = ENOMEM;
+			return NULL;
+		}
+		slash = strchr(str, '/');
+		slash = slash ? slash : strchr(str, '\0');
+		if (slash == NULL) {
+			RTE_LOG(ERR, EAL, "malformed string\n");
+			rte_errno = EINVAL;
+			goto free_str;
+		}
+		slash[0] = '\0';
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			goto free_str;
+		}
+	}
+	if (start)
+		p = start->data->port_id + 1;
+	dev = it->device;
+	for (p = rte_eth_find_next(p);
+	     p < RTE_MAX_ETHPORTS;
+	     p = rte_eth_find_next(p + 1)) {
+		edev = &rte_eth_devices[p];
+		if (dev != edev->device)
+			continue;
+		if (eth_dev_match(edev, kvargs) == 0) {
+			it->class_device = edev;
+			goto free_str;
+		}
+	}
+	dev = NULL;
+free_str:
+	if (it->clsstr != NULL) {
+		rte_kvargs_free(kvargs);
+		free(str);
+	}
+	return dev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 11/18] ethdev: add device matching field name
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (9 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 10/18] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 12/18] bus/pci: fix find device implementation Gaetan Rivet
                   ` (14 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/rte_class_eth.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
index bfa821d09..2f362ebcc 100644
--- a/lib/librte_ether/rte_class_eth.c
+++ b/lib/librte_ether/rte_class_eth.c
@@ -14,11 +14,25 @@
 #include "rte_ethdev_core.h"
 
 static int
+eth_dev_str_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_str)
+{
+	const char *str = _str;
+
+	return strcmp(str, value);
+}
+
+static int
 eth_dev_match(struct rte_eth_dev *edev,
 	      struct rte_kvargs *kvlist)
 {
-	(void) kvlist;
-	(void) edev;
+	struct rte_eth_dev_data *data;
+
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			&eth_dev_str_cmp, data->name))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 12/18] bus/pci: fix find device implementation
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (10 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 11/18] ethdev: add device matching field name Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 13/18] bus/pci: implement device iteration and comparison Gaetan Rivet
                   ` (13 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set, and a device before it matches the data
passed for comparison, then this first device is returned.

This produces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2a00f365a..2c45f8151 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -459,17 +459,20 @@ static struct rte_device *
 pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		const void *data)
 {
-	struct rte_pci_device *dev;
+	const struct rte_pci_device *pstart;
+	struct rte_pci_device *pdev;
 
-	FOREACH_DEVICE_ON_PCIBUS(dev) {
-		if (start && &dev->device == start) {
-			start = NULL; /* starting point found */
-			continue;
-		}
-		if (cmp(&dev->device, data) == 0)
-			return &dev->device;
+	if (start != NULL) {
+		pstart = RTE_DEV_TO_PCI_CONST(start);
+		pdev = TAILQ_NEXT(pstart, next);
+	} else {
+		pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
+	}
+	while (pdev != NULL) {
+		if (cmp(&pdev->device, data) == 0)
+			return &pdev->device;
+		pdev = TAILQ_NEXT(pdev, next);
 	}
-
 	return NULL;
 }
 
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 357afb912..458e6d076 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -74,6 +74,9 @@ struct rte_pci_device {
  */
 #define RTE_DEV_TO_PCI(ptr) container_of(ptr, struct rte_pci_device, device)
 
+#define RTE_DEV_TO_PCI_CONST(ptr) \
+	container_of(ptr, const struct rte_pci_device, device)
+
 #define RTE_ETH_DEV_TO_PCI(eth_dev)	RTE_DEV_TO_PCI((eth_dev)->device)
 
 /** Any PCI device identifier (vendor, device, ...) */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 13/18] bus/pci: implement device iteration and comparison
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (11 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 12/18] bus/pci: fix find device implementation Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 14/18] bus/pci: add device matching field id Gaetan Rivet
                   ` (12 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 54 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index f3df1c4ce..73498dc77 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -50,7 +50,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
 CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2c45f8151..482c96df2 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -13,6 +13,7 @@
 
 #include <rte_errno.h>
 #include <rte_interrupts.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
@@ -497,6 +498,58 @@ pci_unplug(struct rte_device *dev)
 	return ret;
 }
 
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+static struct rte_device *
+pci_dev_iterate(struct rte_dev_iterator *it)
+{
+	struct rte_device *dev = it->device;
+	struct rte_kvargs *kvargs = NULL;
+	char *str = NULL;
+
+	if (it->busstr != NULL) {
+		char *slash;
+
+		str = strdup(it->busstr);
+		if (str == NULL) {
+			RTE_LOG(ERR, EAL, "could not allocate string copy\n");
+			rte_errno = ENOMEM;
+			return NULL;
+		}
+		slash = strchr(str, '/');
+		slash = slash ? slash : strchr(str, '\0');
+		if (slash == NULL) {
+			RTE_LOG(ERR, EAL, "malformed string\n");
+			rte_errno = EINVAL;
+			goto free_str;
+		}
+		slash[0] = '\0';
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			goto free_str;
+		}
+	}
+	dev = pci_find_device(dev, pci_dev_match, kvargs);
+	it->device = dev;
+free_str:
+	if (it->busstr != NULL) {
+		free(str);
+		rte_kvargs_free(kvargs);
+	}
+	return dev;
+}
+
 struct rte_pci_bus rte_pci_bus = {
 	.bus = {
 		.scan = rte_pci_scan,
@@ -506,6 +559,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 14/18] bus/pci: add device matching field id
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (12 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 13/18] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 15/18] bus/vdev: fix find device implementation Gaetan Rivet
                   ` (11 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 482c96df2..6cf1279c3 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -499,13 +499,35 @@ pci_unplug(struct rte_device *dev)
 }
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return rte_pci_addr_cmp(addr1, addr2);
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 15/18] bus/vdev: fix find device implementation
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (13 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 14/18] bus/pci: add device matching field id Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 16/18] bus/vdev: implement device iteration Gaetan Rivet
                   ` (10 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set and a device before it matches the data,
this device is returned.

This produces induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/vdev/rte_bus_vdev.h b/drivers/bus/vdev/rte_bus_vdev.h
index f9d8a2383..4da9967c6 100644
--- a/drivers/bus/vdev/rte_bus_vdev.h
+++ b/drivers/bus/vdev/rte_bus_vdev.h
@@ -53,6 +53,9 @@ struct rte_vdev_device {
 #define RTE_DEV_TO_VDEV(ptr) \
 	container_of(ptr, struct rte_vdev_device, device)
 
+#define RTE_DEV_TO_VDEV_CONST(ptr) \
+	container_of(ptr, const struct rte_vdev_device, device)
+
 static inline const char *
 rte_vdev_device_name(const struct rte_vdev_device *dev)
 {
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index e4bc72463..68306f4eb 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -386,15 +386,19 @@ static struct rte_device *
 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		 const void *data)
 {
+	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
 
-	TAILQ_FOREACH(dev, &vdev_device_list, next) {
-		if (start && &dev->device == start) {
-			start = NULL;
-			continue;
-		}
+	if (start != NULL) {
+		vstart = RTE_DEV_TO_VDEV_CONST(start);
+		dev = TAILQ_NEXT(vstart, next);
+	} else {
+		dev = TAILQ_FIRST(&vdev_device_list);
+	}
+	while (dev != NULL) {
 		if (cmp(&dev->device, data) == 0)
 			return &dev->device;
+		dev = TAILQ_NEXT(dev, next);
 	}
 	return NULL;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 16/18] bus/vdev: implement device iteration
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (14 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 15/18] bus/vdev: fix find device implementation Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 17/18] bus/vdev: add device matching field driver Gaetan Rivet
                   ` (9 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 54 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 55 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 24d424a38..52728833c 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 68306f4eb..d695bdf24 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -43,6 +43,7 @@
 #include <rte_bus.h>
 #include <rte_common.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
 #include <rte_memory.h>
 #include <rte_tailq.h>
 #include <rte_spinlock.h>
@@ -415,6 +416,58 @@ vdev_unplug(struct rte_device *dev)
 	return rte_vdev_uninit(dev->name);
 }
 
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+static struct rte_device *
+vdev_dev_iterate(struct rte_dev_iterator *it)
+{
+	struct rte_device *dev = it->device;
+	struct rte_kvargs *kvargs = NULL;
+	char *str = NULL;
+
+	if (it->busstr != NULL) {
+		char *slash;
+
+		str = strdup(it->busstr);
+		if (str == NULL) {
+			VDEV_LOG(ERR, "could not allocate string copy\n");
+			rte_errno = ENOMEM;
+			return NULL;
+		}
+		slash = strchr(str, '/');
+		slash = slash ? slash : strchr(str, '\0');
+		if (slash == NULL) {
+			VDEV_LOG(ERR, "malformed string\n");
+			rte_errno = EINVAL;
+			goto free_str;
+		}
+		slash[0] = '\0';
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			goto free_str;
+		}
+	}
+	dev = vdev_find_device(dev, vdev_dev_match, kvargs);
+	it->device = dev;
+free_str:
+	if (it->busstr != NULL) {
+		free(str);
+		rte_kvargs_free(kvargs);
+	}
+	return dev;
+}
+
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
@@ -422,6 +475,7 @@ static struct rte_bus rte_vdev_bus = {
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 17/18] bus/vdev: add device matching field driver
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (15 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 16/18] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 18/18] app/testpmd: add show device command Gaetan Rivet
                   ` (8 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index d695bdf24..154d5e4bb 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -417,13 +417,31 @@ vdev_unplug(struct rte_device *dev)
 }
 
 static int
+vdev_str_kv_cmp(const char *key __rte_unused,
+	     const char *value,
+	     void *_str)
+{
+	const  char *str = _str;
+
+	return strcmp(str, value);
+}
+
+static int
 vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		&vdev_str_kv_cmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v1 18/18] app/testpmd: add show device command
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (16 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 17/18] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-03-15 17:49 ` Gaetan Rivet
  2018-03-19 11:33   ` Gaëtan Rivet
  2018-03-20 17:51 ` [dpdk-dev] [PATCH v1 00/18] Device querying Gaëtan Rivet
                   ` (7 subsequent siblings)
  25 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-15 17:49 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev,class=eth
   show device bus=vdev,class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..8ac5fb3ca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device "
+		"<device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v1 18/18] app/testpmd: add show device command
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 18/18] app/testpmd: add show device command Gaetan Rivet
@ 2018-03-19 11:33   ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-19 11:33 UTC (permalink / raw)
  To: dev

On Thu, Mar 15, 2018 at 06:49:48PM +0100, Gaetan Rivet wrote:
> A new interactive command is offered:
> 
>    show device <device description>
> 
> This commands lists all rte_device element matching the device
> description. e.g.:
> 
>    show device bus=pci
>    show device bus=vdev
>    show device bus=vdev,class=eth
>    show device bus=vdev,class=eth,name=net_ring0

Silly mistake, it should read instead:

     show device bus=pci
     show device bus=vdev
     show device bus=vdev/class=eth
     show device bus=vdev/class=eth,name=net_ring0

> 
> These devices may not be otherwise useful, some buses will spawn devices
> to keep track of their assets without having a driver to use them.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index 40b31ad7e..8ac5fb3ca 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
>  	},
>  };
>  
> +/* *** SHOW DEVICE INFO *** */
> +struct cmd_showdevice_result {
> +	cmdline_fixed_string_t show;
> +	cmdline_fixed_string_t device;
> +	cmdline_fixed_string_t filter;
> +};
> +
> +static void
> +cmd_showdevice_dump_device(const struct rte_device *dev)
> +{
> +	const struct rte_driver *drv = dev->driver;
> +
> +	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
> +		drv ? drv->name : "<nil>");
> +}
> +
> +static void cmd_showdevice_parsed(void *parsed_result,
> +				__attribute__((unused)) struct cmdline *cl,
> +				__attribute__((unused)) void *data)
> +{
> +	struct cmd_showdevice_result *res = parsed_result;
> +	struct rte_dev_iterator it;
> +	const struct rte_device *dev;
> +
> +	RTE_DEV_FOREACH(dev, res->filter, &it)
> +		cmd_showdevice_dump_device(dev);
> +}
> +
> +cmdline_parse_token_string_t cmd_showdevice_show =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +				show, "show");
> +cmdline_parse_token_string_t cmd_showdevice_device =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +				device, "device");
> +cmdline_parse_token_string_t cmd_showdevice_filter =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +			filter, NULL);
> +
> +cmdline_parse_inst_t cmd_showdevice = {
> +	.f = cmd_showdevice_parsed,
> +	.data = NULL,
> +	.help_str = "show device "
> +		"<device string>",
> +	.tokens = {
> +		(void *)&cmd_showdevice_show,
> +		(void *)&cmd_showdevice_device,
> +		(void *)&cmd_showdevice_filter,
> +		NULL,
> +	},
> +};
> +
>  /* *** SHOW PORT INFO *** */
>  struct cmd_showport_result {
>  	cmdline_fixed_string_t show;
> @@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
>  	(cmdline_parse_inst_t *)&cmd_help_long,
>  	(cmdline_parse_inst_t *)&cmd_quit,
>  	(cmdline_parse_inst_t *)&cmd_load_from_file,
> +	(cmdline_parse_inst_t *)&cmd_showdevice,
>  	(cmdline_parse_inst_t *)&cmd_showport,
>  	(cmdline_parse_inst_t *)&cmd_showqueue,
>  	(cmdline_parse_inst_t *)&cmd_showportall,
> -- 
> 2.11.0
> 

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v1 00/18] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (17 preceding siblings ...)
  2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 18/18] app/testpmd: add show device command Gaetan Rivet
@ 2018-03-20 17:51 ` Gaëtan Rivet
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                   ` (6 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-20 17:51 UTC (permalink / raw)
  To: dev

On Thu, Mar 15, 2018 at 06:49:30PM +0100, Gaetan Rivet wrote:
> This patchset introduces a new EAL API for querying devices,
> filtered by arbitrary properties.
> 
> The following elements are introduced to this end:
> 
>  * A new object, "rte_class", is used to describe
>    the device class abstraction layer (eth, crypto, ...).
> 
>  * Both rte_bus and rte_class now offer a way to
>    list their devices and filter the result
>    using locally defined properties.
> 
>  * The rte_dev API now has an rte_dev_iterator, which
>    is the way for the user to define the device filter
>    and iterate upon the resulting set.
> 
> As an example, the "eth" device class is implemented.
> 
> Additionally, the device filters for
> 
>   + rte_bus_pci
>   + rte_bus_vdev
>   + rte_class_eth
> 
> are implemented and can be used with some
> properties each, to show how to extend those.
> 
> Some example of filters:
> 
>   "bus=pci/class=eth"
>   "bus=pci"
>   "class=eth"
>   "class=eth,name=net_ring0"
>   "bus=pci,id=00:00.0"
>   "bus=vdev,driver=net_ring"
> 
> Gaetan Rivet (18):

To ease reviewing and have a state of this work, here is a summary of
what to expect / my opinion of what's done:

>   eal: introduce dtor macros

  * Not sure this is necessary, but as long as the libc has a dlclose,
    it makes sense to have a way to cleanly unload objects.

>   eal: introduce device class abstraction

  * The class abstraction might seem controversial introduced there,
    but I do not think there is any other solution than adding it.
    The EAL needs a way to converse in a generic way with each types of
    devices, even if the technical solution I proposed afterward is not
    accepted.

>   eal/class: register destructor

  * If the dtor patch above is accepted, this patch could be squashed
    with the previous one. Otherwise, it can be dropped.

>   eal: add lightweight kvarg parsing utility
>   eal/dev: add device iterator interface

  * An important question regarding device matching is how to deal
    when the query is ambiguous and several devices could match.
    I have taken the technical bias of leaving the management of this
    case to the user.
    This has the beneficial side-effect of allowing to list all devices
    matching specific properties. I think this is useful.
    However, much of the complexity of this solution comes from this
    added functionality.

  * The iterator only allows filtering on the two abstractions:
    + bus
    + class
    This limitation is hard-coded, simplifying the implementation.

>   eal/dev: implement device iteration initialization

  * An important element of this initialization was to make it entirely
    static. To help the user correctly use this API, this seemed important.
    No dynamic allocation was to be performed here.

    This means that the device description string must live for the time
    of the iteration. An iterator must be iterated in the same scope it
    has been initialized.

    A big problem with this approach, is that the matching strings
    cannot be duplicated to be properly reformated, helping the
    subsequent parsing. Thus, the iteration operation implemented both
    in rte_bus and rte_class are more complex, having to take care of
    both cases where an ending '/' and '\0' are present, and this, for
    all implementations. I profoundly dislike this complexity being
    replicated thusly, but I think the advantage of having a lean
    iterator init is worth it.

>   eal/class: add device iteration
>   eal/bus: add device iteration
>   eal/dev: implement device iteration

  * Iteration has been choosen over implementing only a match function,
    that would be used in conjunction with the existing
    bus->find_device

    The reasoning for this is two-fold:

      - Classes are not streamlined. They usually link rte_devices
        instead of extending the rte_device object with their own
        meta-data, like rte_buses are doing.
        So the iteration itself had to be as flexible as possible,
        to allow rte_classes to do anything they might need to
        speed up / simplify the iteration.

     - The filtering strings could have been made once for all
       filters, having only to call *_find_device with the proper
       matching function.

       However, instead of replicating the string handling, each
       matching would thus have to parse the kvargs itself or have the
       kvargs parsed prior to being called. The latter would mean having
       the EAL dependent on librte_kvargs. The former meaning that
       kvargs would be repeated again and again, with dynamic
       allocations with it (meaning that they could not just be kept
       away until the next iteration as they would be already parsed, as
       the user could always break the iteration, loosing the
       reference).

    I think the choice of iteration vs. match function is central to the
    design of this solution and should be carefully reviewed. I tried to
    make the right call, can be wrong.

vvvvvvvvv <-- the rest only builds upon the foundations layed out by the
              previous patches, so choices here are less important.

              Last point however: I havent yet implemented the
              rte_eth_dev finder taking a device description as input
              and giving the corresponding port_id. It should be simple
              to implement with this new API so I will do it shortly,
              once I have some time for it.

>   ethdev: register ether layer as a class
>   ethdev: add device matching field name
>   bus/pci: fix find device implementation
>   bus/pci: implement device iteration and comparison
>   bus/pci: add device matching field id
>   bus/vdev: fix find device implementation
>   bus/vdev: implement device iteration
>   bus/vdev: add device matching field driver
>   app/testpmd: add show device command
> 
>  app/test-pmd/cmdline.c                     |  52 +++++++++
>  drivers/bus/pci/Makefile                   |   2 +-
>  drivers/bus/pci/pci_common.c               |  97 ++++++++++++++--
>  drivers/bus/pci/rte_bus_pci.h              |   3 +
>  drivers/bus/vdev/Makefile                  |   2 +-
>  drivers/bus/vdev/rte_bus_vdev.h            |   3 +
>  drivers/bus/vdev/vdev.c                    |  86 +++++++++++++-
>  lib/Makefile                               |   2 +-
>  lib/librte_eal/bsdapp/eal/Makefile         |   1 +
>  lib/librte_eal/common/Makefile             |   2 +-
>  lib/librte_eal/common/eal_common_class.c   |  62 ++++++++++
>  lib/librte_eal/common/eal_common_dev.c     | 177 +++++++++++++++++++++++++++++
>  lib/librte_eal/common/eal_private.h        |  34 ++++++
>  lib/librte_eal/common/include/rte_bus.h    |   1 +
>  lib/librte_eal/common/include/rte_class.h  | 127 +++++++++++++++++++++
>  lib/librte_eal/common/include/rte_common.h |  23 ++++
>  lib/librte_eal/common/include/rte_dev.h    |  84 ++++++++++++++
>  lib/librte_eal/linuxapp/eal/Makefile       |   1 +
>  lib/librte_eal/rte_eal_version.map         |   4 +
>  lib/librte_ether/Makefile                  |   3 +-
>  lib/librte_ether/rte_class_eth.c           | 100 ++++++++++++++++
>  21 files changed, 847 insertions(+), 19 deletions(-)
>  create mode 100644 lib/librte_eal/common/eal_common_class.c
>  create mode 100644 lib/librte_eal/common/include/rte_class.h
>  create mode 100644 lib/librte_ether/rte_class_eth.c
> 
> -- 
> 2.11.0
> 

Regards,
-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 00/18] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (18 preceding siblings ...)
  2018-03-20 17:51 ` [dpdk-dev] [PATCH v1 00/18] Device querying Gaëtan Rivet
@ 2018-03-21 17:15 ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Gaetan Rivet
                     ` (19 more replies)
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                   ` (5 subsequent siblings)
  25 siblings, 20 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

Gaetan Rivet (18):
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  eal: add lightweight kvarg parsing utility
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  bus/pci: fix find device implementation
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: fix find device implementation
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                     |  52 ++++++
 drivers/bus/pci/Makefile                   |   2 +-
 drivers/bus/pci/pci_common.c               |  77 ++++++++-
 drivers/bus/pci/rte_bus_pci.h              |   3 +
 drivers/bus/vdev/Makefile                  |   2 +-
 drivers/bus/vdev/rte_bus_vdev.h            |   3 +
 drivers/bus/vdev/vdev.c                    |  66 +++++++-
 lib/Makefile                               |   2 +-
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++
 lib/librte_eal/common/eal_common_dev.c     | 255 +++++++++++++++++++++++++++++
 lib/librte_eal/common/eal_private.h        |  34 ++++
 lib/librte_eal/common/include/rte_bus.h    |   1 +
 lib/librte_eal/common/include/rte_class.h  | 127 ++++++++++++++
 lib/librte_eal/common/include/rte_common.h |  23 +++
 lib/librte_eal/common/include/rte_dev.h    |  95 +++++++++++
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   4 +
 lib/librte_ether/Makefile                  |   3 +-
 lib/librte_ether/rte_class_eth.c           |  79 +++++++++
 21 files changed, 875 insertions(+), 19 deletions(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ether/rte_class_eth.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-22 11:35     ` Neil Horman
  2018-03-22 13:51     ` Neil Horman
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 02/18] eal: introduce device class abstraction Gaetan Rivet
                     ` (18 subsequent siblings)
  19 siblings, 2 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index c7803e41c..500fc3adb 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)
 static void __attribute__((constructor(prio), used)) func(void)
 
 /**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+static void __attribute__((destructor, used)) func(void)
+
+/**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(prio), used)) func(void)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 02/18] eal: introduce device class abstraction
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 03/18] eal/class: register destructor Gaetan Rivet
                     ` (17 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile        |   1 +
 lib/librte_eal/common/Makefile            |   2 +-
 lib/librte_eal/common/eal_common_class.c  |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h | 121 ++++++++++++++++++++++++++++++
 lib/librte_eal/linuxapp/eal/Makefile      |   1 +
 lib/librte_eal/rte_eal_version.map        |   2 +
 6 files changed, 188 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index dd455e671..17ff1ac45 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index ea824a3a8..211b21b4b 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..beb0ba86c
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_bus structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, 120); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7e5bbe889..a3edbbe76 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index d12360235..910cb23c9 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -215,6 +215,8 @@ EXPERIMENTAL {
 	global:
 
 	rte_eal_cleanup;
+	rte_class_register;
+	rte_class_unregister;
 	rte_eal_devargs_insert;
 	rte_eal_devargs_parse;
 	rte_eal_devargs_remove;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 03/18] eal/class: register destructor
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 02/18] eal: introduce device class abstraction Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility Gaetan Rivet
                     ` (16 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index beb0ba86c..a2e5f5551 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, 120); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (2 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 03/18] eal/class: register destructor Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:32     ` Wiles, Keith
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 05/18] eal/dev: add device iterator interface Gaetan Rivet
                     ` (15 subsequent siblings)
  19 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This library offers a quick way to parse parameters passed with a
key=value syntax.

A single function is needed and finds the relevant element within the
text. No dynamic allocation is performed. It is possible to chain the
parsing of each pairs for quickly scanning a list.

This utility is private to the EAL and should allow avoiding having to
move around the more complete librte_kvargs.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c | 38 ++++++++++++++++++++++++++++++++++
 lib/librte_eal/common/eal_private.h    | 34 ++++++++++++++++++++++++++++++
 2 files changed, 72 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index cd071442f..4032f1bd8 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -13,10 +13,48 @@
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
+#include <rte_errno.h>
 #include <rte_log.h>
 
 #include "eal_private.h"
 
+/* EAL-private function. */
+int
+rte_parse_kv(const char *str, struct rte_kvarg *kv)
+{
+	const char *equal;
+	const char *end;
+
+	if (str == NULL || str[0] == '\0')
+		return 1;
+	equal = strchr(str, '=');
+	if (equal == NULL) {
+		rte_errno = EINVAL;
+		return -1;
+	}
+	end = strchr(equal + 1, ',');
+	end = end ? end : strchr(equal + 1, '/');
+	end = end ? end : strchr(equal + 1, '\0');
+	if (end == NULL) {
+		rte_errno = ENODEV;
+		return -1;
+	}
+	if (kv == NULL)
+		return 0;
+	snprintf(kv->data, sizeof(kv->data), "%s", str);
+	kv->key = &kv->data[0];
+	strchr(kv->data, end[0])[0] = '\0';
+	if (strchr(kv->data, '=')) {
+		kv->value = strchr(kv->data, '=') + 1;
+		strchr(kv->data, '=')[0] = '\0';
+	}
+	if (end[0] == '\0')
+		kv->next = NULL;
+	else
+		kv->next = end + 1;
+	return 0;
+}
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index 0b2877000..d2774a3ad 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -205,4 +205,38 @@ struct rte_bus *rte_bus_find_by_device_name(const char *str);
 
 int rte_mp_channel_init(void);
 
+/*
+ * Lightweight kvarg parsing library.
+ */
+
+#define RTE_MAX_KVARG_LEN 64
+
+/**
+ * Kvarg representation.
+ */
+struct rte_kvarg {
+	char *key; /**< points the key in the data. */
+	char *value; /**< points the value in the data. */
+	const char *next; /**< next token to parse, if any. */
+	char data[RTE_MAX_KVARG_LEN + 1]; /**< local copy of key and value. */
+};
+
+/**
+ * Parse one kvarg.
+ *
+ * The key-value pair must be shorter than the rte_kvarg data size.
+ *
+ * @param[in] str
+ *   text to parse.
+ *
+ * @param[out] kv
+ *   kvarg structure to fill.
+ *
+ * @return
+ *   0 if parsing succeeded.
+ *   >0 if there was nothing to parse.
+ *   <0 on error, rte_errno is set.
+ */
+int rte_parse_kv(const char *str, struct rte_kvarg *kv);
+
 #endif /* _EAL_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 05/18] eal/dev: add device iterator interface
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (3 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 06/18] eal/class: add device iteration Gaetan Rivet
                     ` (14 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index b688f1efd..937ff6079 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -263,6 +263,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 06/18] eal/class: add device iteration
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (4 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 05/18] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 07/18] eal/bus: " Gaetan Rivet
                     ` (13 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index a2e5f5551..47ebaba31 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 07/18] eal/bus: add device iteration
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (5 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 06/18] eal/class: add device iteration Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 08/18] eal/dev: implement device iteration initialization Gaetan Rivet
                     ` (12 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 6fb08341a..46911afa7 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 08/18] eal/dev: implement device iteration initialization
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (6 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 07/18] eal/bus: " Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 09/18] eal/dev: implement device iteration Gaetan Rivet
                     ` (11 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Parse a device description.

Split this description in their relevant part for both abstraction
layer.

No dynamic allocation is performed.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 58 +++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h | 23 +++++++++++++
 lib/librte_eal/rte_eal_version.map      |  1 +
 3 files changed, 82 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 4032f1bd8..bdab1423a 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -10,6 +10,7 @@
 
 #include <rte_compat.h>
 #include <rte_bus.h>
+#include <rte_class.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
 #include <rte_debug.h>
@@ -245,3 +246,60 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)
 	rte_eal_devargs_remove(busname, devname);
 	return ret;
 }
+
+int __rte_experimental
+rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
+{
+	struct rte_bus *bus = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_kvarg kv;
+
+	/* Having both busstr and clsstr NULL is illegal,
+	 * marking this iterator as invalid unless
+	 * everything goes well.
+	 */
+	it->busstr = NULL;
+	it->clsstr = NULL;
+	/* Safety checks and prep-work */
+	if (rte_parse_kv(str, &kv)) {
+		RTE_LOG(ERR, EAL, "Could not parse: %s\n", str);
+		return -1;
+	}
+	it->device = NULL;
+	it->class_device = NULL;
+	if (strcmp(kv.key, "bus") == 0) {
+		char *slash;
+
+		bus = rte_bus_find_by_name(kv.value);
+		it->busstr = str;
+		slash = strchr(str, '/');
+		if (slash != NULL) {
+			if (rte_parse_kv(slash + 1, &kv))
+				return -1;
+			cls = rte_class_find_by_name(kv.value);
+			it->clsstr = slash + 1;
+		}
+	} else if (strcmp(kv.key, "class") == 0) {
+		cls = rte_class_find_by_name(kv.value);
+		it->clsstr = str;
+	} else {
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+	/* The string should have at least
+	 * one layer specified.
+	 */
+	if (bus == NULL && cls == NULL) {
+		rte_errno = EINVAL;
+		return -rte_errno;
+	}
+	if ((bus != NULL && bus->dev_iterate == NULL) ||
+	    (cls != NULL && cls->dev_iterate == NULL)) {
+		rte_errno = ENOTSUP;
+		return -rte_errno;
+	}
+	it->devstr = str;
+	it->bus = bus;
+	it->cls = cls;
+	return 0;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 937ff6079..7ce13e068 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -310,6 +310,29 @@ 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.
+ */
+int __rte_experimental
+rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 910cb23c9..921da3075 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -228,6 +228,7 @@ EXPERIMENTAL {
 	rte_mp_sendmsg;
 	rte_mp_request;
 	rte_mp_reply;
+	rte_dev_iterator_init;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 09/18] eal/dev: implement device iteration
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (7 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 08/18] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 10/18] bus/pci: fix find device implementation Gaetan Rivet
                     ` (10 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 159 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  25 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 185 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index bdab1423a..4efc27462 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -19,6 +19,28 @@
 
 #include "eal_private.h"
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	((struct dev_next_ctx *)(intptr_t)ptr)->it
+
+#define BUSCTX(ptr) \
+	((struct dev_next_ctx *)(intptr_t)ptr)->busstr
+
+#define CLSCTX(ptr) \
+	((struct dev_next_ctx *)(intptr_t)ptr)->clsstr
+
 /* EAL-private function. */
 int
 rte_parse_kv(const char *str, struct rte_kvarg *kv)
@@ -303,3 +325,140 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
 	it->cls = cls;
 	return 0;
 }
+
+static char *
+dev_str_sane_cpy(const char *str)
+{
+	struct rte_kvarg kv;
+	char *end;
+	char *cpy;
+
+	if (rte_parse_kv(str, &kv)) {
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	/* copying '\0' is valid. */
+	if (kv.next != NULL)
+		cpy = strdup(kv.next);
+	else
+		cpy = strdup("");
+	if (cpy == NULL) {
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+	end = strchr(cpy, '/');
+	if (end != NULL)
+		end[0] = '\0';
+	return cpy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_cpy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_cpy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 7ce13e068..dfb5d696f 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -333,6 +333,31 @@ typedef void *(*rte_dev_iterate_t)(const void *start,
 int __rte_experimental
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+struct rte_device * __rte_experimental
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 921da3075..925efcb6d 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	rte_mp_request;
 	rte_mp_reply;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 10/18] bus/pci: fix find device implementation
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (8 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 09/18] eal/dev: implement device iteration Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 11/18] bus/pci: implement device iteration and comparison Gaetan Rivet
                     ` (9 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set, and a device before it matches the data
passed for comparison, then this first device is returned.

This produces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2a00f365a..2c45f8151 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -459,17 +459,20 @@ static struct rte_device *
 pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		const void *data)
 {
-	struct rte_pci_device *dev;
+	const struct rte_pci_device *pstart;
+	struct rte_pci_device *pdev;
 
-	FOREACH_DEVICE_ON_PCIBUS(dev) {
-		if (start && &dev->device == start) {
-			start = NULL; /* starting point found */
-			continue;
-		}
-		if (cmp(&dev->device, data) == 0)
-			return &dev->device;
+	if (start != NULL) {
+		pstart = RTE_DEV_TO_PCI_CONST(start);
+		pdev = TAILQ_NEXT(pstart, next);
+	} else {
+		pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
+	}
+	while (pdev != NULL) {
+		if (cmp(&pdev->device, data) == 0)
+			return &pdev->device;
+		pdev = TAILQ_NEXT(pdev, next);
 	}
-
 	return NULL;
 }
 
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 357afb912..458e6d076 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -74,6 +74,9 @@ struct rte_pci_device {
  */
 #define RTE_DEV_TO_PCI(ptr) container_of(ptr, struct rte_pci_device, device)
 
+#define RTE_DEV_TO_PCI_CONST(ptr) \
+	container_of(ptr, const struct rte_pci_device, device)
+
 #define RTE_ETH_DEV_TO_PCI(eth_dev)	RTE_DEV_TO_PCI((eth_dev)->device)
 
 /** Any PCI device identifier (vendor, device, ...) */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 11/18] bus/pci: implement device iteration and comparison
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (9 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 10/18] bus/pci: fix find device implementation Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 12/18] bus/pci: add device matching field id Gaetan Rivet
                     ` (8 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index f3df1c4ce..73498dc77 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -50,7 +50,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
 CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2c45f8151..59a776305 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -13,6 +13,7 @@
 
 #include <rte_errno.h>
 #include <rte_interrupts.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
@@ -497,6 +498,38 @@ pci_unplug(struct rte_device *dev)
 	return ret;
 }
 
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+static void *
+pci_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_device *dev;
+	struct rte_kvargs *kvargs = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = pci_find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 struct rte_pci_bus rte_pci_bus = {
 	.bus = {
 		.scan = rte_pci_scan,
@@ -506,6 +539,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 12/18] bus/pci: add device matching field id
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (10 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 11/18] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 13/18] bus/vdev: fix find device implementation Gaetan Rivet
                     ` (7 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 59a776305..af5b48287 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -499,13 +499,35 @@ pci_unplug(struct rte_device *dev)
 }
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return rte_pci_addr_cmp(addr1, addr2);
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 13/18] bus/vdev: fix find device implementation
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (11 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 12/18] bus/pci: add device matching field id Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 14/18] bus/vdev: implement device iteration Gaetan Rivet
                     ` (6 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set and a device before it matches the data,
this device is returned.

This produces induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/vdev/rte_bus_vdev.h b/drivers/bus/vdev/rte_bus_vdev.h
index f9d8a2383..4da9967c6 100644
--- a/drivers/bus/vdev/rte_bus_vdev.h
+++ b/drivers/bus/vdev/rte_bus_vdev.h
@@ -53,6 +53,9 @@ struct rte_vdev_device {
 #define RTE_DEV_TO_VDEV(ptr) \
 	container_of(ptr, struct rte_vdev_device, device)
 
+#define RTE_DEV_TO_VDEV_CONST(ptr) \
+	container_of(ptr, const struct rte_vdev_device, device)
+
 static inline const char *
 rte_vdev_device_name(const struct rte_vdev_device *dev)
 {
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index e4bc72463..68306f4eb 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -386,15 +386,19 @@ static struct rte_device *
 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		 const void *data)
 {
+	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
 
-	TAILQ_FOREACH(dev, &vdev_device_list, next) {
-		if (start && &dev->device == start) {
-			start = NULL;
-			continue;
-		}
+	if (start != NULL) {
+		vstart = RTE_DEV_TO_VDEV_CONST(start);
+		dev = TAILQ_NEXT(vstart, next);
+	} else {
+		dev = TAILQ_FIRST(&vdev_device_list);
+	}
+	while (dev != NULL) {
 		if (cmp(&dev->device, data) == 0)
 			return &dev->device;
+		dev = TAILQ_NEXT(dev, next);
 	}
 	return NULL;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 14/18] bus/vdev: implement device iteration
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (12 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 13/18] bus/vdev: fix find device implementation Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 15/18] bus/vdev: add device matching field driver Gaetan Rivet
                     ` (5 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 24d424a38..52728833c 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 68306f4eb..699ce01e6 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -43,6 +43,7 @@
 #include <rte_bus.h>
 #include <rte_common.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
 #include <rte_memory.h>
 #include <rte_tailq.h>
 #include <rte_spinlock.h>
@@ -415,6 +416,38 @@ vdev_unplug(struct rte_device *dev)
 	return rte_vdev_uninit(dev->name);
 }
 
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+static void *
+vdev_dev_iterate(const void *start,
+		 const char *str,
+		 const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
@@ -422,6 +455,7 @@ static struct rte_bus rte_vdev_bus = {
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 15/18] bus/vdev: add device matching field driver
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (13 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 14/18] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 16/18] ethdev: register ether layer as a class Gaetan Rivet
                     ` (4 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 699ce01e6..d1e712fe9 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -417,13 +417,31 @@ vdev_unplug(struct rte_device *dev)
 }
 
 static int
+vdev_str_kv_cmp(const char *key __rte_unused,
+	     const char *value,
+	     void *_str)
+{
+	const  char *str = _str;
+
+	return strcmp(str, value);
+}
+
+static int
 vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		&vdev_str_kv_cmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 16/18] ethdev: register ether layer as a class
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (14 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 15/18] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 17/18] ethdev: add device matching field name Gaetan Rivet
                     ` (3 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                     |  2 +-
 lib/librte_ether/Makefile        |  3 +-
 lib/librte_ether/rte_class_eth.c | 65 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_ether/rte_class_eth.c

diff --git a/lib/Makefile b/lib/Makefile
index ec965a606..6bb6a8bed 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -20,7 +20,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf
+DEPDIRS-librte_ether += librte_mbuf librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 3ca5782bb..a1a0393de 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 8
 
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
new file mode 100644
index 000000000..3f1537c2a
--- /dev/null
+++ b/lib/librte_ether/rte_class_eth.c
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+
+static int
+eth_dev_match(struct rte_eth_dev *edev,
+	      struct rte_kvargs *kvlist)
+{
+	(void) kvlist;
+	(void) edev;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *_start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	const struct rte_eth_dev *start = _start;
+	struct rte_device *dev = it->device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+	uint16_t p = 0;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	if (start)
+		p = start->data->port_id + 1;
+	for (p = rte_eth_find_next(p);
+	     p < RTE_MAX_ETHPORTS;
+	     p = rte_eth_find_next(p + 1)) {
+		edev = &rte_eth_devices[p];
+		if (dev != edev->device)
+			goto next_ethdev;
+		if (eth_dev_match(edev, kvargs) == 0)
+			break;
+next_ethdev:
+		edev = NULL;
+	}
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 17/18] ethdev: add device matching field name
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (15 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 16/18] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 18/18] app/testpmd: add show device command Gaetan Rivet
                     ` (2 subsequent siblings)
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/rte_class_eth.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
index 3f1537c2a..08f2b43cb 100644
--- a/lib/librte_ether/rte_class_eth.c
+++ b/lib/librte_ether/rte_class_eth.c
@@ -14,11 +14,25 @@
 #include "rte_ethdev_core.h"
 
 static int
+eth_dev_str_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_str)
+{
+	const char *str = _str;
+
+	return strcmp(str, value);
+}
+
+static int
 eth_dev_match(struct rte_eth_dev *edev,
 	      struct rte_kvargs *kvlist)
 {
-	(void) kvlist;
-	(void) edev;
+	struct rte_eth_dev_data *data;
+
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			&eth_dev_str_cmp, data->name))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v2 18/18] app/testpmd: add show device command
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (16 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 17/18] ethdev: add device matching field name Gaetan Rivet
@ 2018-03-21 17:15   ` Gaetan Rivet
  2018-03-22 11:31   ` [dpdk-dev] [PATCH v2 00/18] Device querying Bruce Richardson
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
  19 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-21 17:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..8ac5fb3ca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device "
+		"<device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility Gaetan Rivet
@ 2018-03-21 17:32     ` Wiles, Keith
  2018-03-21 17:58       ` Gaëtan Rivet
  2018-03-22 14:10       ` Neil Horman
  0 siblings, 2 replies; 364+ messages in thread
From: Wiles, Keith @ 2018-03-21 17:32 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev



> On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> 
> This library offers a quick way to parse parameters passed with a
> key=value syntax.
> 
> A single function is needed and finds the relevant element within the
> text. No dynamic allocation is performed. It is possible to chain the
> parsing of each pairs for quickly scanning a list.
> 
> This utility is private to the EAL and should allow avoiding having to
> move around the more complete librte_kvargs.

What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?

My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)

> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

Regards,
Keith

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-21 17:32     ` Wiles, Keith
@ 2018-03-21 17:58       ` Gaëtan Rivet
  2018-03-22 14:10       ` Neil Horman
  1 sibling, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-21 17:58 UTC (permalink / raw)
  To: Wiles, Keith; +Cc: dev

Hello Keith,

On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> 
> 
> > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > 
> > This library offers a quick way to parse parameters passed with a
> > key=value syntax.
> > 
> > A single function is needed and finds the relevant element within the
> > text. No dynamic allocation is performed. It is possible to chain the
> > parsing of each pairs for quickly scanning a list.
> > 
> > This utility is private to the EAL and should allow avoiding having to
> > move around the more complete librte_kvargs.
> 
> What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> 

Pretty much, yes. I needed something lean and simple.

> My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> 

I hear you. I decided this was worth the trade-off.

librte_kvargs does the iteration on a kvlist in one-line.
It processes the input text and mangle as needed to be able to do so.
Drivers using it will be able to declare first a set of acceptable keys,
meaning that it is complementary to having a usage-help and more stringent
input validation.

rte_kvargs does none of it. This means that each user would have to
re-implement checks by hand, and reviewers would need to enforce that
they are done, etc.

So, IMO, different use-cases. In this context, I think making the effort
of moving around librte_kvargs within the EAL, tweaking its use for my
needs, does not make much sense. It would complicate its
implementation only for one less private function.

If people do not like using librte_kvargs, it could maybe evolve, be
rewritten, then all drivers would need to follow suit, etc. But I
haven't seen the need personally.

Regards,
-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 00/18] Device querying
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (17 preceding siblings ...)
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 18/18] app/testpmd: add show device command Gaetan Rivet
@ 2018-03-22 11:31   ` Bruce Richardson
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
  19 siblings, 0 replies; 364+ messages in thread
From: Bruce Richardson @ 2018-03-22 11:31 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Wed, Mar 21, 2018 at 06:15:21PM +0100, Gaetan Rivet wrote:
> This patchset introduces a new EAL API for querying devices,
> filtered by arbitrary properties.
> 
> The following elements are introduced to this end:
> 
>  * A new object, "rte_class", is used to describe
>    the device class abstraction layer (eth, crypto, ...).
> 
>  * Both rte_bus and rte_class now offer a way to
>    list their devices and filter the result
>    using locally defined properties.
> 
>  * The rte_dev API now has an rte_dev_iterator, which
>    is the way for the user to define the device filter
>    and iterate upon the resulting set.
> 
> As an example, the "eth" device class is implemented.
> 
> Additionally, the device filters for
> 
>   + rte_bus_pci
>   + rte_bus_vdev
>   + rte_class_eth
> 
> are implemented and can be used with some
> properties each, to show how to extend those.
> 
> Some example of filters:
> 
>   "bus=pci/class=eth"
>   "bus=pci"
>   "class=eth"
>   "class=eth,name=net_ring0"
>   "bus=pci,id=00:00.0"
>   "bus=vdev,driver=net_ring"
> 
> ---
> 
> v2:
> 
>   * Reworked the dev_iterate callback to simplify
>     its implementation.
> 
>     Now dev_iterate implementation do not need to learn
>     about the intricacies of the rte_dev_iterator.
>     The rte_dev_iterator is managed purely by the
>     rte_dev_iterator_next function. Buses and classes then
>     do not have to care about settings things right.
> 
>     Additionally, dev_iterate implementations do not
>     have to sanitize their dev string anymore, they
>     are prepared by the rte_dev layer prior, which also
>     reduces the number of dynamic allocations.
> 
> Gaetan Rivet (18):
>   eal: introduce dtor macros
>   eal: introduce device class abstraction
>   eal/class: register destructor
>   eal: add lightweight kvarg parsing utility
>   eal/dev: add device iterator interface
>   eal/class: add device iteration
>   eal/bus: add device iteration
>   eal/dev: implement device iteration initialization
>   eal/dev: implement device iteration
>   bus/pci: fix find device implementation
>   bus/pci: implement device iteration and comparison
>   bus/pci: add device matching field id
>   bus/vdev: fix find device implementation
>   bus/vdev: implement device iteration
>   bus/vdev: add device matching field driver
>   ethdev: register ether layer as a class
>   ethdev: add device matching field name
>   app/testpmd: add show device command
> 
>  app/test-pmd/cmdline.c                     |  52 ++++++
>  drivers/bus/pci/Makefile                   |   2 +-
>  drivers/bus/pci/pci_common.c               |  77 ++++++++-
>  drivers/bus/pci/rte_bus_pci.h              |   3 +
>  drivers/bus/vdev/Makefile                  |   2 +-
>  drivers/bus/vdev/rte_bus_vdev.h            |   3 +
>  drivers/bus/vdev/vdev.c                    |  66 +++++++-
>  lib/Makefile                               |   2 +-
>  lib/librte_eal/bsdapp/eal/Makefile         |   1 +
>  lib/librte_eal/common/Makefile             |   2 +-
>  lib/librte_eal/common/eal_common_class.c   |  62 +++++++
>  lib/librte_eal/common/eal_common_dev.c     | 255 +++++++++++++++++++++++++++++
>  lib/librte_eal/common/eal_private.h        |  34 ++++
>  lib/librte_eal/common/include/rte_bus.h    |   1 +
>  lib/librte_eal/common/include/rte_class.h  | 127 ++++++++++++++
>  lib/librte_eal/common/include/rte_common.h |  23 +++
>  lib/librte_eal/common/include/rte_dev.h    |  95 +++++++++++
>  lib/librte_eal/linuxapp/eal/Makefile       |   1 +
>  lib/librte_eal/rte_eal_version.map         |   4 +
>  lib/librte_ether/Makefile                  |   3 +-
>  lib/librte_ether/rte_class_eth.c           |  79 +++++++++
>  21 files changed, 875 insertions(+), 19 deletions(-)
>  create mode 100644 lib/librte_eal/common/eal_common_class.c
>  create mode 100644 lib/librte_eal/common/include/rte_class.h
>  create mode 100644 lib/librte_ether/rte_class_eth.c
>

Not seeing any meson.build files in the list above, but plenty of
makefiles. :-)

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Gaetan Rivet
@ 2018-03-22 11:35     ` Neil Horman
  2018-03-22 13:51     ` Neil Horman
  1 sibling, 0 replies; 364+ messages in thread
From: Neil Horman @ 2018-03-22 11:35 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Wed, Mar 21, 2018 at 06:15:22PM +0100, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> index c7803e41c..500fc3adb 100644
> --- a/lib/librte_eal/common/include/rte_common.h
> +++ b/lib/librte_eal/common/include/rte_common.h
> @@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)
>  static void __attribute__((constructor(prio), used)) func(void)
>  
>  /**
> + * Run after main() with high priority.
> + *
> + * The destructor will be run *before* prioritized destructors.
> + *
> + * @param func
> + *   Destructor function name.
> + */
> +#define RTE_FINI(func) \
> +static void __attribute__((destructor, used)) func(void)
> +
> +/**
> + * Run after main() with low priority.
> + *
> + * @param func
> + *   Destructor function name.
> + * @param prio
> + *   Priority number must be above 100.
> + *   Lowest number is the last to run.
> + */
> +#define RTE_FINI_PRIO(func, prio) \
> +static void __attribute__((destructor(prio), used)) func(void)
> +
> +/**
If you need to require that priority be above 100, you probably want to create a
BUILD_BUG type macro to enforce that.

Neil

>   * Force a function to be inlined
>   */
>  #define __rte_always_inline inline __attribute__((always_inline))
> -- 
> 2.11.0
> 
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros
  2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Gaetan Rivet
  2018-03-22 11:35     ` Neil Horman
@ 2018-03-22 13:51     ` Neil Horman
  2018-03-22 15:56       ` Gaëtan Rivet
  1 sibling, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-22 13:51 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Wed, Mar 21, 2018 at 06:15:22PM +0100, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
>  1 file changed, 23 insertions(+)
> 
> diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> index c7803e41c..500fc3adb 100644
> --- a/lib/librte_eal/common/include/rte_common.h
> +++ b/lib/librte_eal/common/include/rte_common.h
> @@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)
>  static void __attribute__((constructor(prio), used)) func(void)
>  
>  /**
> + * Run after main() with high priority.
> + *
> + * The destructor will be run *before* prioritized destructors.
> + *
> + * @param func
> + *   Destructor function name.
> + */
> +#define RTE_FINI(func) \
> +static void __attribute__((destructor, used)) func(void)
> +
> +/**
> + * Run after main() with low priority.
> + *
> + * @param func
> + *   Destructor function name.
> + * @param prio
> + *   Priority number must be above 100.
> + *   Lowest number is the last to run.
> + */
> +#define RTE_FINI_PRIO(func, prio) \
> +static void __attribute__((destructor(prio), used)) func(void)
> +
> +/**
Additionally, it might be nice to further abstract the destructor priority to
fixed levels so that people aren't always trying to guess what the right magic
number should be.  I.e. create several destructor macros of the form:
RTE_FINI_<NAME>

Where name is a meaningfull term like FINAL, PMD, EARLY, or some such set that
implies a priority value encoded within the macro definition.  That would also
eliminate the need to create a BUILD BUG macro if the priority was specified to
be too low

Neil

>   * Force a function to be inlined
>   */
>  #define __rte_always_inline inline __attribute__((always_inline))
> -- 
> 2.11.0
> 
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-21 17:32     ` Wiles, Keith
  2018-03-21 17:58       ` Gaëtan Rivet
@ 2018-03-22 14:10       ` Neil Horman
  2018-03-22 16:27         ` Gaëtan Rivet
  1 sibling, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-22 14:10 UTC (permalink / raw)
  To: Wiles, Keith; +Cc: Gaetan Rivet, dev

On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> 
> 
> > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > 
> > This library offers a quick way to parse parameters passed with a
> > key=value syntax.
> > 
> > A single function is needed and finds the relevant element within the
> > text. No dynamic allocation is performed. It is possible to chain the
> > parsing of each pairs for quickly scanning a list.
> > 
> > This utility is private to the EAL and should allow avoiding having to
> > move around the more complete librte_kvargs.
> 
> What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> 
> My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> 
+1, this really doesn't make much sense to me.  Two parsing routines seems like
its just asking for us to have to fix parsing bugs in two places.  If allocation
is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
of kvargs that can be shared from init time.  librte_kvargs isn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go
re-inventing the wheel.

Neil

> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> 
> Regards,
> Keith
> 
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros
  2018-03-22 13:51     ` Neil Horman
@ 2018-03-22 15:56       ` Gaëtan Rivet
  2018-03-22 15:58         ` [dpdk-dev] [PATCH] eal: list acceptable init priorities Gaetan Rivet
  2018-03-23  0:38         ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Neil Horman
  0 siblings, 2 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-22 15:56 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev

On Thu, Mar 22, 2018 at 09:51:14AM -0400, Neil Horman wrote:
> On Wed, Mar 21, 2018 at 06:15:22PM +0100, Gaetan Rivet wrote:
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >  lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
> >  1 file changed, 23 insertions(+)
> > 
> > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > index c7803e41c..500fc3adb 100644
> > --- a/lib/librte_eal/common/include/rte_common.h
> > +++ b/lib/librte_eal/common/include/rte_common.h
> > @@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)
> >  static void __attribute__((constructor(prio), used)) func(void)
> >  
> >  /**
> > + * Run after main() with high priority.
> > + *
> > + * The destructor will be run *before* prioritized destructors.
> > + *
> > + * @param func
> > + *   Destructor function name.
> > + */
> > +#define RTE_FINI(func) \
> > +static void __attribute__((destructor, used)) func(void)
> > +
> > +/**
> > + * Run after main() with low priority.
> > + *
> > + * @param func
> > + *   Destructor function name.
> > + * @param prio
> > + *   Priority number must be above 100.
> > + *   Lowest number is the last to run.
> > + */
> > +#define RTE_FINI_PRIO(func, prio) \
> > +static void __attribute__((destructor(prio), used)) func(void)
> > +
> > +/**
> Additionally, it might be nice to further abstract the destructor priority to
> fixed levels so that people aren't always trying to guess what the right magic
> number should be.  I.e. create several destructor macros of the form:
> RTE_FINI_<NAME>
> 
> Where name is a meaningfull term like FINAL, PMD, EARLY, or some such set that
> implies a priority value encoded within the macro definition.  That would also
> eliminate the need to create a BUILD BUG macro if the priority was specified to
> be too low
> 
> Neil
> 

Good idea, and I agree that we need helpers on this.
Not sure about _FINAL and _EARLY however.

I will propose a patch as a response to this mail, let me know if that's
what you had in mind.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH] eal: list acceptable init priorities
  2018-03-22 15:56       ` Gaëtan Rivet
@ 2018-03-22 15:58         ` Gaetan Rivet
  2018-03-23  0:40           ` Neil Horman
  2018-03-23  0:38         ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Neil Horman
  1 sibling, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-22 15:58 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman

Build a central list to quickly see each used priorities for
constructors, allowing to verify that they are both above 100 and in the
proper order.

Cc: Neil Horman <nhorman@tuxdriver.com>
Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_log.c     | 2 +-
 lib/librte_eal/common/include/rte_bus.h    | 2 +-
 lib/librte_eal/common/include/rte_common.h | 8 +++++++-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index 37b2e20e5..b384c72d3 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = {
 };
 
 /* Logging should be first initializer (before drivers and bus) */
-RTE_INIT_PRIO(rte_log_init, 101);
+RTE_INIT_PRIO(rte_log_init, LOG);
 static void
 rte_log_init(void)
 {
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 46911afa7..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -326,7 +326,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
  * The constructor has higher priority than PMD constructors.
  */
 #define RTE_REGISTER_BUS(nm, bus) \
-RTE_INIT_PRIO(businitfn_ ##nm, 110); \
+RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
 static void businitfn_ ##nm(void) \
 {\
 	(bus).name = RTE_STR(nm);\
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 500fc3adb..5ff0de08f 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
  */
 #define RTE_SET_USED(x) (void)(x)
 
+#define RTE_PRIORITY_LOG 101
+#define RTE_PRIORITY_BUS 110
+
+#define RTE_PRIO(prio) \
+	RTE_PRIORITY_ ## prio
+
 /**
  * Run function before main() with low priority.
  *
@@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
  *   Lowest number is the first to run.
  */
 #define RTE_INIT_PRIO(func, prio) \
-static void __attribute__((constructor(prio), used)) func(void)
+static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
  * Run after main() with high priority.
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-22 14:10       ` Neil Horman
@ 2018-03-22 16:27         ` Gaëtan Rivet
  2018-03-23  0:53           ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-22 16:27 UTC (permalink / raw)
  To: Neil Horman; +Cc: Wiles, Keith, dev

On Thu, Mar 22, 2018 at 10:10:37AM -0400, Neil Horman wrote:
> On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> > 
> > 
> > > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > > 
> > > This library offers a quick way to parse parameters passed with a
> > > key=value syntax.
> > > 
> > > A single function is needed and finds the relevant element within the
> > > text. No dynamic allocation is performed. It is possible to chain the
> > > parsing of each pairs for quickly scanning a list.
> > > 
> > > This utility is private to the EAL and should allow avoiding having to
> > > move around the more complete librte_kvargs.
> > 
> > What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> > 
> > My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> > 
> +1, this really doesn't make much sense to me.  Two parsing routines seems like
> its just asking for us to have to fix parsing bugs in two places.  If allocation
> is a concern, I don't see why you can't just change the malloc in
> rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
> of kvargs that can be shared from init time.

I think the existing allocation scheme is fine for other usages (in
drivers and so on). Not for what I wanted to do.

>                                               librte_kvargs isn't necessecarily
> the best parsing library ever, but its not bad, and it just seems wrong to go
> re-inventing the wheel.
> 

It serves a different purpose than the one I'm pursuing.

This helper is lightweight and private. If I wanted to integrate my
needs with librte_kvargs, I would be adding new functionalities, making
it more complex, and for a use-case that is useless for the vast
majority of users of the lib.

If that's really an issue, I'm better off simply removing rte_parse_kv
and writing the parsing by hand within my function. This would be ugly
and tedious, but less than moving librte_kvargs within EAL and changing
it to my needs.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros
  2018-03-22 15:56       ` Gaëtan Rivet
  2018-03-22 15:58         ` [dpdk-dev] [PATCH] eal: list acceptable init priorities Gaetan Rivet
@ 2018-03-23  0:38         ` Neil Horman
  1 sibling, 0 replies; 364+ messages in thread
From: Neil Horman @ 2018-03-23  0:38 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev

On Thu, Mar 22, 2018 at 04:56:43PM +0100, Gaëtan Rivet wrote:
> On Thu, Mar 22, 2018 at 09:51:14AM -0400, Neil Horman wrote:
> > On Wed, Mar 21, 2018 at 06:15:22PM +0100, Gaetan Rivet wrote:
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > ---
> > >  lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
> > >  1 file changed, 23 insertions(+)
> > > 
> > > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > > index c7803e41c..500fc3adb 100644
> > > --- a/lib/librte_eal/common/include/rte_common.h
> > > +++ b/lib/librte_eal/common/include/rte_common.h
> > > @@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)
> > >  static void __attribute__((constructor(prio), used)) func(void)
> > >  
> > >  /**
> > > + * Run after main() with high priority.
> > > + *
> > > + * The destructor will be run *before* prioritized destructors.
> > > + *
> > > + * @param func
> > > + *   Destructor function name.
> > > + */
> > > +#define RTE_FINI(func) \
> > > +static void __attribute__((destructor, used)) func(void)
> > > +
> > > +/**
> > > + * Run after main() with low priority.
> > > + *
> > > + * @param func
> > > + *   Destructor function name.
> > > + * @param prio
> > > + *   Priority number must be above 100.
> > > + *   Lowest number is the last to run.
> > > + */
> > > +#define RTE_FINI_PRIO(func, prio) \
> > > +static void __attribute__((destructor(prio), used)) func(void)
> > > +
> > > +/**
> > Additionally, it might be nice to further abstract the destructor priority to
> > fixed levels so that people aren't always trying to guess what the right magic
> > number should be.  I.e. create several destructor macros of the form:
> > RTE_FINI_<NAME>
> > 
> > Where name is a meaningfull term like FINAL, PMD, EARLY, or some such set that
> > implies a priority value encoded within the macro definition.  That would also
> > eliminate the need to create a BUILD BUG macro if the priority was specified to
> > be too low
> > 
> > Neil
> > 
> 
> Good idea, and I agree that we need helpers on this.
> Not sure about _FINAL and _EARLY however.
> 
Yeah, I don't like those either, but I couldn't think of any other priority
suffixes off the top of my head

FWIW, the kernel creates these macros to register initcalls:
#define pure_initcall(fn)               __define_initcall(fn, 0)
#define core_initcall(fn)               __define_initcall(fn, 1)
#define core_initcall_sync(fn)          __define_initcall(fn, 1s)
#define postcore_initcall(fn)           __define_initcall(fn, 2)
#define postcore_initcall_sync(fn)      __define_initcall(fn, 2s)
#define arch_initcall(fn)               __define_initcall(fn, 3)
#define arch_initcall_sync(fn)          __define_initcall(fn, 3s)
#define subsys_initcall(fn)             __define_initcall(fn, 4)
#define subsys_initcall_sync(fn)        __define_initcall(fn, 4s)
#define fs_initcall(fn)                 __define_initcall(fn, 5)
#define fs_initcall_sync(fn)            __define_initcall(fn, 5s)
#define rootfs_initcall(fn)             __define_initcall(fn, rootfs)
#define device_initcall(fn)             __define_initcall(fn, 6)
#define device_initcall_sync(fn)        __define_initcall(fn, 6s)
#define late_initcall(fn)               __define_initcall(fn, 7)
#define late_initcall_sync(fn)          __define_initcall(fn, 7s)

Its not an exact match, but you could probably borrow from that somewhat.

> I will propose a patch as a response to this mail, let me know if that's
> what you had in mind.
That was my hope yes, thanks!
Neil

> 
> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH] eal: list acceptable init priorities
  2018-03-22 15:58         ` [dpdk-dev] [PATCH] eal: list acceptable init priorities Gaetan Rivet
@ 2018-03-23  0:40           ` Neil Horman
  0 siblings, 0 replies; 364+ messages in thread
From: Neil Horman @ 2018-03-23  0:40 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Thu, Mar 22, 2018 at 04:58:24PM +0100, Gaetan Rivet wrote:
> Build a central list to quickly see each used priorities for
> constructors, allowing to verify that they are both above 100 and in the
> proper order.
> 
> Cc: Neil Horman <nhorman@tuxdriver.com>
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/librte_eal/common/eal_common_log.c     | 2 +-
>  lib/librte_eal/common/include/rte_bus.h    | 2 +-
>  lib/librte_eal/common/include/rte_common.h | 8 +++++++-
>  3 files changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> index 37b2e20e5..b384c72d3 100644
> --- a/lib/librte_eal/common/eal_common_log.c
> +++ b/lib/librte_eal/common/eal_common_log.c
> @@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = {
>  };
>  
>  /* Logging should be first initializer (before drivers and bus) */
> -RTE_INIT_PRIO(rte_log_init, 101);
> +RTE_INIT_PRIO(rte_log_init, LOG);
>  static void
>  rte_log_init(void)
>  {
> diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> index 46911afa7..747baf140 100644
> --- a/lib/librte_eal/common/include/rte_bus.h
> +++ b/lib/librte_eal/common/include/rte_bus.h
> @@ -326,7 +326,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
>   * The constructor has higher priority than PMD constructors.
>   */
>  #define RTE_REGISTER_BUS(nm, bus) \
> -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
>  static void businitfn_ ##nm(void) \
>  {\
>  	(bus).name = RTE_STR(nm);\
> diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> index 500fc3adb..5ff0de08f 100644
> --- a/lib/librte_eal/common/include/rte_common.h
> +++ b/lib/librte_eal/common/include/rte_common.h
> @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
>   */
>  #define RTE_SET_USED(x) (void)(x)
>  
> +#define RTE_PRIORITY_LOG 101
> +#define RTE_PRIORITY_BUS 110
> +
> +#define RTE_PRIO(prio) \
> +	RTE_PRIORITY_ ## prio
> +
>  /**
>   * Run function before main() with low priority.
>   *
> @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
>   *   Lowest number is the first to run.
>   */
>  #define RTE_INIT_PRIO(func, prio) \
> -static void __attribute__((constructor(prio), used)) func(void)
> +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
>  
>  /**
>   * Run after main() with high priority.
> -- 
> 2.11.0
> 
> 
This seems like a good start, something that we can expand if we need more priorities later
Acked-by: Neil Horman <nhorman@tuxdriver.com>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-22 16:27         ` Gaëtan Rivet
@ 2018-03-23  0:53           ` Neil Horman
  2018-03-23  9:31             ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-23  0:53 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Wiles, Keith, dev

On Thu, Mar 22, 2018 at 05:27:51PM +0100, Gaëtan Rivet wrote:
> On Thu, Mar 22, 2018 at 10:10:37AM -0400, Neil Horman wrote:
> > On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> > > 
> > > 
> > > > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > > > 
> > > > This library offers a quick way to parse parameters passed with a
> > > > key=value syntax.
> > > > 
> > > > A single function is needed and finds the relevant element within the
> > > > text. No dynamic allocation is performed. It is possible to chain the
> > > > parsing of each pairs for quickly scanning a list.
> > > > 
> > > > This utility is private to the EAL and should allow avoiding having to
> > > > move around the more complete librte_kvargs.
> > > 
> > > What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> > > 
> > > My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> > > 
> > +1, this really doesn't make much sense to me.  Two parsing routines seems like
> > its just asking for us to have to fix parsing bugs in two places.  If allocation
> > is a concern, I don't see why you can't just change the malloc in
> > rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
> > of kvargs that can be shared from init time.
> 
> I think the existing allocation scheme is fine for other usages (in
> drivers and so on). Not for what I wanted to do.
> 
Ok, but thats an adressable issue.  you can bifurcate the parse function to an
internal function that accepts any preallocated kvargs struct, and export two
wrapper functions, one which allocates the struct from the heap, another which
allocated automatically on the stack.

> >                                               librte_kvargs isn't necessecarily
> > the best parsing library ever, but its not bad, and it just seems wrong to go
> > re-inventing the wheel.
> > 
> 
> It serves a different purpose than the one I'm pursuing.
> 
> This helper is lightweight and private. If I wanted to integrate my
> needs with librte_kvargs, I would be adding new functionalities, making
> it more complex, and for a use-case that is useless for the vast
> majority of users of the lib.
> 
Ok, to that end:

1) Privacy is not an issue (at least from my understanding of what your doing).
If we start with the assumption that librte_kvargs is capable of satisfying your
needs (even if its not done in an optimal way), the fact that your version of
the function is internal to the library doesn't seem overly relevant, unless
theres something critical to that privacy that I'm missing.

2) Lightweight function  seems like something that can be integrated with
librte_kvargs.  Looking at it, what may I ask in librte_kvargs is insufficiently
non-performant for your needs, specifically?  We talked about the heap
allocation above, is there something else? The string duplication perhaps?


> If that's really an issue, I'm better off simply removing rte_parse_kv
> and writing the parsing by hand within my function. This would be ugly
> and tedious, but less than moving librte_kvargs within EAL and changing
> it to my needs.
I don't think thats necessecary, I just think if you can ennumerate the items
that are non-performant for your needs we can make some changes to librte_kvargs
to optimize around them, or offer parsing options to avoid them, and in the
process avoid some code duplication

Neil

> 
> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-23  0:53           ` Neil Horman
@ 2018-03-23  9:31             ` Gaëtan Rivet
  2018-03-23 11:54               ` Neil Horman
  2018-03-23 13:15               ` Wiles, Keith
  0 siblings, 2 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-23  9:31 UTC (permalink / raw)
  To: Neil Horman; +Cc: Wiles, Keith, dev

On Thu, Mar 22, 2018 at 08:53:49PM -0400, Neil Horman wrote:
> On Thu, Mar 22, 2018 at 05:27:51PM +0100, Gaëtan Rivet wrote:
> > On Thu, Mar 22, 2018 at 10:10:37AM -0400, Neil Horman wrote:
> > > On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> > > > 
> > > > 
> > > > > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > > > > 
> > > > > This library offers a quick way to parse parameters passed with a
> > > > > key=value syntax.
> > > > > 
> > > > > A single function is needed and finds the relevant element within the
> > > > > text. No dynamic allocation is performed. It is possible to chain the
> > > > > parsing of each pairs for quickly scanning a list.
> > > > > 
> > > > > This utility is private to the EAL and should allow avoiding having to
> > > > > move around the more complete librte_kvargs.
> > > > 
> > > > What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> > > > 
> > > > My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> > > > 
> > > +1, this really doesn't make much sense to me.  Two parsing routines seems like
> > > its just asking for us to have to fix parsing bugs in two places.  If allocation
> > > is a concern, I don't see why you can't just change the malloc in
> > > rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
> > > of kvargs that can be shared from init time.
> > 
> > I think the existing allocation scheme is fine for other usages (in
> > drivers and so on). Not for what I wanted to do.
> > 
> Ok, but thats an adressable issue.  you can bifurcate the parse function to an
> internal function that accepts any preallocated kvargs struct, and export two
> wrapper functions, one which allocates the struct from the heap, another which
> allocated automatically on the stack.
> 

Sure, everything is possible.

> > >                                               librte_kvargs isn't necessecarily
> > > the best parsing library ever, but its not bad, and it just seems wrong to go
> > > re-inventing the wheel.
> > > 
> > 
> > It serves a different purpose than the one I'm pursuing.
> > 
> > This helper is lightweight and private. If I wanted to integrate my
> > needs with librte_kvargs, I would be adding new functionalities, making
> > it more complex, and for a use-case that is useless for the vast
> > majority of users of the lib.
> > 
> Ok, to that end:
> 
> 1) Privacy is not an issue (at least from my understanding of what your doing).
> If we start with the assumption that librte_kvargs is capable of satisfying your
> needs (even if its not done in an optimal way), the fact that your version of
> the function is internal to the library doesn't seem overly relevant, unless
> theres something critical to that privacy that I'm missing.
> 

Privacy is only a point I brought up to say that the impact of this
function is minimal. People looking to parse their kvargs should not
have any ambiguity regarding how they should do so. Only librte_kvargs
is available.

> 2) Lightweight function  seems like something that can be integrated with
> librte_kvargs.  Looking at it, what may I ask in librte_kvargs is insufficiently
> non-performant for your needs, specifically?  We talked about the heap
> allocation above, is there something else? The string duplication perhaps?
> 
> 

Mostly the way to use it.
The filter strings are
bus=value,.../class=value,...

where either bus= list or class= list can be omitted, but at least one
must appear.

I want to read a single kvarg. I do not want to parse the whole string.
the '/' signifies the end of the current layer.

librte_kvargs does not care about those points. I cannot ask it to only
read either bus or class, as it would then throw an error for all the
other keys (which the EAL has necessarily no knowledge of).

So I would need to:

  * Add a custom storage scheme
  * Add a custom parsing mode stopping at the first kvarg
  * Add an edge-case to ignore the '/', so as not to throw off the rest
    of the parsing (least it be considered part of the previous kvarg
    value field).

Seeing this, does adding those really specifics functionality help
librte_kvargs to be more useful and usable? I do not think so.

It would only serve to disrupt the library for a marginal use-case, with
the introduction of edge-cases that will blur the specs of the lib's
API, making it harder to avoid subtle bugs.

Only way to do so sanely would be to add rte_parse_kv as part of
librte_kvargs, as is. But then the whole thing does not make sense IMO:
no one would care to use it, the maintainance effort is the same, the
likelyhood of bugs as well (but in the process we would disrupt the
distribution of librte_kvargs by moving it within the EAL).

I see no benefit to either solution.

> > If that's really an issue, I'm better off simply removing rte_parse_kv
> > and writing the parsing by hand within my function. This would be ugly
> > and tedious, but less than moving librte_kvargs within EAL and changing
> > it to my needs.
> I don't think thats necessecary, I just think if you can ennumerate the items
> that are non-performant for your needs we can make some changes to librte_kvargs
> to optimize around them, or offer parsing options to avoid them, and in the
> process avoid some code duplication
> 

I think it makes sense to have specialized functions for specialized
use-cases, and forcing the code to be generic and work with all of them
will make it more complicated.

The genericity would only be worth it if people actually needed to parse
the device strings the same way I do. No one has any business doing so.
This genericity adds complexity and issues, without even being useful in
the first place.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-23  9:31             ` Gaëtan Rivet
@ 2018-03-23 11:54               ` Neil Horman
  2018-03-23 13:12                 ` Gaëtan Rivet
  2018-03-23 13:15               ` Wiles, Keith
  1 sibling, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-23 11:54 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Wiles, Keith, dev

On Fri, Mar 23, 2018 at 10:31:22AM +0100, Gaëtan Rivet wrote:
> On Thu, Mar 22, 2018 at 08:53:49PM -0400, Neil Horman wrote:
> > On Thu, Mar 22, 2018 at 05:27:51PM +0100, Gaëtan Rivet wrote:
> > > On Thu, Mar 22, 2018 at 10:10:37AM -0400, Neil Horman wrote:
> > > > On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> > > > > 
> > > > > 
> > > > > > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > > > > > 
> > > > > > This library offers a quick way to parse parameters passed with a
> > > > > > key=value syntax.
> > > > > > 
> > > > > > A single function is needed and finds the relevant element within the
> > > > > > text. No dynamic allocation is performed. It is possible to chain the
> > > > > > parsing of each pairs for quickly scanning a list.
> > > > > > 
> > > > > > This utility is private to the EAL and should allow avoiding having to
> > > > > > move around the more complete librte_kvargs.
> > > > > 
> > > > > What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> > > > > 
> > > > > My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> > > > > 
> > > > +1, this really doesn't make much sense to me.  Two parsing routines seems like
> > > > its just asking for us to have to fix parsing bugs in two places.  If allocation
> > > > is a concern, I don't see why you can't just change the malloc in
> > > > rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
> > > > of kvargs that can be shared from init time.
> > > 
> > > I think the existing allocation scheme is fine for other usages (in
> > > drivers and so on). Not for what I wanted to do.
> > > 
> > Ok, but thats an adressable issue.  you can bifurcate the parse function to an
> > internal function that accepts any preallocated kvargs struct, and export two
> > wrapper functions, one which allocates the struct from the heap, another which
> > allocated automatically on the stack.
> > 
> 
> Sure, everything is possible.
> 
Ok.

> > > >                                               librte_kvargs isn't necessecarily
> > > > the best parsing library ever, but its not bad, and it just seems wrong to go
> > > > re-inventing the wheel.
> > > > 
> > > 
> > > It serves a different purpose than the one I'm pursuing.
> > > 
> > > This helper is lightweight and private. If I wanted to integrate my
> > > needs with librte_kvargs, I would be adding new functionalities, making
> > > it more complex, and for a use-case that is useless for the vast
> > > majority of users of the lib.
> > > 
> > Ok, to that end:
> > 
> > 1) Privacy is not an issue (at least from my understanding of what your doing).
> > If we start with the assumption that librte_kvargs is capable of satisfying your
> > needs (even if its not done in an optimal way), the fact that your version of
> > the function is internal to the library doesn't seem overly relevant, unless
> > theres something critical to that privacy that I'm missing.
> > 
> 
> Privacy is only a point I brought up to say that the impact of this
> function is minimal. People looking to parse their kvargs should not
> have any ambiguity regarding how they should do so. Only librte_kvargs
> is available.
> 
Ok, would you also council others developing dpdk apps to write their own
parsing routines when what they needed was trivial for the existing library?
You are people too :)

> > 2) Lightweight function  seems like something that can be integrated with
> > librte_kvargs.  Looking at it, what may I ask in librte_kvargs is insufficiently
> > non-performant for your needs, specifically?  We talked about the heap
> > allocation above, is there something else? The string duplication perhaps?
> > 
> > 
> 
> Mostly the way to use it.
> The filter strings are
> bus=value,.../class=value,...
> 
> where either bus= list or class= list can be omitted, but at least one
> must appear.
> 
Ok, so whats the problem with using librte_kvargs for that?  Is it that the list
that acts as the value to the key isn't parsed out into its own set of tokens?
That seems entirely addressable.

> I want to read a single kvarg. I do not want to parse the whole string.
> the '/' signifies the end of the current layer.
> 
This makes it seem like librte_kvargs can handle this as a trivial case of its
functionality.

> librte_kvargs does not care about those points. I cannot ask it to only
> read either bus or class, as it would then throw an error for all the
> other keys (which the EAL has necessarily no knowledge of).
> 
But you can ask it to read both, and within your libraries logic make the
determination as to the validitiy of receiving both.  Alternatively you can
modify the valid_keys check in kvargs to be a regex that matches on either bus
or class, or accept an ignore parameter for keys that may appear but should be
ignored in the light of other keys.  Theres lots of options here.

> So I would need to:
> 
>   * Add a custom storage scheme
>   * Add a custom parsing mode stopping at the first kvarg
>   * Add an edge-case to ignore the '/', so as not to throw off the rest
>     of the parsing (least it be considered part of the previous kvarg
>     value field).
> 
> Seeing this, does adding those really specifics functionality help
> librte_kvargs to be more useful and usable? I do not think so.
> 
I think you're overcomplicating this.
How about enhancing librte_kvargs to make parsing configurable
such that invalid keys get ignored rather than generate errors?

> It would only serve to disrupt the library for a marginal use-case, with
> the introduction of edge-cases that will blur the specs of the lib's
> API, making it harder to avoid subtle bugs.
> 
What do you mean "disrupt the library"?  What is its purpose of a library if not
to do the jobs we want it to?  If everyone created their own routine to do
something that a library could do with some modifications, we'd be left with
1000 versions of the same routine.  If the existing library does 99% of what you
want it to, lets ennumerate what the missing %1 is and make the change, not
throw the baby out with the bathwater.

> Only way to do so sanely would be to add rte_parse_kv as part of
> librte_kvargs, as is. But then the whole thing does not make sense IMO:
> no one would care to use it, the maintainance effort is the same, the
> likelyhood of bugs as well (but in the process we would disrupt the
> distribution of librte_kvargs by moving it within the EAL).
> 
> I see no benefit to either solution.
> 
Again, thats an overcomplication.  As I read it, you have a need to interrogate
a key/value string, whos contents may contain invalid keys (for your parsing
purposes), and whos values may themselves be lists, correct?  If so, I don't see
the problem in enhancing libkvargs to:

1) Allow for the parsing routine to ignore invalid keys (or even ignore specific
invalid keys, and trigger on any unknown keys)

2) Allows for the subparsing of lists into their own set of tokens.

> > > If that's really an issue, I'm better off simply removing rte_parse_kv
> > > and writing the parsing by hand within my function. This would be ugly
> > > and tedious, but less than moving librte_kvargs within EAL and changing
> > > it to my needs.
> > I don't think thats necessecary, I just think if you can ennumerate the items
> > that are non-performant for your needs we can make some changes to librte_kvargs
> > to optimize around them, or offer parsing options to avoid them, and in the
> > process avoid some code duplication
> > 
> 
> I think it makes sense to have specialized functions for specialized
> use-cases, and forcing the code to be generic and work with all of them
> will make it more complicated.
> 
This isn't specialized, its trivial.  Its just a trivial case that libkvargs
isn't built to handle at the moment.  Lets get it there.

> The genericity would only be worth it if people actually needed to parse
> the device strings the same way I do. No one has any business doing so.
> This genericity adds complexity and issues, without even being useful in
> the first place.
> 
I really think you're trying to take a short cut here where none is needed, and
I'm sorry, but I can't support that.

Neil

> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-23 11:54               ` Neil Horman
@ 2018-03-23 13:12                 ` Gaëtan Rivet
  2018-03-23 18:45                   ` [dpdk-dev] [PATCH 1/2] kvargs: the life of the party Gaetan Rivet
  2018-03-26 11:23                   ` [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility Neil Horman
  0 siblings, 2 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-23 13:12 UTC (permalink / raw)
  To: Neil Horman; +Cc: Wiles, Keith, dev

On Fri, Mar 23, 2018 at 07:54:11AM -0400, Neil Horman wrote:
> On Fri, Mar 23, 2018 at 10:31:22AM +0100, Gaëtan Rivet wrote:
> > On Thu, Mar 22, 2018 at 08:53:49PM -0400, Neil Horman wrote:
> > > On Thu, Mar 22, 2018 at 05:27:51PM +0100, Gaëtan Rivet wrote:
> > > > On Thu, Mar 22, 2018 at 10:10:37AM -0400, Neil Horman wrote:
> > > > > On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> > > > > > 
> > > > > > 
> > > > > > > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > > > > > > 
> > > > > > > This library offers a quick way to parse parameters passed with a
> > > > > > > key=value syntax.
> > > > > > > 
> > > > > > > A single function is needed and finds the relevant element within the
> > > > > > > text. No dynamic allocation is performed. It is possible to chain the
> > > > > > > parsing of each pairs for quickly scanning a list.
> > > > > > > 
> > > > > > > This utility is private to the EAL and should allow avoiding having to
> > > > > > > move around the more complete librte_kvargs.
> > > > > > 
> > > > > > What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> > > > > > 
> > > > > > My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> > > > > > 
> > > > > +1, this really doesn't make much sense to me.  Two parsing routines seems like
> > > > > its just asking for us to have to fix parsing bugs in two places.  If allocation
> > > > > is a concern, I don't see why you can't just change the malloc in
> > > > > rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
> > > > > of kvargs that can be shared from init time.
> > > > 
> > > > I think the existing allocation scheme is fine for other usages (in
> > > > drivers and so on). Not for what I wanted to do.
> > > > 
> > > Ok, but thats an adressable issue.  you can bifurcate the parse function to an
> > > internal function that accepts any preallocated kvargs struct, and export two
> > > wrapper functions, one which allocates the struct from the heap, another which
> > > allocated automatically on the stack.
> > > 
> > 
> > Sure, everything is possible.
> > 
> Ok.
> 
> > > > >                                               librte_kvargs isn't necessecarily
> > > > > the best parsing library ever, but its not bad, and it just seems wrong to go
> > > > > re-inventing the wheel.
> > > > > 
> > > > 
> > > > It serves a different purpose than the one I'm pursuing.
> > > > 
> > > > This helper is lightweight and private. If I wanted to integrate my
> > > > needs with librte_kvargs, I would be adding new functionalities, making
> > > > it more complex, and for a use-case that is useless for the vast
> > > > majority of users of the lib.
> > > > 
> > > Ok, to that end:
> > > 
> > > 1) Privacy is not an issue (at least from my understanding of what your doing).
> > > If we start with the assumption that librte_kvargs is capable of satisfying your
> > > needs (even if its not done in an optimal way), the fact that your version of
> > > the function is internal to the library doesn't seem overly relevant, unless
> > > theres something critical to that privacy that I'm missing.
> > > 
> > 
> > Privacy is only a point I brought up to say that the impact of this
> > function is minimal. People looking to parse their kvargs should not
> > have any ambiguity regarding how they should do so. Only librte_kvargs
> > is available.
> > 
> Ok, would you also council others developing dpdk apps to write their own
> parsing routines when what they needed was trivial for the existing library?
> You are people too :)
> 
> > > 2) Lightweight function  seems like something that can be integrated with
> > > librte_kvargs.  Looking at it, what may I ask in librte_kvargs is insufficiently
> > > non-performant for your needs, specifically?  We talked about the heap
> > > allocation above, is there something else? The string duplication perhaps?
> > > 
> > > 
> > 
> > Mostly the way to use it.
> > The filter strings are
> > bus=value,.../class=value,...
> > 
> > where either bus= list or class= list can be omitted, but at least one
> > must appear.
> > 
> Ok, so whats the problem with using librte_kvargs for that?  Is it that the list
> that acts as the value to the key isn't parsed out into its own set of tokens?
> That seems entirely addressable.
> 
> > I want to read a single kvarg. I do not want to parse the whole string.
> > the '/' signifies the end of the current layer.
> > 
> This makes it seem like librte_kvargs can handle this as a trivial case of its
> functionality.
> 
> > librte_kvargs does not care about those points. I cannot ask it to only
> > read either bus or class, as it would then throw an error for all the
> > other keys (which the EAL has necessarily no knowledge of).
> > 
> But you can ask it to read both, and within your libraries logic make the
> determination as to the validitiy of receiving both.  Alternatively you can
> modify the valid_keys check in kvargs to be a regex that matches on either bus
> or class, or accept an ignore parameter for keys that may appear but should be
> ignored in the light of other keys.  Theres lots of options here.
> 

No, I will not be adding regex parsing to express a set of acceptable
token :)

> > So I would need to:
> > 
> >   * Add a custom storage scheme
> >   * Add a custom parsing mode stopping at the first kvarg
> >   * Add an edge-case to ignore the '/', so as not to throw off the rest
> >     of the parsing (least it be considered part of the previous kvarg
> >     value field).
> > 
> > Seeing this, does adding those really specifics functionality help
> > librte_kvargs to be more useful and usable? I do not think so.
> > 
> I think you're overcomplicating this.
> How about enhancing librte_kvargs to make parsing configurable
> such that invalid keys get ignored rather than generate errors?
> 

Invalid keys can already be ignored, it's not an issue.

> > It would only serve to disrupt the library for a marginal use-case, with
> > the introduction of edge-cases that will blur the specs of the lib's
> > API, making it harder to avoid subtle bugs.
> > 
> What do you mean "disrupt the library"?  What is its purpose of a library if not
> to do the jobs we want it to?  If everyone created their own routine to do
> something that a library could do with some modifications, we'd be left with
> 1000 versions of the same routine.  If the existing library does 99% of what you
> want it to, lets ennumerate what the missing %1 is and make the change, not
> throw the baby out with the bathwater.
> 
> > Only way to do so sanely would be to add rte_parse_kv as part of
> > librte_kvargs, as is. But then the whole thing does not make sense IMO:
> > no one would care to use it, the maintainance effort is the same, the
> > likelyhood of bugs as well (but in the process we would disrupt the
> > distribution of librte_kvargs by moving it within the EAL).
> > 
> > I see no benefit to either solution.
> > 
> Again, thats an overcomplication.  As I read it, you have a need to interrogate
> a key/value string, whos contents may contain invalid keys (for your parsing
> purposes), and whos values may themselves be lists, correct?  If so, I don't see
> the problem in enhancing libkvargs to:
> 
> 1) Allow for the parsing routine to ignore invalid keys (or even ignore specific
> invalid keys, and trigger on any unknown keys)
> 
> 2) Allows for the subparsing of lists into their own set of tokens.
> 

What I would do if I wanted to use librte_kvargs, would be to duplicate
the input text, mangle it to respect the intended format, and feed it to
librte_kvargs for parsing. Then I would iterate over the pairs, and stop
on the two I'm concerned about.

What I dislike here:

  * I actually do the bulk of the parsing by hand (recognizing first a
    valid input, modifying it to respect the lib, and after iterating on
    the list of pairs and strcmp-ing the ones I want). This is approximately
    as complicated as the current helper function.

  * I have to move librte_kvargs in the EAL.

> > > > If that's really an issue, I'm better off simply removing rte_parse_kv
> > > > and writing the parsing by hand within my function. This would be ugly
> > > > and tedious, but less than moving librte_kvargs within EAL and changing
> > > > it to my needs.
> > > I don't think thats necessecary, I just think if you can ennumerate the items
> > > that are non-performant for your needs we can make some changes to librte_kvargs
> > > to optimize around them, or offer parsing options to avoid them, and in the
> > > process avoid some code duplication
> > > 
> > 
> > I think it makes sense to have specialized functions for specialized
> > use-cases, and forcing the code to be generic and work with all of them
> > will make it more complicated.
> > 
> This isn't specialized, its trivial.  Its just a trivial case that libkvargs
> isn't built to handle at the moment.  Lets get it there.
> 

My use-case is trivial. Putting it within the librte_kvargs makes it
more complicated to write. I hate this.

> > The genericity would only be worth it if people actually needed to parse
> > the device strings the same way I do. No one has any business doing so.
> > This genericity adds complexity and issues, without even being useful in
> > the first place.
> > 
> I really think you're trying to take a short cut here where none is needed, and
> I'm sorry, but I can't support that.

There are countably infinite solutions, we will probably reach one (and
it might even do what we want).

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-23  9:31             ` Gaëtan Rivet
  2018-03-23 11:54               ` Neil Horman
@ 2018-03-23 13:15               ` Wiles, Keith
  1 sibling, 0 replies; 364+ messages in thread
From: Wiles, Keith @ 2018-03-23 13:15 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Neil Horman, dev



> On Mar 23, 2018, at 4:31 AM, Gaëtan Rivet <gaetan.rivet@6wind.com> wrote:
> 
> On Thu, Mar 22, 2018 at 08:53:49PM -0400, Neil Horman wrote:
>> On Thu, Mar 22, 2018 at 05:27:51PM +0100, Gaëtan Rivet wrote:
>>> On Thu, Mar 22, 2018 at 10:10:37AM -0400, Neil Horman wrote:
>>>> On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
>>>>> 
>>>>> 
>>>>>> On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
>>>>>> 
>>>>>> This library offers a quick way to parse parameters passed with a
>>>>>> key=value syntax.
>>>>>> 
>>>>>> A single function is needed and finds the relevant element within the
>>>>>> text. No dynamic allocation is performed. It is possible to chain the
>>>>>> parsing of each pairs for quickly scanning a list.
>>>>>> 
>>>>>> This utility is private to the EAL and should allow avoiding having to
>>>>>> move around the more complete librte_kvargs.
>>>>> 
>>>>> What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
>>>>> 
>>>>> My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
>>>>> 
>>>> +1, this really doesn't make much sense to me.  Two parsing routines seems like
>>>> its just asking for us to have to fix parsing bugs in two places.  If allocation
>>>> is a concern, I don't see why you can't just change the malloc in
>>>> rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
>>>> of kvargs that can be shared from init time.
>>> 
>>> I think the existing allocation scheme is fine for other usages (in
>>> drivers and so on). Not for what I wanted to do.
>>> 
>> Ok, but thats an adressable issue.  you can bifurcate the parse function to an
>> internal function that accepts any preallocated kvargs struct, and export two
>> wrapper functions, one which allocates the struct from the heap, another which
>> allocated automatically on the stack.
>> 
> 
> Sure, everything is possible.
> 
>>>>                                              librte_kvargs isn't necessecarily
>>>> the best parsing library ever, but its not bad, and it just seems wrong to go
>>>> re-inventing the wheel.
>>>> 
>>> 
>>> It serves a different purpose than the one I'm pursuing.
>>> 
>>> This helper is lightweight and private. If I wanted to integrate my
>>> needs with librte_kvargs, I would be adding new functionalities, making
>>> it more complex, and for a use-case that is useless for the vast
>>> majority of users of the lib.
>>> 
>> Ok, to that end:
>> 
>> 1) Privacy is not an issue (at least from my understanding of what your doing).
>> If we start with the assumption that librte_kvargs is capable of satisfying your
>> needs (even if its not done in an optimal way), the fact that your version of
>> the function is internal to the library doesn't seem overly relevant, unless
>> theres something critical to that privacy that I'm missing.
>> 
> 
> Privacy is only a point I brought up to say that the impact of this
> function is minimal. People looking to parse their kvargs should not
> have any ambiguity regarding how they should do so. Only librte_kvargs
> is available.
> 
>> 2) Lightweight function  seems like something that can be integrated with
>> librte_kvargs.  Looking at it, what may I ask in librte_kvargs is insufficiently
>> non-performant for your needs, specifically?  We talked about the heap
>> allocation above, is there something else? The string duplication perhaps?
>> 
>> 
> 
> Mostly the way to use it.
> The filter strings are
> bus=value,.../class=value,...
> 
> where either bus= list or class= list can be omitted, but at least one
> must appear.
> 
> I want to read a single kvarg. I do not want to parse the whole string.
> the '/' signifies the end of the current layer.
> 
> librte_kvargs does not care about those points. I cannot ask it to only
> read either bus or class, as it would then throw an error for all the
> other keys (which the EAL has necessarily no knowledge of).
> 
> So I would need to:
> 
>  * Add a custom storage scheme
>  * Add a custom parsing mode stopping at the first kvarg
>  * Add an edge-case to ignore the '/', so as not to throw off the rest
>    of the parsing (least it be considered part of the previous kvarg
>    value field).
> 
> Seeing this, does adding those really specifics functionality help
> librte_kvargs to be more useful and usable? I do not think so.
> 
> It would only serve to disrupt the library for a marginal use-case, with
> the introduction of edge-cases that will blur the specs of the lib's
> API, making it harder to avoid subtle bugs.
> 
> Only way to do so sanely would be to add rte_parse_kv as part of
> librte_kvargs, as is. But then the whole thing does not make sense IMO:
> no one would care to use it, the maintainance effort is the same, the
> likelyhood of bugs as well (but in the process we would disrupt the
> distribution of librte_kvargs by moving it within the EAL).

It seems to me you could layer the new functionality on top of rte_kvargs to provide the new layering you want and still provide the old API for current usage. The allocation of memory is internal to rte_kvargs and it really should not allocate memory or allocate on the stack. This change is something we should most likely do for rte_kvargs anyway. I do not like routines that allocate memory for me then expect me to free the memory later only because it needed some internal working space, but that is just me.

In my previous coding needs I had layered a structure and routine on top of rte_kvargs to provide something close to your needs, but in the long run I did not need the code as the design changed. I could look at the again and see if it would help here.

> 
> I see no benefit to either solution.
> 
>>> If that's really an issue, I'm better off simply removing rte_parse_kv
>>> and writing the parsing by hand within my function. This would be ugly
>>> and tedious, but less than moving librte_kvargs within EAL and changing
>>> it to my needs.
>> I don't think thats necessecary, I just think if you can ennumerate the items
>> that are non-performant for your needs we can make some changes to librte_kvargs
>> to optimize around them, or offer parsing options to avoid them, and in the
>> process avoid some code duplication
>> 
> 
> I think it makes sense to have specialized functions for specialized
> use-cases, and forcing the code to be generic and work with all of them
> will make it more complicated.
> 
> The genericity would only be worth it if people actually needed to parse
> the device strings the same way I do. No one has any business doing so.
> This genericity adds complexity and issues, without even being useful in
> the first place.
> 
> -- 
> Gaëtan Rivet
> 6WIND

Regards,
Keith


^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH 1/2] kvargs: the life of the party
  2018-03-23 13:12                 ` Gaëtan Rivet
@ 2018-03-23 18:45                   ` Gaetan Rivet
  2018-03-23 18:45                     ` [dpdk-dev] [PATCH 2/2] dev: use rte_kvargs Gaetan Rivet
  2018-03-26 11:23                   ` [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility Neil Horman
  1 sibling, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-23 18:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---

This is a rough sketch of what would be done to move rte_kvargs
within the EAL and change the parsing in rte_dev to use it.

 drivers/baseband/Makefile                          |  2 +-
 lib/Makefile                                       |  5 +-
 lib/librte_eal/Makefile                            |  2 +
 lib/librte_eal/common/Makefile                     |  2 +-
 lib/librte_eal/kvargs/Makefile                     | 23 ++++++++++
 .../kvargs}/meson.build                            |  0
 .../kvargs}/rte_kvargs.c                           | 12 +++--
 .../kvargs}/rte_kvargs.h                           |  0
 .../kvargs}/rte_kvargs_version.map                 |  0
 .../{common/include => kvargs}/rte_string_fns.h    |  0
 lib/librte_eal/linuxapp/eal/eal_hugepage_info.c    |  2 +-
 lib/librte_kvargs/Makefile                         | 53 ----------------------
 12 files changed, 37 insertions(+), 64 deletions(-)
 create mode 100644 lib/librte_eal/kvargs/Makefile
 rename lib/{librte_kvargs => librte_eal/kvargs}/meson.build (100%)
 rename lib/{librte_kvargs => librte_eal/kvargs}/rte_kvargs.c (96%)
 rename lib/{librte_kvargs => librte_eal/kvargs}/rte_kvargs.h (100%)
 rename lib/{librte_kvargs => librte_eal/kvargs}/rte_kvargs_version.map (100%)
 rename lib/librte_eal/{common/include => kvargs}/rte_string_fns.h (100%)
 delete mode 100644 lib/librte_kvargs/Makefile

diff --git a/drivers/baseband/Makefile b/drivers/baseband/Makefile
index 4ec83b0a0..64f6f9ca7 100644
--- a/drivers/baseband/Makefile
+++ b/drivers/baseband/Makefile
@@ -4,7 +4,7 @@
 include $(RTE_SDK)/mk/rte.vars.mk
 
 core-libs := librte_eal librte_mbuf librte_mempool librte_ring
-core-libs += librte_bbdev librte_kvargs librte_cfgfile
+core-libs += librte_bbdev librte_cfgfile
 
 DIRS-$(CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL) += null
 DEPDIRS-null = $(core-libs)
diff --git a/lib/Makefile b/lib/Makefile
index 6bb6a8bed..aef95b201 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -20,12 +20,11 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf librte_kvargs
+DEPDIRS-librte_ether += librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
 DEPDIRS-librte_cryptodev := librte_eal librte_mempool librte_ring librte_mbuf
-DEPDIRS-librte_cryptodev += librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_SECURITY) += librte_security
 DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf
 DEPDIRS-librte_security += librte_ether
@@ -71,8 +70,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/Makefile b/lib/librte_eal/Makefile
index ccd45cb84..d6b520aeb 100644
--- a/lib/librte_eal/Makefile
+++ b/lib/librte_eal/Makefile
@@ -3,7 +3,9 @@
 
 include $(RTE_SDK)/mk/rte.vars.mk
 
+DIRS-y += kvargs
 DIRS-y += common
+DEPDIRS-common := kvargs
 DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += linuxapp
 DEPDIRS-linuxapp := common
 DIRS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += bsdapp
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 211b21b4b..607ae0447 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -9,7 +9,7 @@ INC += rte_errno.h rte_launch.h rte_lcore.h
 INC += rte_log.h rte_memory.h rte_memzone.h
 INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
+INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
diff --git a/lib/librte_eal/kvargs/Makefile b/lib/librte_eal/kvargs/Makefile
new file mode 100644
index 000000000..65d15744e
--- /dev/null
+++ b/lib/librte_eal/kvargs/Makefile
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2014 6WIND S.A.
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_kvargs.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+
+EXPORT_MAP := rte_kvargs_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c
+
+# install includes
+INCS := rte_kvargs.h
+INCS += rte_string_fns.h
+SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS)
+
+include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_kvargs/meson.build b/lib/librte_eal/kvargs/meson.build
similarity index 100%
rename from lib/librte_kvargs/meson.build
rename to lib/librte_eal/kvargs/meson.build
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_eal/kvargs/rte_kvargs.c
similarity index 96%
rename from lib/librte_kvargs/rte_kvargs.c
rename to lib/librte_eal/kvargs/rte_kvargs.c
index 9662375e8..69a942723 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_eal/kvargs/rte_kvargs.c
@@ -3,13 +3,17 @@
  * Copyright(c) 2014 6WIND S.A.
  */
 
-#include <string.h>
+#include <stdio.h>
 #include <stdlib.h>
-
-#include <rte_log.h>
-#include <rte_string_fns.h>
+#include <string.h>
 
 #include "rte_kvargs.h"
+#include "rte_string_fns.h"
+
+#define ERR stderr
+#define PMD "[PMD]"
+#define RTE_LOG(lvl, prefix, ...) \
+	fprintf(lvl, prefix " " __VA_ARGS__);
 
 /*
  * Receive a string with a list of arguments following the pattern
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_eal/kvargs/rte_kvargs.h
similarity index 100%
rename from lib/librte_kvargs/rte_kvargs.h
rename to lib/librte_eal/kvargs/rte_kvargs.h
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_eal/kvargs/rte_kvargs_version.map
similarity index 100%
rename from lib/librte_kvargs/rte_kvargs_version.map
rename to lib/librte_eal/kvargs/rte_kvargs_version.map
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_eal/kvargs/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_eal/kvargs/rte_string_fns.h
diff --git a/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c b/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c
index 8bbf771af..63d701555 100644
--- a/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c
+++ b/lib/librte_eal/linuxapp/eal/eal_hugepage_info.c
@@ -24,7 +24,7 @@
 #include <rte_debug.h>
 #include <rte_log.h>
 #include <rte_common.h>
-#include "rte_string_fns.h"
+#include <rte_string_fns.h>
 #include "eal_internal_cfg.h"
 #include "eal_hugepages.h"
 #include "eal_filesystem.h"
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
deleted file mode 100644
index 4eaa9334d..000000000
--- a/lib/librte_kvargs/Makefile
+++ /dev/null
@@ -1,53 +0,0 @@
-# BSD LICENSE
-#
-# Copyright 2014 6WIND S.A.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# - Redistributions of source code must retain the above copyright
-#   notice, this list of conditions and the following disclaimer.
-#
-# - Redistributions in binary form must reproduce the above copyright
-#   notice, this list of conditions and the following disclaimer in
-#   the documentation and/or other materials provided with the
-#   distribution.
-#
-# - Neither the name of 6WIND S.A. nor the names of its
-#   contributors may be used to endorse or promote products derived
-#   from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
-# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
-# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-# OF THE POSSIBILITY OF SUCH DAMAGE.
-
-include $(RTE_SDK)/mk/rte.vars.mk
-
-# library name
-LIB = librte_kvargs.a
-
-CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
-
-EXPORT_MAP := rte_kvargs_version.map
-
-LIBABIVER := 1
-
-# all source are stored in SRCS-y
-SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c
-
-# install includes
-INCS := rte_kvargs.h
-SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS)
-
-include $(RTE_SDK)/mk/rte.lib.mk
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH 2/2] dev: use rte_kvargs
  2018-03-23 18:45                   ` [dpdk-dev] [PATCH 1/2] kvargs: the life of the party Gaetan Rivet
@ 2018-03-23 18:45                     ` Gaetan Rivet
  2018-03-26 11:38                       ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-23 18:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---

Cc: Neil Horman <nhorman@tuxdriver.com>

I find using rte_parse_kv cleaner.
The function rte_dev_iterator_init is already ugly enough as it is.
This is really not helping.

 lib/librte_eal/common/eal_common_dev.c | 127 +++++++++++++++++++++------------
 lib/librte_eal/linuxapp/eal/Makefile   |   1 +
 2 files changed, 83 insertions(+), 45 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 21703b777..9f1a0ebda 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -15,6 +15,7 @@
 #include <rte_devargs.h>
 #include <rte_debug.h>
 #include <rte_errno.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 
 #include "eal_private.h"
@@ -270,12 +271,15 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)
 }
 
 int __rte_experimental
-rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
+rte_dev_iterator_init(struct rte_dev_iterator *it,
+		      const char *devstr)
 {
-	struct rte_bus *bus = NULL;
+	struct rte_kvargs *kvlist = NULL;
 	struct rte_class *cls = NULL;
-	struct rte_kvarg kv;
-	char *slash;
+	struct rte_bus *bus = NULL;
+	struct rte_kvargs_pair *kv;
+	char *slash = NULL;
+	char *str = NULL;
 
 	/* Having both busstr and clsstr NULL is illegal,
 	 * marking this iterator as invalid unless
@@ -283,98 +287,131 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
 	 */
 	it->busstr = NULL;
 	it->clsstr = NULL;
+	str = strdup(devstr);
+	if (str == NULL) {
+		rte_errno = ENOMEM;
+		goto get_out;
+	}
+	slash = strchr(str, '/');
+	if (slash != NULL) {
+		slash[0] = '\0';
+		slash = strchr(devstr, '/') + 1;
+	}
 	/* Safety checks and prep-work */
-	if (rte_parse_kv(str, &kv)) {
+	kvlist = rte_kvargs_parse(str, NULL);
+	if (kvlist == NULL) {
 		RTE_LOG(ERR, EAL, "Could not parse: %s\n", str);
 		rte_errno = EINVAL;
-		return -rte_errno;
+		goto get_out;
 	}
 	it->device = NULL;
 	it->class_device = NULL;
-	if (strcmp(kv.key, "bus") == 0) {
-		bus = rte_bus_find_by_name(kv.value);
+	kv = &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);
+				kv->value);
 			rte_errno = EFAULT;
-			return -rte_errno;
+			goto get_out;
 		}
-		slash = strchr(str, '/');
 		if (slash != NULL) {
-			if (rte_parse_kv(slash + 1, &kv)) {
+			rte_kvargs_free(kvlist);
+			kvlist = rte_kvargs_parse(slash, NULL);
+			if (kvlist == NULL) {
 				RTE_LOG(ERR, EAL, "Could not parse: %s\n",
-					slash + 1);
+					slash);
 				rte_errno = EINVAL;
-				return -rte_errno;
+				goto get_out;
 			}
-			cls = rte_class_find_by_name(kv.value);
+			kv = &kvlist->pairs[0];
+			if (strcmp(kv->key, "class")) {
+				RTE_LOG(ERR, EAL, "Additional layer must be a class\n");
+				rte_errno = EINVAL;
+				goto get_out;
+			}
+			cls = rte_class_find_by_name(kv->value);
 			if (cls == NULL) {
 				RTE_LOG(ERR, EAL, "Could not find class \"%s\"\n",
-					kv.value);
+					kv->value);
 				rte_errno = EFAULT;
-				return -rte_errno;
+				goto get_out;
 			}
 		}
-	} else if (strcmp(kv.key, "class") == 0) {
-		cls = rte_class_find_by_name(kv.value);
+	} 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);
+				kv->value);
 			rte_errno = EFAULT;
-			return -rte_errno;
+			goto get_out;
 		}
 	} else {
 		rte_errno = EINVAL;
-		return -rte_errno;
+		goto get_out;
 	}
 	/* The string should have at least
 	 * one layer specified.
 	 */
 	if (bus == NULL && cls == NULL) {
 		rte_errno = EINVAL;
-		return -rte_errno;
+		goto get_out;
 	}
 	if ((bus != NULL && bus->dev_iterate == NULL) ||
 	    (cls != NULL && cls->dev_iterate == NULL)) {
 		rte_errno = ENOTSUP;
-		return -rte_errno;
+		goto get_out;
 	}
 	if (bus != NULL) {
-		it->busstr = str;
+		it->busstr = devstr;
 		if (cls != NULL)
-			it->clsstr = slash + 1;
+			it->clsstr = slash;
 	} else if (cls != NULL) {
-		it->clsstr = str;
+		it->clsstr = devstr;
 	}
-	it->devstr = str;
+	it->devstr = devstr;
 	it->bus = bus;
 	it->cls = cls;
-	return 0;
+get_out:
+	rte_kvargs_free(kvlist);
+	free(str);
+	return -rte_errno;
+}
+
+/* '\0' forbidden in sym */
+static const char *
+strfirstof(const char *str,
+	   const char *sym)
+{
+	const char *s;
+
+	for (s = str; s[0] != '\0'; s++) {
+		const char *c;
+
+		for (c = sym; c[0] != '\0'; c++) {
+			if (c[0] == s[0])
+				return s;
+		}
+	}
+	return NULL;
 }
 
 static char *
 dev_str_sane_cpy(const char *str)
 {
-	struct rte_kvarg kv;
-	char *end;
+	const char *end;
 	char *cpy;
 
-	if (rte_parse_kv(str, &kv)) {
-		rte_errno = EINVAL;
-		return NULL;
-	}
-	/* copying '\0' is valid. */
-	if (kv.next != NULL)
-		cpy = strdup(kv.next);
-	else
+	end = strfirstof(str, ",/");
+	if (end != NULL &&
+	    end[0] == ',') {
+		cpy = strdup(end + 1);
+	} else {
+		/* '/' or '\0' */
 		cpy = strdup("");
-	if (cpy == NULL) {
-		rte_errno = ENOMEM;
-		return NULL;
 	}
-	end = strchr(cpy, '/');
-	if (end != NULL)
-		end[0] = '\0';
+	if (cpy == NULL)
+		rte_errno = ENOMEM;
 	return cpy;
 }
 
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index a3edbbe76..87caa23a1 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
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
  2018-03-23 13:12                 ` Gaëtan Rivet
  2018-03-23 18:45                   ` [dpdk-dev] [PATCH 1/2] kvargs: the life of the party Gaetan Rivet
@ 2018-03-26 11:23                   ` Neil Horman
  1 sibling, 0 replies; 364+ messages in thread
From: Neil Horman @ 2018-03-26 11:23 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Wiles, Keith, dev

On Fri, Mar 23, 2018 at 02:12:36PM +0100, Gaëtan Rivet wrote:
> On Fri, Mar 23, 2018 at 07:54:11AM -0400, Neil Horman wrote:
> > On Fri, Mar 23, 2018 at 10:31:22AM +0100, Gaëtan Rivet wrote:
> > > On Thu, Mar 22, 2018 at 08:53:49PM -0400, Neil Horman wrote:
> > > > On Thu, Mar 22, 2018 at 05:27:51PM +0100, Gaëtan Rivet wrote:
> > > > > On Thu, Mar 22, 2018 at 10:10:37AM -0400, Neil Horman wrote:
> > > > > > On Wed, Mar 21, 2018 at 05:32:24PM +0000, Wiles, Keith wrote:
> > > > > > > 
> > > > > > > 
> > > > > > > > On Mar 21, 2018, at 12:15 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > > > > > > > 
> > > > > > > > This library offers a quick way to parse parameters passed with a
> > > > > > > > key=value syntax.
> > > > > > > > 
> > > > > > > > A single function is needed and finds the relevant element within the
> > > > > > > > text. No dynamic allocation is performed. It is possible to chain the
> > > > > > > > parsing of each pairs for quickly scanning a list.
> > > > > > > > 
> > > > > > > > This utility is private to the EAL and should allow avoiding having to
> > > > > > > > move around the more complete librte_kvargs.
> > > > > > > 
> > > > > > > What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
> > > > > > > 
> > > > > > > My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
> > > > > > > 
> > > > > > +1, this really doesn't make much sense to me.  Two parsing routines seems like
> > > > > > its just asking for us to have to fix parsing bugs in two places.  If allocation
> > > > > > is a concern, I don't see why you can't just change the malloc in
> > > > > > rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set
> > > > > > of kvargs that can be shared from init time.
> > > > > 
> > > > > I think the existing allocation scheme is fine for other usages (in
> > > > > drivers and so on). Not for what I wanted to do.
> > > > > 
> > > > Ok, but thats an adressable issue.  you can bifurcate the parse function to an
> > > > internal function that accepts any preallocated kvargs struct, and export two
> > > > wrapper functions, one which allocates the struct from the heap, another which
> > > > allocated automatically on the stack.
> > > > 
> > > 
> > > Sure, everything is possible.
> > > 
> > Ok.
> > 
> > > > > >                                               librte_kvargs isn't necessecarily
> > > > > > the best parsing library ever, but its not bad, and it just seems wrong to go
> > > > > > re-inventing the wheel.
> > > > > > 
> > > > > 
> > > > > It serves a different purpose than the one I'm pursuing.
> > > > > 
> > > > > This helper is lightweight and private. If I wanted to integrate my
> > > > > needs with librte_kvargs, I would be adding new functionalities, making
> > > > > it more complex, and for a use-case that is useless for the vast
> > > > > majority of users of the lib.
> > > > > 
> > > > Ok, to that end:
> > > > 
> > > > 1) Privacy is not an issue (at least from my understanding of what your doing).
> > > > If we start with the assumption that librte_kvargs is capable of satisfying your
> > > > needs (even if its not done in an optimal way), the fact that your version of
> > > > the function is internal to the library doesn't seem overly relevant, unless
> > > > theres something critical to that privacy that I'm missing.
> > > > 
> > > 
> > > Privacy is only a point I brought up to say that the impact of this
> > > function is minimal. People looking to parse their kvargs should not
> > > have any ambiguity regarding how they should do so. Only librte_kvargs
> > > is available.
> > > 
> > Ok, would you also council others developing dpdk apps to write their own
> > parsing routines when what they needed was trivial for the existing library?
> > You are people too :)
> > 
> > > > 2) Lightweight function  seems like something that can be integrated with
> > > > librte_kvargs.  Looking at it, what may I ask in librte_kvargs is insufficiently
> > > > non-performant for your needs, specifically?  We talked about the heap
> > > > allocation above, is there something else? The string duplication perhaps?
> > > > 
> > > > 
> > > 
> > > Mostly the way to use it.
> > > The filter strings are
> > > bus=value,.../class=value,...
> > > 
> > > where either bus= list or class= list can be omitted, but at least one
> > > must appear.
> > > 
> > Ok, so whats the problem with using librte_kvargs for that?  Is it that the list
> > that acts as the value to the key isn't parsed out into its own set of tokens?
> > That seems entirely addressable.
> > 
> > > I want to read a single kvarg. I do not want to parse the whole string.
> > > the '/' signifies the end of the current layer.
> > > 
> > This makes it seem like librte_kvargs can handle this as a trivial case of its
> > functionality.
> > 
> > > librte_kvargs does not care about those points. I cannot ask it to only
> > > read either bus or class, as it would then throw an error for all the
> > > other keys (which the EAL has necessarily no knowledge of).
> > > 
> > But you can ask it to read both, and within your libraries logic make the
> > determination as to the validitiy of receiving both.  Alternatively you can
> > modify the valid_keys check in kvargs to be a regex that matches on either bus
> > or class, or accept an ignore parameter for keys that may appear but should be
> > ignored in the light of other keys.  Theres lots of options here.
> > 
> 
> No, I will not be adding regex parsing to express a set of acceptable
> token :)
> 
Thats fine, Just making suggestions as to how to add the functionality you need
to the command line parsing library.  I'm not sure what you're opposision is,
but there are lots of other ways to skin this cat.


> > > So I would need to:
> > > 
> > >   * Add a custom storage scheme
> > >   * Add a custom parsing mode stopping at the first kvarg
> > >   * Add an edge-case to ignore the '/', so as not to throw off the rest
> > >     of the parsing (least it be considered part of the previous kvarg
> > >     value field).
> > > 
> > > Seeing this, does adding those really specifics functionality help
> > > librte_kvargs to be more useful and usable? I do not think so.
> > > 
> > I think you're overcomplicating this.
> > How about enhancing librte_kvargs to make parsing configurable
> > such that invalid keys get ignored rather than generate errors?
> > 
> 
> Invalid keys can already be ignored, it's not an issue.
> 
Ok, that eliminates one problem and seems like it makes even more sense to use
the standard parsing library.

> > > It would only serve to disrupt the library for a marginal use-case, with
> > > the introduction of edge-cases that will blur the specs of the lib's
> > > API, making it harder to avoid subtle bugs.
> > > 
> > What do you mean "disrupt the library"?  What is its purpose of a library if not
> > to do the jobs we want it to?  If everyone created their own routine to do
> > something that a library could do with some modifications, we'd be left with
> > 1000 versions of the same routine.  If the existing library does 99% of what you
> > want it to, lets ennumerate what the missing %1 is and make the change, not
> > throw the baby out with the bathwater.
> > 
> > > Only way to do so sanely would be to add rte_parse_kv as part of
> > > librte_kvargs, as is. But then the whole thing does not make sense IMO:
> > > no one would care to use it, the maintainance effort is the same, the
> > > likelyhood of bugs as well (but in the process we would disrupt the
> > > distribution of librte_kvargs by moving it within the EAL).
> > > 
> > > I see no benefit to either solution.
> > > 
> > Again, thats an overcomplication.  As I read it, you have a need to interrogate
> > a key/value string, whos contents may contain invalid keys (for your parsing
> > purposes), and whos values may themselves be lists, correct?  If so, I don't see
> > the problem in enhancing libkvargs to:
> > 
> > 1) Allow for the parsing routine to ignore invalid keys (or even ignore specific
> > invalid keys, and trigger on any unknown keys)
> > 
> > 2) Allows for the subparsing of lists into their own set of tokens.
> > 
> 
> What I would do if I wanted to use librte_kvargs, would be to duplicate
> the input text, mangle it to respect the intended format, and feed it to
> librte_kvargs for parsing. Then I would iterate over the pairs, and stop
> on the two I'm concerned about.
> 
> What I dislike here:
> 
>   * I actually do the bulk of the parsing by hand (recognizing first a
>     valid input, modifying it to respect the lib, and after iterating on
>     the list of pairs and strcmp-ing the ones I want). This is approximately
>     as complicated as the current helper function.
> 
Or, just extend the kvargs string format to allow for nested lits (which I think
is the main sticking point here) and adjust your input format accordingly.

>   * I have to move librte_kvargs in the EAL.
> 
Why?  Theres no reason you can't make eal dependent on kvargs, I see no circular
dependency there.

> > > > > If that's really an issue, I'm better off simply removing rte_parse_kv
> > > > > and writing the parsing by hand within my function. This would be ugly
> > > > > and tedious, but less than moving librte_kvargs within EAL and changing
> > > > > it to my needs.
> > > > I don't think thats necessecary, I just think if you can ennumerate the items
> > > > that are non-performant for your needs we can make some changes to librte_kvargs
> > > > to optimize around them, or offer parsing options to avoid them, and in the
> > > > process avoid some code duplication
> > > > 
> > > 
> > > I think it makes sense to have specialized functions for specialized
> > > use-cases, and forcing the code to be generic and work with all of them
> > > will make it more complicated.
> > > 
> > This isn't specialized, its trivial.  Its just a trivial case that libkvargs
> > isn't built to handle at the moment.  Lets get it there.
> > 
> 
> My use-case is trivial. Putting it within the librte_kvargs makes it
> more complicated to write. I hate this.
> 
If librte_kvargs can't handle a trivial use case, then kvargs needs to be
improved.

> > > The genericity would only be worth it if people actually needed to parse
> > > the device strings the same way I do. No one has any business doing so.
> > > This genericity adds complexity and issues, without even being useful in
> > > the first place.
> > > 
> > I really think you're trying to take a short cut here where none is needed, and
> > I'm sorry, but I can't support that.
> 
> There are countably infinite solutions, we will probably reach one (and
> it might even do what we want).
I'm not really sure what you mean by this, but the bottom line for me is that
there is no reason to invent a new wheel when you have a library who purpose is
to do the kind of things you want.

Neil

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] dev: use rte_kvargs
  2018-03-23 18:45                     ` [dpdk-dev] [PATCH 2/2] dev: use rte_kvargs Gaetan Rivet
@ 2018-03-26 11:38                       ` Neil Horman
  2018-03-26 13:59                         ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-26 11:38 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Fri, Mar 23, 2018 at 07:45:03PM +0100, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
> 
> Cc: Neil Horman <nhorman@tuxdriver.com>
> 
I'm actually ok with this, but as Keith noted, I'm not sure why you didn't just:

1) Add the ability to create a grouping key, so that key value pairs could
contain a list of comma separated values (something like '{}' to denote that
everything between the characters was the value in a kv pair, regardless of
other tokenizing characters in the value).

2) Add the ability to recursively parse the value into a list of tokens

3) Layer your functionality on top of (1) and (2), as Keith noted

Neil

> I find using rte_parse_kv cleaner.
> The function rte_dev_iterator_init is already ugly enough as it is.
> This is really not helping.
> 
>  lib/librte_eal/common/eal_common_dev.c | 127 +++++++++++++++++++++------------
>  lib/librte_eal/linuxapp/eal/Makefile   |   1 +
>  2 files changed, 83 insertions(+), 45 deletions(-)
> 
> diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
> index 21703b777..9f1a0ebda 100644
> --- a/lib/librte_eal/common/eal_common_dev.c
> +++ b/lib/librte_eal/common/eal_common_dev.c
> @@ -15,6 +15,7 @@
>  #include <rte_devargs.h>
>  #include <rte_debug.h>
>  #include <rte_errno.h>
> +#include <rte_kvargs.h>
>  #include <rte_log.h>
>  
>  #include "eal_private.h"
> @@ -270,12 +271,15 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)
>  }
>  
>  int __rte_experimental
> -rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
> +rte_dev_iterator_init(struct rte_dev_iterator *it,
> +		      const char *devstr)
>  {
> -	struct rte_bus *bus = NULL;
> +	struct rte_kvargs *kvlist = NULL;
>  	struct rte_class *cls = NULL;
> -	struct rte_kvarg kv;
> -	char *slash;
> +	struct rte_bus *bus = NULL;
> +	struct rte_kvargs_pair *kv;
> +	char *slash = NULL;
> +	char *str = NULL;
>  
>  	/* Having both busstr and clsstr NULL is illegal,
>  	 * marking this iterator as invalid unless
> @@ -283,98 +287,131 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)
>  	 */
>  	it->busstr = NULL;
>  	it->clsstr = NULL;
> +	str = strdup(devstr);
> +	if (str == NULL) {
> +		rte_errno = ENOMEM;
> +		goto get_out;
> +	}
> +	slash = strchr(str, '/');
> +	if (slash != NULL) {
> +		slash[0] = '\0';
> +		slash = strchr(devstr, '/') + 1;
> +	}
>  	/* Safety checks and prep-work */
> -	if (rte_parse_kv(str, &kv)) {
> +	kvlist = rte_kvargs_parse(str, NULL);
> +	if (kvlist == NULL) {
>  		RTE_LOG(ERR, EAL, "Could not parse: %s\n", str);
>  		rte_errno = EINVAL;
> -		return -rte_errno;
> +		goto get_out;
>  	}
>  	it->device = NULL;
>  	it->class_device = NULL;
> -	if (strcmp(kv.key, "bus") == 0) {
> -		bus = rte_bus_find_by_name(kv.value);
> +	kv = &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);
> +				kv->value);
>  			rte_errno = EFAULT;
> -			return -rte_errno;
> +			goto get_out;
>  		}
> -		slash = strchr(str, '/');
>  		if (slash != NULL) {
> -			if (rte_parse_kv(slash + 1, &kv)) {
> +			rte_kvargs_free(kvlist);
> +			kvlist = rte_kvargs_parse(slash, NULL);
> +			if (kvlist == NULL) {
>  				RTE_LOG(ERR, EAL, "Could not parse: %s\n",
> -					slash + 1);
> +					slash);
>  				rte_errno = EINVAL;
> -				return -rte_errno;
> +				goto get_out;
>  			}
> -			cls = rte_class_find_by_name(kv.value);
> +			kv = &kvlist->pairs[0];
> +			if (strcmp(kv->key, "class")) {
> +				RTE_LOG(ERR, EAL, "Additional layer must be a class\n");
> +				rte_errno = EINVAL;
> +				goto get_out;
> +			}
> +			cls = rte_class_find_by_name(kv->value);
>  			if (cls == NULL) {
>  				RTE_LOG(ERR, EAL, "Could not find class \"%s\"\n",
> -					kv.value);
> +					kv->value);
>  				rte_errno = EFAULT;
> -				return -rte_errno;
> +				goto get_out;
>  			}
>  		}
> -	} else if (strcmp(kv.key, "class") == 0) {
> -		cls = rte_class_find_by_name(kv.value);
> +	} 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);
> +				kv->value);
>  			rte_errno = EFAULT;
> -			return -rte_errno;
> +			goto get_out;
>  		}
>  	} else {
>  		rte_errno = EINVAL;
> -		return -rte_errno;
> +		goto get_out;
>  	}
>  	/* The string should have at least
>  	 * one layer specified.
>  	 */
>  	if (bus == NULL && cls == NULL) {
>  		rte_errno = EINVAL;
> -		return -rte_errno;
> +		goto get_out;
>  	}
>  	if ((bus != NULL && bus->dev_iterate == NULL) ||
>  	    (cls != NULL && cls->dev_iterate == NULL)) {
>  		rte_errno = ENOTSUP;
> -		return -rte_errno;
> +		goto get_out;
>  	}
>  	if (bus != NULL) {
> -		it->busstr = str;
> +		it->busstr = devstr;
>  		if (cls != NULL)
> -			it->clsstr = slash + 1;
> +			it->clsstr = slash;
>  	} else if (cls != NULL) {
> -		it->clsstr = str;
> +		it->clsstr = devstr;
>  	}
> -	it->devstr = str;
> +	it->devstr = devstr;
>  	it->bus = bus;
>  	it->cls = cls;
> -	return 0;
> +get_out:
> +	rte_kvargs_free(kvlist);
> +	free(str);
> +	return -rte_errno;
> +}
> +
> +/* '\0' forbidden in sym */
> +static const char *
> +strfirstof(const char *str,
> +	   const char *sym)
> +{
> +	const char *s;
> +
> +	for (s = str; s[0] != '\0'; s++) {
> +		const char *c;
> +
> +		for (c = sym; c[0] != '\0'; c++) {
> +			if (c[0] == s[0])
> +				return s;
> +		}
> +	}
> +	return NULL;
>  }
>  
>  static char *
>  dev_str_sane_cpy(const char *str)
>  {
> -	struct rte_kvarg kv;
> -	char *end;
> +	const char *end;
>  	char *cpy;
>  
> -	if (rte_parse_kv(str, &kv)) {
> -		rte_errno = EINVAL;
> -		return NULL;
> -	}
> -	/* copying '\0' is valid. */
> -	if (kv.next != NULL)
> -		cpy = strdup(kv.next);
> -	else
> +	end = strfirstof(str, ",/");
> +	if (end != NULL &&
> +	    end[0] == ',') {
> +		cpy = strdup(end + 1);
> +	} else {
> +		/* '/' or '\0' */
>  		cpy = strdup("");
> -	if (cpy == NULL) {
> -		rte_errno = ENOMEM;
> -		return NULL;
>  	}
> -	end = strchr(cpy, '/');
> -	if (end != NULL)
> -		end[0] = '\0';
> +	if (cpy == NULL)
> +		rte_errno = ENOMEM;
>  	return cpy;
>  }
>  
> diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
> index a3edbbe76..87caa23a1 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
> -- 
> 2.11.0
> 
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] dev: use rte_kvargs
  2018-03-26 11:38                       ` Neil Horman
@ 2018-03-26 13:59                         ` Gaëtan Rivet
  2018-03-26 15:14                           ` Wiles, Keith
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-26 13:59 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Wiles, Keith

Hi Neil,

On Mon, Mar 26, 2018 at 07:38:19AM -0400, Neil Horman wrote:
> On Fri, Mar 23, 2018 at 07:45:03PM +0100, Gaetan Rivet wrote:
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> > 
> > Cc: Neil Horman <nhorman@tuxdriver.com>
> > 

Keep in mind that all of this is to achieve the trivial task I was
doing in 20 lines or so.

> I'm actually ok with this but as Keith noted, I'm not sure why you didn't just:
> 
> 1) Add the ability to create a grouping key, so that key value pairs could
> contain a list of comma separated values (something like '{}' to denote that
> everything between the characters was the value in a kv pair, regardless of
> other tokenizing characters in the value).
> 
> 2) Add the ability to recursively parse the value into a list of tokens
> 

I don't need a recursive construct or a tree-like structure. I only need
an alternative to '\0' to signify "end-of-list".
This seems like an edge-case to librte_kvargs that would only be useful
to a specific case. It does not seem a wise addition.

So maybe I did not understand your suggestion. Can you give an example
of inputs?

I need to parse something like

"bus=pci,vendor_id=0x8086/class=eth"
(and I only care about bus=pci and class=eth).

how can grouping help? My issue is that librte_kvargs would parse

key:vendor_id
value:0x8086/class

and would then stumble on the unexpected '='.

> 3) Layer your functionality on top of (1) and (2), as Keith noted

The stack allocator seems like a nice-to-have that would interest
people using librte_kvargs. I find librte_kvargs to be cumbersome. I
cannot rewrite it from scratch, unless I update everything that relies
on it as well. So I do not touch it, because I don't care *that* much.

Why not simply leave my helper alongside? If people care enough about
it and would prefer to use it over librte_kvargs, then maybe we could
think about doing the effort of exposing it cleanly (or maybe they could).
Right now, I see only me needing it and I do not see this effort as
worth it.

Regards,
-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH 2/2] dev: use rte_kvargs
  2018-03-26 13:59                         ` Gaëtan Rivet
@ 2018-03-26 15:14                           ` Wiles, Keith
  0 siblings, 0 replies; 364+ messages in thread
From: Wiles, Keith @ 2018-03-26 15:14 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Neil Horman, dev, Wiles



> On Mar 26, 2018, at 8:59 AM, Gaëtan Rivet <gaetan.rivet@6wind.com> wrote:
> 
> Hi Neil,
> 
> On Mon, Mar 26, 2018 at 07:38:19AM -0400, Neil Horman wrote:
>> On Fri, Mar 23, 2018 at 07:45:03PM +0100, Gaetan Rivet wrote:
>>> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
>>> ---
>>> 
>>> Cc: Neil Horman <nhorman@tuxdriver.com>
>>> 
> 
> Keep in mind that all of this is to achieve the trivial task I was
> doing in 20 lines or so.
> 
>> I'm actually ok with this but as Keith noted, I'm not sure why you didn't just:
>> 
>> 1) Add the ability to create a grouping key, so that key value pairs could
>> contain a list of comma separated values (something like '{}' to denote that
>> everything between the characters was the value in a kv pair, regardless of
>> other tokenizing characters in the value).
>> 
>> 2) Add the ability to recursively parse the value into a list of tokens
>> 
> 
> I don't need a recursive construct or a tree-like structure. I only need
> an alternative to '\0' to signify "end-of-list".
> This seems like an edge-case to librte_kvargs that would only be useful
> to a specific case. It does not seem a wise addition.
> 
> So maybe I did not understand your suggestion. Can you give an example
> of inputs?
> 
> I need to parse something like
> 
> "bus=pci,vendor_id=0x8086/class=eth"
> (and I only care about bus=pci and class=eth).
> 
> how can grouping help? My issue is that librte_kvargs would parse
> 
> key:vendor_id
> value:0x8086/class
> 
> and would then stumble on the unexpected '=‘.

Let me try to remember what I did here.

Created a new list structure of top level keywords like ‘bus’, ‘class’, …
	The new list is passed into the new API that splits up the string by ‘/‘ then for each string you call into the original kvargs routines to parse the remaining items within each string. I believe I passed a function pointer in the new array of structures that allowed me to handle the top level keywords. What is passed to the top level keyword function is the string to be parsed by the normal kvargs routines. Each routine then used kvargs routines as normal. I am sure the layer could be done differently and the structure could maybe even contain the kvargs list or keywords if you want.

Anyway it worked out pretty well, just adding new APIs to handle and layer on top of kvargs APIs.

> 
>> 3) Layer your functionality on top of (1) and (2), as Keith noted
> 
> The stack allocator seems like a nice-to-have that would interest
> people using librte_kvargs. I find librte_kvargs to be cumbersome. I
> cannot rewrite it from scratch, unless I update everything that relies
> on it as well. So I do not touch it, because I don't care *that* much.
> 
> Why not simply leave my helper alongside? If people care enough about
> it and would prefer to use it over librte_kvargs, then maybe we could
> think about doing the effort of exposing it cleanly (or maybe they could).
> Right now, I see only me needing it and I do not see this effort as
> worth it.
> 
> Regards,
> -- 
> Gaëtan Rivet
> 6WIND

Regards,
Keith


^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 00/20] Device querying
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
                     ` (18 preceding siblings ...)
  2018-03-22 11:31   ` [dpdk-dev] [PATCH v2 00/18] Device querying Bruce Richardson
@ 2018-03-26 23:18   ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 01/20] kvargs: remove rte log dependency Gaetan Rivet
                       ` (20 more replies)
  19 siblings, 21 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Bruce Richardson

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.

Cc: Bruce Richardson <bruce.richardson@intel.com>
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

Gaetan Rivet (20):
  kvargs: remove rte log dependency
  kvargs: build before EAL
  eal: list acceptable init priorities
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  bus/pci: fix find device implementation
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: fix find device implementation
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                             |  52 ++++
 drivers/bus/pci/Makefile                           |   2 +-
 drivers/bus/pci/pci_common.c                       |  77 ++++-
 drivers/bus/pci/rte_bus_pci.h                      |   3 +
 drivers/bus/vdev/Makefile                          |   2 +-
 drivers/bus/vdev/rte_bus_vdev.h                    |   3 +
 drivers/bus/vdev/vdev.c                            |  66 ++++-
 lib/Makefile                                       |   6 +-
 lib/librte_eal/bsdapp/eal/Makefile                 |   2 +
 lib/librte_eal/common/Makefile                     |   4 +-
 lib/librte_eal/common/eal_common_class.c           |  62 ++++
 lib/librte_eal/common/eal_common_dev.c             | 317 +++++++++++++++++++++
 lib/librte_eal/common/eal_common_log.c             |   2 +-
 lib/librte_eal/common/include/rte_bus.h            |   3 +-
 lib/librte_eal/common/include/rte_class.h          | 127 +++++++++
 lib/librte_eal/common/include/rte_common.h         |  32 ++-
 lib/librte_eal/common/include/rte_dev.h            |  95 ++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   2 +
 lib/librte_eal/rte_eal_version.map                 |   4 +
 lib/librte_ether/Makefile                          |   3 +-
 lib/librte_ether/rte_class_eth.c                   |  79 +++++
 lib/librte_kvargs/Makefile                         |   2 +-
 lib/librte_kvargs/rte_kvargs.c                     |  13 +-
 .../include => librte_kvargs}/rte_string_fns.h     |   0
 24 files changed, 925 insertions(+), 33 deletions(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ether/rte_class_eth.c
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 01/20] kvargs: remove rte log dependency
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-27 18:19       ` Neil Horman
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 02/20] kvargs: build before EAL Gaetan Rivet
                       ` (19 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_kvargs/rte_kvargs.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 9662375e8..d6b187aac 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -3,10 +3,10 @@
  * Copyright(c) 2014 6WIND S.A.
  */
 
+#include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
 
-#include <rte_log.h>
 #include <rte_string_fns.h>
 
 #include "rte_kvargs.h"
@@ -29,7 +29,7 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
 	 */
 	kvlist->str = strdup(params);
 	if (kvlist->str == NULL) {
-		RTE_LOG(ERR, PMD, "Cannot parse arguments: not enough memory\n");
+		fprintf(stderr, "Cannot parse arguments: not enough memory\n");
 		return -1;
 	}
 
@@ -39,14 +39,14 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
 
 		i = kvlist->count;
 		if (i >= RTE_KVARGS_MAX) {
-			RTE_LOG(ERR, PMD, "Cannot parse arguments: list full\n");
+			fprintf(stderr, "Cannot parse arguments: list full\n");
 			return -1;
 		}
 
 		kvlist->pairs[i].key = strtok_r(str, RTE_KVARGS_KV_DELIM, &ctx2);
 		kvlist->pairs[i].value = strtok_r(NULL, RTE_KVARGS_KV_DELIM, &ctx2);
 		if (kvlist->pairs[i].key == NULL || kvlist->pairs[i].value == NULL) {
-			RTE_LOG(ERR, PMD,
+			fprintf(stderr,
 				"Cannot parse arguments: wrong key or value\n"
 				"params=<%s>\n", params);
 			return -1;
@@ -90,7 +90,7 @@ check_for_valid_keys(struct rte_kvargs *kvlist,
 		pair = &kvlist->pairs[i];
 		ret = is_valid_key(valid, pair->key);
 		if (!ret) {
-			RTE_LOG(ERR, PMD,
+			fprintf(stderr,
 				"Error parsing device, invalid key <%s>\n",
 				pair->key);
 			return -1;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 02/20] kvargs: build before EAL
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 01/20] kvargs: remove rte log dependency Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-27  9:12       ` Bruce Richardson
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init priorities Gaetan Rivet
                       ` (18 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                                                      | 3 +--
 lib/librte_eal/common/Makefile                                    | 2 +-
 lib/librte_kvargs/Makefile                                        | 2 +-
 lib/librte_kvargs/rte_kvargs.c                                    | 3 +--
 lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
 5 files changed, 4 insertions(+), 6 deletions(-)
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a606..fc7a55a37 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -71,8 +72,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index ea824a3a8..75776d3e2 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -9,7 +9,7 @@ INC += rte_errno.h rte_launch.h rte_lcore.h
 INC += rte_log.h rte_memory.h rte_memzone.h
 INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
+INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 4eaa9334d..43e28fc53 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -37,7 +37,6 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
 
 EXPORT_MAP := rte_kvargs_version.map
 
@@ -48,6 +47,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c
 
 # install includes
 INCS := rte_kvargs.h
+INCS += rte_string_fns.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS)
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d6b187aac..e73a5c6c1 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -7,8 +7,7 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include <rte_string_fns.h>
-
+#include "rte_string_fns.h"
 #include "rte_kvargs.h"
 
 /*
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_kvargs/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_kvargs/rte_string_fns.h
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init priorities
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 01/20] kvargs: remove rte log dependency Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 02/20] kvargs: build before EAL Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-27  7:18       ` Shreyansh Jain
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 04/20] eal: introduce dtor macros Gaetan Rivet
                       ` (17 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Build a central list to quickly see each used priorities for
constructors, allowing to verify that they are both above 100 and in the
proper order.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
---
 lib/librte_eal/common/eal_common_log.c     | 2 +-
 lib/librte_eal/common/include/rte_bus.h    | 2 +-
 lib/librte_eal/common/include/rte_common.h | 8 +++++++-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index 37b2e20e5..b384c72d3 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = {
 };
 
 /* Logging should be first initializer (before drivers and bus) */
-RTE_INIT_PRIO(rte_log_init, 101);
+RTE_INIT_PRIO(rte_log_init, LOG);
 static void
 rte_log_init(void)
 {
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 6fb08341a..eb9eded4e 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
  * The constructor has higher priority than PMD constructors.
  */
 #define RTE_REGISTER_BUS(nm, bus) \
-RTE_INIT_PRIO(businitfn_ ##nm, 110); \
+RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
 static void businitfn_ ##nm(void) \
 {\
 	(bus).name = RTE_STR(nm);\
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index c7803e41c..99a799d6d 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
  */
 #define RTE_SET_USED(x) (void)(x)
 
+#define RTE_PRIORITY_LOG 101
+#define RTE_PRIORITY_BUS 110
+
+#define RTE_PRIO(prio) \
+	RTE_PRIORITY_ ## prio
+
 /**
  * Run function before main() with low priority.
  *
@@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
  *   Lowest number is the first to run.
  */
 #define RTE_INIT_PRIO(func, prio) \
-static void __attribute__((constructor(prio), used)) func(void)
+static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
  * Force a function to be inlined
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 04/20] eal: introduce dtor macros
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (2 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init priorities Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 05/20] eal: introduce device class abstraction Gaetan Rivet
                       ` (16 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 99a799d6d..bdccc2553 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -111,6 +111,29 @@ static void __attribute__((constructor, used)) func(void)
 static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+static void __attribute__((destructor, used)) func(void)
+
+/**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 05/20] eal: introduce device class abstraction
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (3 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 04/20] eal: introduce dtor macros Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-27  8:38       ` Shreyansh Jain
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 06/20] eal/class: register destructor Gaetan Rivet
                       ` (15 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 7 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index dd455e671..17ff1ac45 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 75776d3e2..607ae0447 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..59b578e3e
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_bus structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index bdccc2553..d8ee35e2d 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 
 #define RTE_PRIO(prio) \
 	RTE_PRIORITY_ ## prio
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7e5bbe889..a3edbbe76 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index d12360235..910cb23c9 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -215,6 +215,8 @@ EXPERIMENTAL {
 	global:
 
 	rte_eal_cleanup;
+	rte_class_register;
+	rte_class_unregister;
 	rte_eal_devargs_insert;
 	rte_eal_devargs_parse;
 	rte_eal_devargs_remove;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 06/20] eal/class: register destructor
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (4 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 05/20] eal: introduce device class abstraction Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-27  8:42       ` Shreyansh Jain
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 07/20] eal/dev: add device iterator interface Gaetan Rivet
                       ` (14 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index 59b578e3e..95107d937 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 07/20] eal/dev: add device iterator interface
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (5 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 06/20] eal/class: register destructor Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 08/20] eal/class: add device iteration Gaetan Rivet
                       ` (13 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index b688f1efd..937ff6079 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -263,6 +263,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 08/20] eal/class: add device iteration
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (6 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 07/20] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 09/20] eal/bus: " Gaetan Rivet
                       ` (12 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index 95107d937..6cce99925 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 09/20] eal/bus: add device iteration
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (7 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 08/20] eal/class: add device iteration Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization Gaetan Rivet
                       ` (11 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (8 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 09/20] eal/bus: " Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-27 11:47       ` Neil Horman
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 11/20] eal/dev: implement device iteration Gaetan Rivet
                       ` (10 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman, Wiles, Keith

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

Cc: Neil Horman <nhorman@tuxdriver.com>
Cc: "Wiles, Keith" <keith.wiles@intel.com>
Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---

This version uses librte_kvargs.

 lib/Makefile                            |   1 +
 lib/librte_eal/bsdapp/eal/Makefile      |   1 +
 lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  23 +++++
 lib/librte_eal/linuxapp/eal/Makefile    |   1 +
 lib/librte_eal/rte_eal_version.map      |   1 +
 6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
+}
+
+int __rte_experimental
+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..7ce13e068 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -310,6 +310,29 @@ 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.
+ */
+int __rte_experimental
+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 a3edbbe76..87caa23a1 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 910cb23c9..921da3075 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -228,6 +228,7 @@ EXPERIMENTAL {
 	rte_mp_sendmsg;
 	rte_mp_request;
 	rte_mp_reply;
+	rte_dev_iterator_init;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 11/20] eal/dev: implement device iteration
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (9 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 12/20] bus/pci: fix find device implementation Gaetan Rivet
                       ` (9 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 170 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  25 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 196 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 1f6df2351..604e01940 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -20,6 +20,28 @@
 
 #include "eal_private.h"
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -354,3 +376,151 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 	}
 	return -rte_errno;
 }
+
+/* '\0' forbidden in sym */
+static const char *
+strfirstof(const char *str,
+	   const char *sym)
+{
+	const char *s;
+
+	for (s = str; s[0] != '\0'; s++) {
+		const char *c;
+
+		for (c = sym; c[0] != '\0'; c++) {
+			if (c[0] == s[0])
+				return s;
+		}
+	}
+	return NULL;
+}
+
+static char *
+dev_str_sane_cpy(const char *str)
+{
+	const char *end;
+	char *copy;
+
+	end = strfirstof(str, ",/");
+	if (end != NULL &&
+	    end[0] == ',') {
+		copy = strdup(end + 1);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL)
+		rte_errno = ENOMEM;
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_cpy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_cpy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 7ce13e068..dfb5d696f 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -333,6 +333,31 @@ typedef void *(*rte_dev_iterate_t)(const void *start,
 int __rte_experimental
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+struct rte_device * __rte_experimental
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 921da3075..925efcb6d 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	rte_mp_request;
 	rte_mp_reply;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 12/20] bus/pci: fix find device implementation
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (10 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 11/20] eal/dev: implement device iteration Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 13/20] bus/pci: implement device iteration and comparison Gaetan Rivet
                       ` (8 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set, and a device before it matches the data
passed for comparison, then this first device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2a00f365a..2c45f8151 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -459,17 +459,20 @@ static struct rte_device *
 pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		const void *data)
 {
-	struct rte_pci_device *dev;
+	const struct rte_pci_device *pstart;
+	struct rte_pci_device *pdev;
 
-	FOREACH_DEVICE_ON_PCIBUS(dev) {
-		if (start && &dev->device == start) {
-			start = NULL; /* starting point found */
-			continue;
-		}
-		if (cmp(&dev->device, data) == 0)
-			return &dev->device;
+	if (start != NULL) {
+		pstart = RTE_DEV_TO_PCI_CONST(start);
+		pdev = TAILQ_NEXT(pstart, next);
+	} else {
+		pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
+	}
+	while (pdev != NULL) {
+		if (cmp(&pdev->device, data) == 0)
+			return &pdev->device;
+		pdev = TAILQ_NEXT(pdev, next);
 	}
-
 	return NULL;
 }
 
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 357afb912..458e6d076 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -74,6 +74,9 @@ struct rte_pci_device {
  */
 #define RTE_DEV_TO_PCI(ptr) container_of(ptr, struct rte_pci_device, device)
 
+#define RTE_DEV_TO_PCI_CONST(ptr) \
+	container_of(ptr, const struct rte_pci_device, device)
+
 #define RTE_ETH_DEV_TO_PCI(eth_dev)	RTE_DEV_TO_PCI((eth_dev)->device)
 
 /** Any PCI device identifier (vendor, device, ...) */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 13/20] bus/pci: implement device iteration and comparison
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (11 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 12/20] bus/pci: fix find device implementation Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 14/20] bus/pci: add device matching field id Gaetan Rivet
                       ` (7 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index f3df1c4ce..73498dc77 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -50,7 +50,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
 CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2c45f8151..59a776305 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -13,6 +13,7 @@
 
 #include <rte_errno.h>
 #include <rte_interrupts.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
@@ -497,6 +498,38 @@ pci_unplug(struct rte_device *dev)
 	return ret;
 }
 
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+static void *
+pci_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_device *dev;
+	struct rte_kvargs *kvargs = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = pci_find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 struct rte_pci_bus rte_pci_bus = {
 	.bus = {
 		.scan = rte_pci_scan,
@@ -506,6 +539,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 14/20] bus/pci: add device matching field id
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (12 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 13/20] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 15/20] bus/vdev: fix find device implementation Gaetan Rivet
                       ` (6 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c | 26 ++++++++++++++++++++++++--
 1 file changed, 24 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 59a776305..af5b48287 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -499,13 +499,35 @@ pci_unplug(struct rte_device *dev)
 }
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return rte_pci_addr_cmp(addr1, addr2);
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 15/20] bus/vdev: fix find device implementation
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (13 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 14/20] bus/pci: add device matching field id Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 16/20] bus/vdev: implement device iteration Gaetan Rivet
                       ` (5 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set and a device before it matches the data,
this device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/vdev/rte_bus_vdev.h b/drivers/bus/vdev/rte_bus_vdev.h
index f9d8a2383..4da9967c6 100644
--- a/drivers/bus/vdev/rte_bus_vdev.h
+++ b/drivers/bus/vdev/rte_bus_vdev.h
@@ -53,6 +53,9 @@ struct rte_vdev_device {
 #define RTE_DEV_TO_VDEV(ptr) \
 	container_of(ptr, struct rte_vdev_device, device)
 
+#define RTE_DEV_TO_VDEV_CONST(ptr) \
+	container_of(ptr, const struct rte_vdev_device, device)
+
 static inline const char *
 rte_vdev_device_name(const struct rte_vdev_device *dev)
 {
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index e4bc72463..68306f4eb 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -386,15 +386,19 @@ static struct rte_device *
 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		 const void *data)
 {
+	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
 
-	TAILQ_FOREACH(dev, &vdev_device_list, next) {
-		if (start && &dev->device == start) {
-			start = NULL;
-			continue;
-		}
+	if (start != NULL) {
+		vstart = RTE_DEV_TO_VDEV_CONST(start);
+		dev = TAILQ_NEXT(vstart, next);
+	} else {
+		dev = TAILQ_FIRST(&vdev_device_list);
+	}
+	while (dev != NULL) {
 		if (cmp(&dev->device, data) == 0)
 			return &dev->device;
+		dev = TAILQ_NEXT(dev, next);
 	}
 	return NULL;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 16/20] bus/vdev: implement device iteration
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (14 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 15/20] bus/vdev: fix find device implementation Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 17/20] bus/vdev: add device matching field driver Gaetan Rivet
                       ` (4 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 34 ++++++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 24d424a38..52728833c 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 68306f4eb..699ce01e6 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -43,6 +43,7 @@
 #include <rte_bus.h>
 #include <rte_common.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
 #include <rte_memory.h>
 #include <rte_tailq.h>
 #include <rte_spinlock.h>
@@ -415,6 +416,38 @@ vdev_unplug(struct rte_device *dev)
 	return rte_vdev_uninit(dev->name);
 }
 
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+static void *
+vdev_dev_iterate(const void *start,
+		 const char *str,
+		 const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
@@ -422,6 +455,7 @@ static struct rte_bus rte_vdev_bus = {
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 17/20] bus/vdev: add device matching field driver
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (15 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 16/20] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 18/20] ethdev: register ether layer as a class Gaetan Rivet
                       ` (3 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 699ce01e6..d1e712fe9 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -417,13 +417,31 @@ vdev_unplug(struct rte_device *dev)
 }
 
 static int
+vdev_str_kv_cmp(const char *key __rte_unused,
+	     const char *value,
+	     void *_str)
+{
+	const  char *str = _str;
+
+	return strcmp(str, value);
+}
+
+static int
 vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		&vdev_str_kv_cmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 18/20] ethdev: register ether layer as a class
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (16 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 17/20] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 19/20] ethdev: add device matching field name Gaetan Rivet
                       ` (2 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                     |  2 +-
 lib/librte_ether/Makefile        |  3 +-
 lib/librte_ether/rte_class_eth.c | 65 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_ether/rte_class_eth.c

diff --git a/lib/Makefile b/lib/Makefile
index 1b17526f7..b291dd2cd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -22,7 +22,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf
+DEPDIRS-librte_ether += librte_mbuf librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 3ca5782bb..a1a0393de 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 8
 
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
new file mode 100644
index 000000000..3f1537c2a
--- /dev/null
+++ b/lib/librte_ether/rte_class_eth.c
@@ -0,0 +1,65 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+
+static int
+eth_dev_match(struct rte_eth_dev *edev,
+	      struct rte_kvargs *kvlist)
+{
+	(void) kvlist;
+	(void) edev;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *_start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	const struct rte_eth_dev *start = _start;
+	struct rte_device *dev = it->device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+	uint16_t p = 0;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, NULL);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	if (start)
+		p = start->data->port_id + 1;
+	for (p = rte_eth_find_next(p);
+	     p < RTE_MAX_ETHPORTS;
+	     p = rte_eth_find_next(p + 1)) {
+		edev = &rte_eth_devices[p];
+		if (dev != edev->device)
+			goto next_ethdev;
+		if (eth_dev_match(edev, kvargs) == 0)
+			break;
+next_ethdev:
+		edev = NULL;
+	}
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 19/20] ethdev: add device matching field name
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (17 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 18/20] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 20/20] app/testpmd: add show device command Gaetan Rivet
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/rte_class_eth.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
index 3f1537c2a..08f2b43cb 100644
--- a/lib/librte_ether/rte_class_eth.c
+++ b/lib/librte_ether/rte_class_eth.c
@@ -14,11 +14,25 @@
 #include "rte_ethdev_core.h"
 
 static int
+eth_dev_str_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_str)
+{
+	const char *str = _str;
+
+	return strcmp(str, value);
+}
+
+static int
 eth_dev_match(struct rte_eth_dev *edev,
 	      struct rte_kvargs *kvlist)
 {
-	(void) kvlist;
-	(void) edev;
+	struct rte_eth_dev_data *data;
+
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			&eth_dev_str_cmp, data->name))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v3 20/20] app/testpmd: add show device command
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (18 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 19/20] ethdev: add device matching field name Gaetan Rivet
@ 2018-03-26 23:18     ` Gaetan Rivet
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-26 23:18 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..8ac5fb3ca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device "
+		"<device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init priorities
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init priorities Gaetan Rivet
@ 2018-03-27  7:18       ` Shreyansh Jain
  0 siblings, 0 replies; 364+ messages in thread
From: Shreyansh Jain @ 2018-03-27  7:18 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> Sent: Tuesday, March 27, 2018 4:48 AM
> To: dev@dpdk.org
> Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> Subject: [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init
> priorities
> 
> Build a central list to quickly see each used priorities for
> constructors, allowing to verify that they are both above 100 and in the
> proper order.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> Acked-by: Neil Horman <nhorman@tuxdriver.com>
> ---

Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 05/20] eal: introduce device class abstraction
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 05/20] eal: introduce device class abstraction Gaetan Rivet
@ 2018-03-27  8:38       ` Shreyansh Jain
  2018-03-27  9:51         ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Shreyansh Jain @ 2018-03-27  8:38 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On 3/27/2018 4:48 AM, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>   lib/librte_eal/bsdapp/eal/Makefile         |   1 +
>   lib/librte_eal/common/Makefile             |   2 +-
>   lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
>   lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
>   lib/librte_eal/common/include/rte_common.h |   1 +
>   lib/librte_eal/linuxapp/eal/Makefile       |   1 +
>   lib/librte_eal/rte_eal_version.map         |   2 +
>   7 files changed, 189 insertions(+), 1 deletion(-)
>   create mode 100644 lib/librte_eal/common/eal_common_class.c
>   create mode 100644 lib/librte_eal/common/include/rte_class.h
> 

[...]

> +
> +/**
> + * Class iterator to find a particular class.
> + *
> + * This function compares each registered class to find one that matches
> + * the data passed as parameter.
> + *
> + * If the comparison function returns zero this function will stop iterating
> + * over any more classes. To continue a search the class of a previous search
> + * can be passed via the start parameter.
> + *
> + * @param start
> + *	Starting point for the iteration.
> + *
> + * @param cmp
> + *	Comparison function.
> + *
> + * @param data
> + *	 Data to pass to comparison function.
> + *
> + * @return
> + *	 A pointer to a rte_bus structure or NULL in case no class matches

Trivial:               ^^^^^^^^
                 Should be rte_class

[...]

-
Shreyansh

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 06/20] eal/class: register destructor
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 06/20] eal/class: register destructor Gaetan Rivet
@ 2018-03-27  8:42       ` Shreyansh Jain
  2018-03-27  8:49         ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Shreyansh Jain @ 2018-03-27  8:42 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On 3/27/2018 4:48 AM, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>   lib/librte_eal/common/include/rte_class.h | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
> index 59b578e3e..95107d937 100644
> --- a/lib/librte_eal/common/include/rte_class.h
> +++ b/lib/librte_eal/common/include/rte_class.h
> @@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
>   {\
>   	(cls).name = RTE_STR(nm);\
>   	rte_class_register(&cls); \
> +} \
> +RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
> +static void classfinifn_ ##nm(void) \
> +{ \
> +	rte_class_unregister(&cls); \
>   }
>   
>   #ifdef __cplusplus
> 

I think this can be merged with the Patch 05/20 - isn't it?

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 06/20] eal/class: register destructor
  2018-03-27  8:42       ` Shreyansh Jain
@ 2018-03-27  8:49         ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27  8:49 UTC (permalink / raw)
  To: Shreyansh Jain; +Cc: dev

Hi Shreyansh,

On Tue, Mar 27, 2018 at 02:12:51PM +0530, Shreyansh Jain wrote:
> On 3/27/2018 4:48 AM, Gaetan Rivet wrote:
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >   lib/librte_eal/common/include/rte_class.h | 5 +++++
> >   1 file changed, 5 insertions(+)
> > 
> > diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
> > index 59b578e3e..95107d937 100644
> > --- a/lib/librte_eal/common/include/rte_class.h
> > +++ b/lib/librte_eal/common/include/rte_class.h
> > @@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
> >   {\
> >   	(cls).name = RTE_STR(nm);\
> >   	rte_class_register(&cls); \
> > +} \
> > +RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
> > +static void classfinifn_ ##nm(void) \
> > +{ \
> > +	rte_class_unregister(&cls); \
> >   }
> >   #ifdef __cplusplus
> > 
> 
> I think this can be merged with the Patch 05/20 - isn't it?

Absolutely, I only separated it as I wasn't sure for the dtor patch
itself.

If the dtors are accepted, this patch can be merged with the previous
patch.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 02/20] kvargs: build before EAL
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 02/20] kvargs: build before EAL Gaetan Rivet
@ 2018-03-27  9:12       ` Bruce Richardson
  2018-03-27  9:53         ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Bruce Richardson @ 2018-03-27  9:12 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Tue, Mar 27, 2018 at 01:18:26AM +0200, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/Makefile                                                      | 3 +--
>  lib/librte_eal/common/Makefile                                    | 2 +-
>  lib/librte_kvargs/Makefile                                        | 2 +-
>  lib/librte_kvargs/rte_kvargs.c                                    | 3 +--
>  lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
>  5 files changed, 4 insertions(+), 6 deletions(-)
>  rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)
> 
Don't forget to update the meson.build file. You need to move kvargs before
EAL in the list of libraries, and modify the special case for
default dependencies for non-EAL libs.

/Bruce

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 05/20] eal: introduce device class abstraction
  2018-03-27  8:38       ` Shreyansh Jain
@ 2018-03-27  9:51         ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27  9:51 UTC (permalink / raw)
  To: Shreyansh Jain; +Cc: dev

On Tue, Mar 27, 2018 at 02:08:31PM +0530, Shreyansh Jain wrote:
> On 3/27/2018 4:48 AM, Gaetan Rivet wrote:
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >   lib/librte_eal/bsdapp/eal/Makefile         |   1 +
> >   lib/librte_eal/common/Makefile             |   2 +-
> >   lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
> >   lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
> >   lib/librte_eal/common/include/rte_common.h |   1 +
> >   lib/librte_eal/linuxapp/eal/Makefile       |   1 +
> >   lib/librte_eal/rte_eal_version.map         |   2 +
> >   7 files changed, 189 insertions(+), 1 deletion(-)
> >   create mode 100644 lib/librte_eal/common/eal_common_class.c
> >   create mode 100644 lib/librte_eal/common/include/rte_class.h
> > 
> 
> [...]
> 
> > +
> > +/**
> > + * Class iterator to find a particular class.
> > + *
> > + * This function compares each registered class to find one that matches
> > + * the data passed as parameter.
> > + *
> > + * If the comparison function returns zero this function will stop iterating
> > + * over any more classes. To continue a search the class of a previous search
> > + * can be passed via the start parameter.
> > + *
> > + * @param start
> > + *	Starting point for the iteration.
> > + *
> > + * @param cmp
> > + *	Comparison function.
> > + *
> > + * @param data
> > + *	 Data to pass to comparison function.
> > + *
> > + * @return
> > + *	 A pointer to a rte_bus structure or NULL in case no class matches
> 
> Trivial:               ^^^^^^^^
>                 Should be rte_class

Thanks, will fix.

> 
> [...]
> 
> -
> Shreyansh

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 02/20] kvargs: build before EAL
  2018-03-27  9:12       ` Bruce Richardson
@ 2018-03-27  9:53         ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27  9:53 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: dev

On Tue, Mar 27, 2018 at 10:12:20AM +0100, Bruce Richardson wrote:
> On Tue, Mar 27, 2018 at 01:18:26AM +0200, Gaetan Rivet wrote:
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >  lib/Makefile                                                      | 3 +--
> >  lib/librte_eal/common/Makefile                                    | 2 +-
> >  lib/librte_kvargs/Makefile                                        | 2 +-
> >  lib/librte_kvargs/rte_kvargs.c                                    | 3 +--
> >  lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
> >  5 files changed, 4 insertions(+), 6 deletions(-)
> >  rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)
> > 
> Don't forget to update the meson.build file. You need to move kvargs before
> EAL in the list of libraries, and modify the special case for
> default dependencies for non-EAL libs.
> 
> /Bruce

Sure, I will tackle meson build once everything is a little more stable.

I'm not at all convinced by this librte_kvargs move, these two patches
are verging on RFC.

Once I know where everything will be, I will complete the build support.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-03-27 11:47       ` Neil Horman
  2018-03-27 12:40         ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-27 11:47 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> Parse a device description.
> Split this description in their relevant part for each layers.
> No dynamic allocation is performed.
> 
> Cc: Neil Horman <nhorman@tuxdriver.com>
> Cc: "Wiles, Keith" <keith.wiles@intel.com>
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
> 
> This version uses librte_kvargs.
> 
>  lib/Makefile                            |   1 +
>  lib/librte_eal/bsdapp/eal/Makefile      |   1 +
>  lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
>  lib/librte_eal/common/include/rte_dev.h |  23 +++++
>  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
>  lib/librte_eal/rte_eal_version.map      |   1 +
>  6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> +}
> +
So the above code really just counts the number characters in the string,
omitting the delimiter character '/', right?  If thats all you want to do, you can just
use strtok and strnlen for that, cant you?

Otherwise, this looks pretty good to me
Neil

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 11:47       ` Neil Horman
@ 2018-03-27 12:40         ` Gaëtan Rivet
  2018-03-27 13:04           ` Gaëtan Rivet
                             ` (2 more replies)
  0 siblings, 3 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27 12:40 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > Parse a device description.
> > Split this description in their relevant part for each layers.
> > No dynamic allocation is performed.
> > 
> > Cc: Neil Horman <nhorman@tuxdriver.com>
> > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> > 
> > This version uses librte_kvargs.
> > 
> >  lib/Makefile                            |   1 +
> >  lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> >  lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> >  lib/librte_eal/common/include/rte_dev.h |  23 +++++
> >  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> >  lib/librte_eal/rte_eal_version.map      |   1 +
> >  6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> > +}
> > +
> So the above code really just counts the number characters in the string,
> omitting the delimiter character '/', right?  If thats all you want to do, you can just
> use strtok and strnlen for that, cant you?

Will do.

> 
> Otherwise, this looks pretty good to me

Please look into the librte_kvargs compatibility patch as well (quite
short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer on rte_log
with the proper loglevels and so on.
Ideally rte_log could be made independent (starting skimming EAL from
all the fat), but this is much less trivial.

This implementation relies on librte_kvargs being available. If this is
not the case, there isn't much point to it.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 12:40         ` Gaëtan Rivet
@ 2018-03-27 13:04           ` Gaëtan Rivet
  2018-03-27 20:23             ` Gaëtan Rivet
  2018-03-27 13:08           ` Wiles, Keith
  2018-03-27 18:26           ` Neil Horman
  2 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27 13:04 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > Parse a device description.
> > > Split this description in their relevant part for each layers.
> > > No dynamic allocation is performed.
> > > 
> > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > ---
> > > 
> > > This version uses librte_kvargs.
> > > 
> > >  lib/Makefile                            |   1 +
> > >  lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> > >  lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> > >  lib/librte_eal/common/include/rte_dev.h |  23 +++++
> > >  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> > >  lib/librte_eal/rte_eal_version.map      |   1 +
> > >  6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> > > +}
> > > +
> > So the above code really just counts the number characters in the string,
> > omitting the delimiter character '/', right?  If thats all you want to do, you can just
> > use strtok and strnlen for that, cant you?
> 
> Will do.
> 

Answered too quickly.
No, this function only counts the number of occurences of '/' in the
text.

strtok could be used however in the main function.
Will see for a simpler implementation using it.

> > 
> > Otherwise, this looks pretty good to me
> 
> Please look into the librte_kvargs compatibility patch as well (quite
> short). I'm very unhappy about the logging hack.
> There is always the solution of setting a function pointer on rte_log
> with the proper loglevels and so on.
> Ideally rte_log could be made independent (starting skimming EAL from
> all the fat), but this is much less trivial.
> 
> This implementation relies on librte_kvargs being available. If this is
> not the case, there isn't much point to it.
> 
> -- 
> Gaëtan Rivet
> 6WIND

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 12:40         ` Gaëtan Rivet
  2018-03-27 13:04           ` Gaëtan Rivet
@ 2018-03-27 13:08           ` Wiles, Keith
  2018-03-27 18:26           ` Neil Horman
  2 siblings, 0 replies; 364+ messages in thread
From: Wiles, Keith @ 2018-03-27 13:08 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Neil Horman, dev



> On Mar 27, 2018, at 7:40 AM, Gaëtan Rivet <gaetan.rivet@6wind.com> wrote:
> 
> On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
>> On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
>>> Parse a device description.
>>> Split this description in their relevant part for each layers.
>>> No dynamic allocation is performed.
>>> 
>>> Cc: Neil Horman <nhorman@tuxdriver.com>
>>> Cc: "Wiles, Keith" <keith.wiles@intel.com>
>>> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
>>> ---
>>> 
>>> This version uses librte_kvargs.
>>> 
>>> lib/Makefile                            |   1 +
>>> lib/librte_eal/bsdapp/eal/Makefile      |   1 +
>>> lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
>>> lib/librte_eal/common/include/rte_dev.h |  23 +++++
>>> lib/librte_eal/linuxapp/eal/Makefile    |   1 +
>>> lib/librte_eal/rte_eal_version.map      |   1 +
>>> 6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
>>> +}
>>> +
>> So the above code really just counts the number characters in the string,
>> omitting the delimiter character '/', right?  If thats all you want to do, you can just
>> use strtok and strnlen for that, cant you?
> 
> Will do.
> 
>> 
>> Otherwise, this looks pretty good to me
> 
> Please look into the librte_kvargs compatibility patch as well (quite
> short). I'm very unhappy about the logging hack.
> There is always the solution of setting a function pointer on rte_log
> with the proper loglevels and so on.
> Ideally rte_log could be made independent (starting skimming EAL from
> all the fat), but this is much less trivial.

I thought RTE_LOG was setup correctly using defaults, some changes after I looked at must have changed that behavior I guess. That needs to be address at some point IMO, but not in this patch set.

> 
> This implementation relies on librte_kvargs being available. If this is
> not the case, there isn't much point to it.

Looked at the kvargs change and does look correct, but the above needs to be addressed or it will not be logged for normal usage of kvargs. I would have expected RTE_LOG to be able to handle the case of being called before it is inited and just use stderr. It needs to be looked at.

> 
> -- 
> Gaëtan Rivet
> 6WIND

Regards,
Keith


^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 01/20] kvargs: remove rte log dependency
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 01/20] kvargs: remove rte log dependency Gaetan Rivet
@ 2018-03-27 18:19       ` Neil Horman
  0 siblings, 0 replies; 364+ messages in thread
From: Neil Horman @ 2018-03-27 18:19 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Tue, Mar 27, 2018 at 01:18:25AM +0200, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/librte_kvargs/rte_kvargs.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
> index 9662375e8..d6b187aac 100644
> --- a/lib/librte_kvargs/rte_kvargs.c
> +++ b/lib/librte_kvargs/rte_kvargs.c
> @@ -3,10 +3,10 @@
>   * Copyright(c) 2014 6WIND S.A.
>   */
>  
> +#include <stdio.h>
>  #include <string.h>
>  #include <stdlib.h>
>  
> -#include <rte_log.h>
>  #include <rte_string_fns.h>
>  
>  #include "rte_kvargs.h"
> @@ -29,7 +29,7 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
>  	 */
>  	kvlist->str = strdup(params);
>  	if (kvlist->str == NULL) {
> -		RTE_LOG(ERR, PMD, "Cannot parse arguments: not enough memory\n");
> +		fprintf(stderr, "Cannot parse arguments: not enough memory\n");
>  		return -1;
>  	}
>  
I'm not entirely sure why any of this is needed.  RTE_LOG is basically a wrapper
around rte_vlog, which has this block of code:

if (f == NULL) {
                f = default_log_stream;
                if (f == NULL) {
                        /*
                         * Grab the current value of stderr here, rather than
                         * just initializing default_log_stream to stderr. This
                         * ensures that we will always use the current value
                         * of stderr, even if the application closes and
                         * reopens it.
                         */
                        f = stderr;
                }
        }
}

It seems to me that if rte_log_openstream hasn't been called yet, we should just
dump messages to stderr, just like Keith noted in his other email.  If thats not
working, thats definately a problem, but regardless, you should be able to use
RTE_LOG in your code without issue.

Neil

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 12:40         ` Gaëtan Rivet
  2018-03-27 13:04           ` Gaëtan Rivet
  2018-03-27 13:08           ` Wiles, Keith
@ 2018-03-27 18:26           ` Neil Horman
  2018-03-27 20:20             ` Gaëtan Rivet
  2 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-27 18:26 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > Parse a device description.
> > > Split this description in their relevant part for each layers.
> > > No dynamic allocation is performed.
> > > 
> > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > ---
> > > 
> > > This version uses librte_kvargs.
> > > 
> > >  lib/Makefile                            |   1 +
> > >  lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> > >  lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> > >  lib/librte_eal/common/include/rte_dev.h |  23 +++++
> > >  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> > >  lib/librte_eal/rte_eal_version.map      |   1 +
> > >  6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> > > +}
> > > +
> > So the above code really just counts the number characters in the string,
> > omitting the delimiter character '/', right?  If thats all you want to do, you can just
> > use strtok and strnlen for that, cant you?
> 
> Will do.
> 
> > 
> > Otherwise, this looks pretty good to me
> 
> Please look into the librte_kvargs compatibility patch as well (quite
> short). I'm very unhappy about the logging hack.
> There is always the solution of setting a function pointer on rte_log
> with the proper loglevels and so on.
> Ideally rte_log could be made independent (starting skimming EAL from
> all the fat), but this is much less trivial.
> 
just posted about that.  I agree with Keith, I don't think you should need that
patch.  RTE_LOG just calls rte_vlog which contains this code:

if (f == NULL) {
                f = default_log_stream;
                if (f == NULL) {
                        /*
                         * Grab the current value of stderr here, rather than
                         * just initializing default_log_stream to stderr. This
                         * ensures that we will always use the current value
                         * of stderr, even if the application closes and
                         * reopens it.
                         */
                        f = stderr;
                }
        }
}

Which I read as saying that the logging library should back off to stderr if its
not initialized yet.  If you've encountered a problem that made you need that
logging patch, it seems like you should be able to drop it, and we need to fix
the logging library.  Can you elaborate on what you ran into here?

Neil

> This implementation relies on librte_kvargs being available. If this is
> not the case, there isn't much point to it.
> 
> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 18:26           ` Neil Horman
@ 2018-03-27 20:20             ` Gaëtan Rivet
  2018-03-27 20:28               ` Bruce Richardson
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27 20:20 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 02:26:33PM -0400, Neil Horman wrote:
> On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > Parse a device description.
> > > > Split this description in their relevant part for each layers.
> > > > No dynamic allocation is performed.
> > > > 
> > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > ---
> > > > 
> > > > This version uses librte_kvargs.
> > > > 
> > > 
> > > Otherwise, this looks pretty good to me
> > 
> > Please look into the librte_kvargs compatibility patch as well (quite
> > short). I'm very unhappy about the logging hack.
> > There is always the solution of setting a function pointer on rte_log
> > with the proper loglevels and so on.
> > Ideally rte_log could be made independent (starting skimming EAL from
> > all the fat), but this is much less trivial.
> > 
> just posted about that.  I agree with Keith, I don't think you should need that
> patch.  RTE_LOG just calls rte_vlog which contains this code:
> 
> if (f == NULL) {
>                 f = default_log_stream;
>                 if (f == NULL) {
>                         /*
>                          * Grab the current value of stderr here, rather than
>                          * just initializing default_log_stream to stderr. This
>                          * ensures that we will always use the current value
>                          * of stderr, even if the application closes and
>                          * reopens it.
>                          */
>                         f = stderr;
>                 }
>         }
> }
> 
> Which I read as saying that the logging library should back off to stderr if its
> not initialized yet.  If you've encountered a problem that made you need that
> logging patch, it seems like you should be able to drop it, and we need to fix
> the logging library.  Can you elaborate on what you ran into here?
> 
> Neil

Neat. The issue is that rte_log.h is not symlink-ed until librte_eal is
processed. rte_log cannot be included.

I know Keith and Bruce discussed a few months back the possibility of
having an initial linking pass. Personally I am still against this kind of
solution, hiding design issues under the rug.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 13:04           ` Gaëtan Rivet
@ 2018-03-27 20:23             ` Gaëtan Rivet
  2018-03-27 23:26               ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27 20:23 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 03:04:13PM +0200, Gaëtan Rivet wrote:
> On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > Parse a device description.
> > > > Split this description in their relevant part for each layers.
> > > > No dynamic allocation is performed.
> > > > 
> > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > ---
> > > > 
> > > > This version uses librte_kvargs.
> > > > 
> > > >  lib/Makefile                            |   1 +
> > > >  lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> > > >  lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> > > >  lib/librte_eal/common/include/rte_dev.h |  23 +++++
> > > >  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> > > >  lib/librte_eal/rte_eal_version.map      |   1 +
> > > >  6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> > > > +}
> > > > +
> > > So the above code really just counts the number characters in the string,
> > > omitting the delimiter character '/', right?  If thats all you want to do, you can just
> > > use strtok and strnlen for that, cant you?
> > 
> > Will do.
> > 
> 
> Answered too quickly.
> No, this function only counts the number of occurences of '/' in the
> text.
> 
> strtok could be used however in the main function.
> Will see for a simpler implementation using it.
> 

After a few tries, I see no benefit in using strtok.
The original const text must still be tokenized, strtok would modify it.

Duplicating would force finding the references in the original text,
which would make the code as complex as it is now.

> > > 
> > > Otherwise, this looks pretty good to me
> > 
> > Please look into the librte_kvargs compatibility patch as well (quite
> > short). I'm very unhappy about the logging hack.
> > There is always the solution of setting a function pointer on rte_log
> > with the proper loglevels and so on.
> > Ideally rte_log could be made independent (starting skimming EAL from
> > all the fat), but this is much less trivial.
> > 
> > This implementation relies on librte_kvargs being available. If this is
> > not the case, there isn't much point to it.
> > 
> > -- 
> > Gaëtan Rivet
> > 6WIND
> 
> -- 
> Gaëtan Rivet
> 6WIND

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 20:20             ` Gaëtan Rivet
@ 2018-03-27 20:28               ` Bruce Richardson
  2018-03-27 20:35                 ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Bruce Richardson @ 2018-03-27 20:28 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Neil Horman, dev, Wiles, Keith

On Tue, Mar 27, 2018 at 10:20:40PM +0200, Gaëtan Rivet wrote:
> On Tue, Mar 27, 2018 at 02:26:33PM -0400, Neil Horman wrote:
> > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > Parse a device description.
> > > > > Split this description in their relevant part for each layers.
> > > > > No dynamic allocation is performed.
> > > > > 
> > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > ---
> > > > > 
> > > > > This version uses librte_kvargs.
> > > > > 
> > > > 
> > > > Otherwise, this looks pretty good to me
> > > 
> > > Please look into the librte_kvargs compatibility patch as well (quite
> > > short). I'm very unhappy about the logging hack.
> > > There is always the solution of setting a function pointer on rte_log
> > > with the proper loglevels and so on.
> > > Ideally rte_log could be made independent (starting skimming EAL from
> > > all the fat), but this is much less trivial.
> > > 
> > just posted about that.  I agree with Keith, I don't think you should need that
> > patch.  RTE_LOG just calls rte_vlog which contains this code:
> > 
> > if (f == NULL) {
> >                 f = default_log_stream;
> >                 if (f == NULL) {
> >                         /*
> >                          * Grab the current value of stderr here, rather than
> >                          * just initializing default_log_stream to stderr. This
> >                          * ensures that we will always use the current value
> >                          * of stderr, even if the application closes and
> >                          * reopens it.
> >                          */
> >                         f = stderr;
> >                 }
> >         }
> > }
> > 
> > Which I read as saying that the logging library should back off to stderr if its
> > not initialized yet.  If you've encountered a problem that made you need that
> > logging patch, it seems like you should be able to drop it, and we need to fix
> > the logging library.  Can you elaborate on what you ran into here?
> > 
> > Neil
> 
> Neat. The issue is that rte_log.h is not symlink-ed until librte_eal is
> processed. rte_log cannot be included.
> 
Sure it can - just pass -I/path/to/eal as a cflag.

/Bruce

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 20:28               ` Bruce Richardson
@ 2018-03-27 20:35                 ` Gaëtan Rivet
  2018-03-27 20:48                   ` Richardson, Bruce
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-27 20:35 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: Neil Horman, dev, Wiles, Keith

On Tue, Mar 27, 2018 at 09:28:07PM +0100, Bruce Richardson wrote:
> On Tue, Mar 27, 2018 at 10:20:40PM +0200, Gaëtan Rivet wrote:
> > On Tue, Mar 27, 2018 at 02:26:33PM -0400, Neil Horman wrote:
> > > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > > Parse a device description.
> > > > > > Split this description in their relevant part for each layers.
> > > > > > No dynamic allocation is performed.
> > > > > > 
> > > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > ---
> > > > > > 
> > > > > > This version uses librte_kvargs.
> > > > > > 
> > > > > 
> > > > > Otherwise, this looks pretty good to me
> > > > 
> > > > Please look into the librte_kvargs compatibility patch as well (quite
> > > > short). I'm very unhappy about the logging hack.
> > > > There is always the solution of setting a function pointer on rte_log
> > > > with the proper loglevels and so on.
> > > > Ideally rte_log could be made independent (starting skimming EAL from
> > > > all the fat), but this is much less trivial.
> > > > 
> > > just posted about that.  I agree with Keith, I don't think you should need that
> > > patch.  RTE_LOG just calls rte_vlog which contains this code:
> > > 
> > > if (f == NULL) {
> > >                 f = default_log_stream;
> > >                 if (f == NULL) {
> > >                         /*
> > >                          * Grab the current value of stderr here, rather than
> > >                          * just initializing default_log_stream to stderr. This
> > >                          * ensures that we will always use the current value
> > >                          * of stderr, even if the application closes and
> > >                          * reopens it.
> > >                          */
> > >                         f = stderr;
> > >                 }
> > >         }
> > > }
> > > 
> > > Which I read as saying that the logging library should back off to stderr if its
> > > not initialized yet.  If you've encountered a problem that made you need that
> > > logging patch, it seems like you should be able to drop it, and we need to fix
> > > the logging library.  Can you elaborate on what you ran into here?
> > > 
> > > Neil
> > 
> > Neat. The issue is that rte_log.h is not symlink-ed until librte_eal is
> > processed. rte_log cannot be included.
> > 
> Sure it can - just pass -I/path/to/eal as a cflag.
> 
> /Bruce

When you put it this way... :)

Sure, this is a solution, of which early symlink was a genericization.
I'm just not a fan of having co-dependent libraries.

But this will probably come to that.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 20:35                 ` Gaëtan Rivet
@ 2018-03-27 20:48                   ` Richardson, Bruce
  2018-03-27 23:53                     ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Richardson, Bruce @ 2018-03-27 20:48 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Neil Horman, dev, Wiles, Keith



> -----Original Message-----
> From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com]
> Sent: Tuesday, March 27, 2018 9:35 PM
> To: Richardson, Bruce <bruce.richardson@intel.com>
> Cc: Neil Horman <nhorman@tuxdriver.com>; dev@dpdk.org; Wiles, Keith
> <keith.wiles@intel.com>
> Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device
> iteration initialization
> 
> On Tue, Mar 27, 2018 at 09:28:07PM +0100, Bruce Richardson wrote:
> > On Tue, Mar 27, 2018 at 10:20:40PM +0200, Gaëtan Rivet wrote:
> > > On Tue, Mar 27, 2018 at 02:26:33PM -0400, Neil Horman wrote:
> > > > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > > > Parse a device description.
> > > > > > > Split this description in their relevant part for each layers.
> > > > > > > No dynamic allocation is performed.
> > > > > > >
> > > > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > > ---
> > > > > > >
> > > > > > > This version uses librte_kvargs.
> > > > > > >
> > > > > >
> > > > > > Otherwise, this looks pretty good to me
> > > > >
> > > > > Please look into the librte_kvargs compatibility patch as well
> > > > > (quite short). I'm very unhappy about the logging hack.
> > > > > There is always the solution of setting a function pointer on
> > > > > rte_log with the proper loglevels and so on.
> > > > > Ideally rte_log could be made independent (starting skimming EAL
> > > > > from all the fat), but this is much less trivial.
> > > > >
> > > > just posted about that.  I agree with Keith, I don't think you
> > > > should need that patch.  RTE_LOG just calls rte_vlog which contains
> this code:
> > > >
> > > > if (f == NULL) {
> > > >                 f = default_log_stream;
> > > >                 if (f == NULL) {
> > > >                         /*
> > > >                          * Grab the current value of stderr here,
> rather than
> > > >                          * just initializing default_log_stream to
> stderr. This
> > > >                          * ensures that we will always use the
> current value
> > > >                          * of stderr, even if the application closes
> and
> > > >                          * reopens it.
> > > >                          */
> > > >                         f = stderr;
> > > >                 }
> > > >         }
> > > > }
> > > >
> > > > Which I read as saying that the logging library should back off to
> > > > stderr if its not initialized yet.  If you've encountered a
> > > > problem that made you need that logging patch, it seems like you
> > > > should be able to drop it, and we need to fix the logging library.
> Can you elaborate on what you ran into here?
> > > >
> > > > Neil
> > >
> > > Neat. The issue is that rte_log.h is not symlink-ed until librte_eal
> > > is processed. rte_log cannot be included.
> > >
> > Sure it can - just pass -I/path/to/eal as a cflag.
> >
> > /Bruce
> 
> When you put it this way... :)
> 
> Sure, this is a solution, of which early symlink was a genericization.
> I'm just not a fan of having co-dependent libraries.
> 
> But this will probably come to that.
> 

The other alternative is what was done with rte_compat.h - create a new lib
just with a single header file in it. Works ok too, and may seem less hacky
to some folks.

/Bruce

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 20:23             ` Gaëtan Rivet
@ 2018-03-27 23:26               ` Neil Horman
  2018-03-28 12:48                 ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-27 23:26 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 10:23:21PM +0200, Gaëtan Rivet wrote:
> On Tue, Mar 27, 2018 at 03:04:13PM +0200, Gaëtan Rivet wrote:
> > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > Parse a device description.
> > > > > Split this description in their relevant part for each layers.
> > > > > No dynamic allocation is performed.
> > > > > 
> > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > ---
> > > > > 
> > > > > This version uses librte_kvargs.
> > > > > 
> > > > >  lib/Makefile                            |   1 +
> > > > >  lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> > > > >  lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> > > > >  lib/librte_eal/common/include/rte_dev.h |  23 +++++
> > > > >  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> > > > >  lib/librte_eal/rte_eal_version.map      |   1 +
> > > > >  6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> > > > > +}
> > > > > +
> > > > So the above code really just counts the number characters in the string,
> > > > omitting the delimiter character '/', right?  If thats all you want to do, you can just
> > > > use strtok and strnlen for that, cant you?
> > > 
> > > Will do.
> > > 
> > 
> > Answered too quickly.
> > No, this function only counts the number of occurences of '/' in the
> > text.
> > 
> > strtok could be used however in the main function.
> > Will see for a simpler implementation using it.
> > 
> 
> After a few tries, I see no benefit in using strtok.
> The original const text must still be tokenized, strtok would modify it.
> 
> Duplicating would force finding the references in the original text,
> which would make the code as complex as it is now.
> 
Oh, if you don't want to modify the string, then index() is what you want.  see
man 3 index, or man 3 rindex

Neil

> > > > 
> > > > Otherwise, this looks pretty good to me
> > > 
> > > Please look into the librte_kvargs compatibility patch as well (quite
> > > short). I'm very unhappy about the logging hack.
> > > There is always the solution of setting a function pointer on rte_log
> > > with the proper loglevels and so on.
> > > Ideally rte_log could be made independent (starting skimming EAL from
> > > all the fat), but this is much less trivial.
> > > 
> > > This implementation relies on librte_kvargs being available. If this is
> > > not the case, there isn't much point to it.
> > > 
> > > -- 
> > > Gaëtan Rivet
> > > 6WIND
> > 
> > -- 
> > Gaëtan Rivet
> > 6WIND
> 
> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 20:48                   ` Richardson, Bruce
@ 2018-03-27 23:53                     ` Neil Horman
  2018-03-28  8:10                       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-27 23:53 UTC (permalink / raw)
  To: Richardson, Bruce; +Cc: Gaëtan Rivet, dev, Wiles, Keith

On Tue, Mar 27, 2018 at 08:48:01PM +0000, Richardson, Bruce wrote:
> 
> 
> > -----Original Message-----
> > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com]
> > Sent: Tuesday, March 27, 2018 9:35 PM
> > To: Richardson, Bruce <bruce.richardson@intel.com>
> > Cc: Neil Horman <nhorman@tuxdriver.com>; dev@dpdk.org; Wiles, Keith
> > <keith.wiles@intel.com>
> > Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device
> > iteration initialization
> > 
> > On Tue, Mar 27, 2018 at 09:28:07PM +0100, Bruce Richardson wrote:
> > > On Tue, Mar 27, 2018 at 10:20:40PM +0200, Gaëtan Rivet wrote:
> > > > On Tue, Mar 27, 2018 at 02:26:33PM -0400, Neil Horman wrote:
> > > > > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > > > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > > > > Parse a device description.
> > > > > > > > Split this description in their relevant part for each layers.
> > > > > > > > No dynamic allocation is performed.
> > > > > > > >
> > > > > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > > > ---
> > > > > > > >
> > > > > > > > This version uses librte_kvargs.
> > > > > > > >
> > > > > > >
> > > > > > > Otherwise, this looks pretty good to me
> > > > > >
> > > > > > Please look into the librte_kvargs compatibility patch as well
> > > > > > (quite short). I'm very unhappy about the logging hack.
> > > > > > There is always the solution of setting a function pointer on
> > > > > > rte_log with the proper loglevels and so on.
> > > > > > Ideally rte_log could be made independent (starting skimming EAL
> > > > > > from all the fat), but this is much less trivial.
> > > > > >
> > > > > just posted about that.  I agree with Keith, I don't think you
> > > > > should need that patch.  RTE_LOG just calls rte_vlog which contains
> > this code:
> > > > >
> > > > > if (f == NULL) {
> > > > >                 f = default_log_stream;
> > > > >                 if (f == NULL) {
> > > > >                         /*
> > > > >                          * Grab the current value of stderr here,
> > rather than
> > > > >                          * just initializing default_log_stream to
> > stderr. This
> > > > >                          * ensures that we will always use the
> > current value
> > > > >                          * of stderr, even if the application closes
> > and
> > > > >                          * reopens it.
> > > > >                          */
> > > > >                         f = stderr;
> > > > >                 }
> > > > >         }
> > > > > }
> > > > >
> > > > > Which I read as saying that the logging library should back off to
> > > > > stderr if its not initialized yet.  If you've encountered a
> > > > > problem that made you need that logging patch, it seems like you
> > > > > should be able to drop it, and we need to fix the logging library.
> > Can you elaborate on what you ran into here?
> > > > >
> > > > > Neil
> > > >
> > > > Neat. The issue is that rte_log.h is not symlink-ed until librte_eal
> > > > is processed. rte_log cannot be included.
> > > >
> > > Sure it can - just pass -I/path/to/eal as a cflag.
> > >
> > > /Bruce
> > 
> > When you put it this way... :)
> > 
> > Sure, this is a solution, of which early symlink was a genericization.
> > I'm just not a fan of having co-dependent libraries.
> > 
> > But this will probably come to that.
> > 
> 
> The other alternative is what was done with rte_compat.h - create a new lib
> just with a single header file in it. Works ok too, and may seem less hacky
> to some folks.
> 
> /Bruce
> 
This seems like a good alternative to me.  I'm not entirely sure why the logging
functions are integrated to EAL anyway.  

Neil
 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 23:53                     ` Neil Horman
@ 2018-03-28  8:10                       ` Gaëtan Rivet
  2018-03-28 11:17                         ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-28  8:10 UTC (permalink / raw)
  To: Neil Horman; +Cc: Richardson, Bruce, dev, Wiles, Keith

On Tue, Mar 27, 2018 at 07:53:46PM -0400, Neil Horman wrote:
> On Tue, Mar 27, 2018 at 08:48:01PM +0000, Richardson, Bruce wrote:
> > 
> > 
> > > -----Original Message-----
> > > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com]
> > > Sent: Tuesday, March 27, 2018 9:35 PM
> > > To: Richardson, Bruce <bruce.richardson@intel.com>
> > > Cc: Neil Horman <nhorman@tuxdriver.com>; dev@dpdk.org; Wiles, Keith
> > > <keith.wiles@intel.com>
> > > Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device
> > > iteration initialization
> > > 
> > > On Tue, Mar 27, 2018 at 09:28:07PM +0100, Bruce Richardson wrote:
> > > > On Tue, Mar 27, 2018 at 10:20:40PM +0200, Gaëtan Rivet wrote:
> > > > > On Tue, Mar 27, 2018 at 02:26:33PM -0400, Neil Horman wrote:
> > > > > > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > > > > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > > > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > > > > > Parse a device description.
> > > > > > > > > Split this description in their relevant part for each layers.
> > > > > > > > > No dynamic allocation is performed.
> > > > > > > > >
> > > > > > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > > > > ---
> > > > > > > > >
> > > > > > > > > This version uses librte_kvargs.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Otherwise, this looks pretty good to me
> > > > > > >
> > > > > > > Please look into the librte_kvargs compatibility patch as well
> > > > > > > (quite short). I'm very unhappy about the logging hack.
> > > > > > > There is always the solution of setting a function pointer on
> > > > > > > rte_log with the proper loglevels and so on.
> > > > > > > Ideally rte_log could be made independent (starting skimming EAL
> > > > > > > from all the fat), but this is much less trivial.
> > > > > > >
> > > > > > just posted about that.  I agree with Keith, I don't think you
> > > > > > should need that patch.  RTE_LOG just calls rte_vlog which contains
> > > this code:
> > > > > >
> > > > > > if (f == NULL) {
> > > > > >                 f = default_log_stream;
> > > > > >                 if (f == NULL) {
> > > > > >                         /*
> > > > > >                          * Grab the current value of stderr here,
> > > rather than
> > > > > >                          * just initializing default_log_stream to
> > > stderr. This
> > > > > >                          * ensures that we will always use the
> > > current value
> > > > > >                          * of stderr, even if the application closes
> > > and
> > > > > >                          * reopens it.
> > > > > >                          */
> > > > > >                         f = stderr;
> > > > > >                 }
> > > > > >         }
> > > > > > }
> > > > > >
> > > > > > Which I read as saying that the logging library should back off to
> > > > > > stderr if its not initialized yet.  If you've encountered a
> > > > > > problem that made you need that logging patch, it seems like you
> > > > > > should be able to drop it, and we need to fix the logging library.
> > > Can you elaborate on what you ran into here?
> > > > > >
> > > > > > Neil
> > > > >
> > > > > Neat. The issue is that rte_log.h is not symlink-ed until librte_eal
> > > > > is processed. rte_log cannot be included.
> > > > >
> > > > Sure it can - just pass -I/path/to/eal as a cflag.
> > > >
> > > > /Bruce
> > > 
> > > When you put it this way... :)
> > > 
> > > Sure, this is a solution, of which early symlink was a genericization.
> > > I'm just not a fan of having co-dependent libraries.
> > > 
> > > But this will probably come to that.
> > > 
> > 
> > The other alternative is what was done with rte_compat.h - create a new lib
> > just with a single header file in it. Works ok too, and may seem less hacky
> > to some folks.
> > 
> > /Bruce
> > 
> This seems like a good alternative to me.  I'm not entirely sure why the logging
> functions are integrated to EAL anyway.  
> 
> Neil
>  

As I said earlier:

> > > > > > > Ideally rte_log could be made independent (starting skimming EAL
> > > > > > > from all the fat), but this is much less trivial.

rte_log could certainly stand on its own. I quickly attempted to make it
a library, but this is too much work at this point. I think the EAL
should be broken down, it is too monolithic. Problem is that many
other libraries / applications, now relies on parts of the EAL that
would need to be moved.

So any effort in this direction will be difficult to undertake (and
badly received by the community, with good reasons), especially when
the workaround is an additional -I cflag.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-28  8:10                       ` Gaëtan Rivet
@ 2018-03-28 11:17                         ` Neil Horman
  2018-04-22 22:29                           ` Thomas Monjalon
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-03-28 11:17 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Richardson, Bruce, dev, Wiles, Keith

On Wed, Mar 28, 2018 at 10:10:07AM +0200, Gaëtan Rivet wrote:
> On Tue, Mar 27, 2018 at 07:53:46PM -0400, Neil Horman wrote:
> > On Tue, Mar 27, 2018 at 08:48:01PM +0000, Richardson, Bruce wrote:
> > > 
> > > 
> > > > -----Original Message-----
> > > > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com]
> > > > Sent: Tuesday, March 27, 2018 9:35 PM
> > > > To: Richardson, Bruce <bruce.richardson@intel.com>
> > > > Cc: Neil Horman <nhorman@tuxdriver.com>; dev@dpdk.org; Wiles, Keith
> > > > <keith.wiles@intel.com>
> > > > Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device
> > > > iteration initialization
> > > > 
> > > > On Tue, Mar 27, 2018 at 09:28:07PM +0100, Bruce Richardson wrote:
> > > > > On Tue, Mar 27, 2018 at 10:20:40PM +0200, Gaëtan Rivet wrote:
> > > > > > On Tue, Mar 27, 2018 at 02:26:33PM -0400, Neil Horman wrote:
> > > > > > > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > > > > > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > > > > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > > > > > > Parse a device description.
> > > > > > > > > > Split this description in their relevant part for each layers.
> > > > > > > > > > No dynamic allocation is performed.
> > > > > > > > > >
> > > > > > > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > > > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > > > > > ---
> > > > > > > > > >
> > > > > > > > > > This version uses librte_kvargs.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Otherwise, this looks pretty good to me
> > > > > > > >
> > > > > > > > Please look into the librte_kvargs compatibility patch as well
> > > > > > > > (quite short). I'm very unhappy about the logging hack.
> > > > > > > > There is always the solution of setting a function pointer on
> > > > > > > > rte_log with the proper loglevels and so on.
> > > > > > > > Ideally rte_log could be made independent (starting skimming EAL
> > > > > > > > from all the fat), but this is much less trivial.
> > > > > > > >
> > > > > > > just posted about that.  I agree with Keith, I don't think you
> > > > > > > should need that patch.  RTE_LOG just calls rte_vlog which contains
> > > > this code:
> > > > > > >
> > > > > > > if (f == NULL) {
> > > > > > >                 f = default_log_stream;
> > > > > > >                 if (f == NULL) {
> > > > > > >                         /*
> > > > > > >                          * Grab the current value of stderr here,
> > > > rather than
> > > > > > >                          * just initializing default_log_stream to
> > > > stderr. This
> > > > > > >                          * ensures that we will always use the
> > > > current value
> > > > > > >                          * of stderr, even if the application closes
> > > > and
> > > > > > >                          * reopens it.
> > > > > > >                          */
> > > > > > >                         f = stderr;
> > > > > > >                 }
> > > > > > >         }
> > > > > > > }
> > > > > > >
> > > > > > > Which I read as saying that the logging library should back off to
> > > > > > > stderr if its not initialized yet.  If you've encountered a
> > > > > > > problem that made you need that logging patch, it seems like you
> > > > > > > should be able to drop it, and we need to fix the logging library.
> > > > Can you elaborate on what you ran into here?
> > > > > > >
> > > > > > > Neil
> > > > > >
> > > > > > Neat. The issue is that rte_log.h is not symlink-ed until librte_eal
> > > > > > is processed. rte_log cannot be included.
> > > > > >
> > > > > Sure it can - just pass -I/path/to/eal as a cflag.
> > > > >
> > > > > /Bruce
> > > > 
> > > > When you put it this way... :)
> > > > 
> > > > Sure, this is a solution, of which early symlink was a genericization.
> > > > I'm just not a fan of having co-dependent libraries.
> > > > 
> > > > But this will probably come to that.
> > > > 
> > > 
> > > The other alternative is what was done with rte_compat.h - create a new lib
> > > just with a single header file in it. Works ok too, and may seem less hacky
> > > to some folks.
> > > 
> > > /Bruce
> > > 
> > This seems like a good alternative to me.  I'm not entirely sure why the logging
> > functions are integrated to EAL anyway.  
> > 
> > Neil
> >  
> 
> As I said earlier:
> 
> > > > > > > > Ideally rte_log could be made independent (starting skimming EAL
> > > > > > > > from all the fat), but this is much less trivial.
> 
> rte_log could certainly stand on its own. I quickly attempted to make it
> a library, but this is too much work at this point. I think the EAL
> should be broken down, it is too monolithic. Problem is that many
> other libraries / applications, now relies on parts of the EAL that
> would need to be moved.
> 
> So any effort in this direction will be difficult to undertake (and
> badly received by the community, with good reasons), especially when
> the workaround is an additional -I cflag.
> 
I'm fine with just adding another include path to the CFLAGS for this purpose in
the short term, just saying I'm not sure why the log library got integrated into
EAL in the first place.

Neil

> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-27 23:26               ` Neil Horman
@ 2018-03-28 12:48                 ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-28 12:48 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev, Wiles, Keith

On Tue, Mar 27, 2018 at 07:26:41PM -0400, Neil Horman wrote:
> On Tue, Mar 27, 2018 at 10:23:21PM +0200, Gaëtan Rivet wrote:
> > On Tue, Mar 27, 2018 at 03:04:13PM +0200, Gaëtan Rivet wrote:
> > > On Tue, Mar 27, 2018 at 02:40:00PM +0200, Gaëtan Rivet wrote:
> > > > On Tue, Mar 27, 2018 at 07:47:50AM -0400, Neil Horman wrote:
> > > > > On Tue, Mar 27, 2018 at 01:18:34AM +0200, Gaetan Rivet wrote:
> > > > > > Parse a device description.
> > > > > > Split this description in their relevant part for each layers.
> > > > > > No dynamic allocation is performed.
> > > > > > 
> > > > > > Cc: Neil Horman <nhorman@tuxdriver.com>
> > > > > > Cc: "Wiles, Keith" <keith.wiles@intel.com>
> > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > ---
> > > > > > 
> > > > > > This version uses librte_kvargs.
> > > > > > 
> > > > > >  lib/Makefile                            |   1 +
> > > > > >  lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> > > > > >  lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> > > > > >  lib/librte_eal/common/include/rte_dev.h |  23 +++++
> > > > > >  lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> > > > > >  lib/librte_eal/rte_eal_version.map      |   1 +
> > > > > >  6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> > > > > > +}
> > > > > > +
> > > > > So the above code really just counts the number characters in the string,
> > > > > omitting the delimiter character '/', right?  If thats all you want to do, you can just
> > > > > use strtok and strnlen for that, cant you?
> > > > 
> > > > Will do.
> > > > 
> > > 
> > > Answered too quickly.
> > > No, this function only counts the number of occurences of '/' in the
> > > text.
> > > 
> > > strtok could be used however in the main function.
> > > Will see for a simpler implementation using it.
> > > 
> > 
> > After a few tries, I see no benefit in using strtok.
> > The original const text must still be tokenized, strtok would modify it.
> > 
> > Duplicating would force finding the references in the original text,
> > which would make the code as complex as it is now.
> > 
> Oh, if you don't want to modify the string, then index() is what you want.  see
> man 3 index, or man 3 rindex
> 
> Neil
> 

strchr is already used when necessary, and index is removed since
POSIX.1-2008.

Thanks for the suggestions, it was still helpful to go over the code and
see if there were possible improvements.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 00/20] Device querying
  2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
                       ` (19 preceding siblings ...)
  2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 20/20] app/testpmd: add show device command Gaetan Rivet
@ 2018-03-29 21:23     ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 01/20] kvargs: build before EAL Gaetan Rivet
                         ` (20 more replies)
  20 siblings, 21 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.


Gaetan Rivet (20):
  kvargs: build before EAL
  eal: list acceptable init priorities
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: fix find device implementation
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: fix find device implementation
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                             |  52 ++++
 drivers/bus/pci/Makefile                           |   2 +-
 drivers/bus/pci/pci_common.c                       |  87 +++++-
 drivers/bus/pci/rte_bus_pci.h                      |   3 +
 drivers/bus/vdev/Makefile                          |   3 +-
 drivers/bus/vdev/rte_bus_vdev.h                    |   3 +
 drivers/bus/vdev/vdev.c                            |  66 +++-
 lib/Makefile                                       |   7 +-
 lib/librte_eal/bsdapp/eal/Makefile                 |   2 +
 lib/librte_eal/common/Makefile                     |   4 +-
 lib/librte_eal/common/eal_common_class.c           |  62 ++++
 lib/librte_eal/common/eal_common_dev.c             | 334 +++++++++++++++++++++
 lib/librte_eal/common/eal_common_log.c             |   2 +-
 lib/librte_eal/common/include/rte_bus.h            |   3 +-
 lib/librte_eal/common/include/rte_class.h          | 127 ++++++++
 lib/librte_eal/common/include/rte_common.h         |  32 +-
 lib/librte_eal/common/include/rte_dev.h            |  95 ++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   2 +
 lib/librte_eal/rte_eal_version.map                 |   4 +
 lib/librte_ether/Makefile                          |   3 +-
 lib/librte_ether/rte_class_eth.c                   |  79 +++++
 lib/librte_kvargs/Makefile                         |   3 +-
 lib/librte_kvargs/rte_kvargs.c                     |  12 +-
 lib/librte_kvargs/rte_kvargs.h                     |  28 ++
 lib/librte_kvargs/rte_kvargs_version.map           |   7 +
 .../include => librte_kvargs}/rte_string_fns.h     |   0
 26 files changed, 995 insertions(+), 27 deletions(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ether/rte_class_eth.c
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 01/20] kvargs: build before EAL
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 02/20] eal: list acceptable init priorities Gaetan Rivet
                         ` (19 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                                                      | 3 +--
 lib/librte_eal/common/Makefile                                    | 2 +-
 lib/librte_kvargs/Makefile                                        | 3 ++-
 lib/librte_kvargs/rte_kvargs.c                                    | 2 +-
 lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
 5 files changed, 5 insertions(+), 5 deletions(-)
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a606..fc7a55a37 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -71,8 +72,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index ea824a3a8..75776d3e2 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -9,7 +9,7 @@ INC += rte_errno.h rte_launch.h rte_lcore.h
 INC += rte_log.h rte_memory.h rte_memzone.h
 INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
+INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 4eaa9334d..e026ecc21 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -37,7 +37,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c
 
 # install includes
 INCS := rte_kvargs.h
+INCS += rte_string_fns.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS)
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..0a1abf579 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -7,8 +7,8 @@
 #include <stdlib.h>
 
 #include <rte_log.h>
-#include <rte_string_fns.h>
 
+#include "rte_string_fns.h"
 #include "rte_kvargs.h"
 
 /*
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_kvargs/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_kvargs/rte_string_fns.h
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 02/20] eal: list acceptable init priorities
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 01/20] kvargs: build before EAL Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 03/20] eal: introduce dtor macros Gaetan Rivet
                         ` (18 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Build a central list to quickly see each used priorities for
constructors, allowing to verify that they are both above 100 and in the
proper order.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
 lib/librte_eal/common/eal_common_log.c     | 2 +-
 lib/librte_eal/common/include/rte_bus.h    | 2 +-
 lib/librte_eal/common/include/rte_common.h | 8 +++++++-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index 37b2e20e5..b384c72d3 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = {
 };
 
 /* Logging should be first initializer (before drivers and bus) */
-RTE_INIT_PRIO(rte_log_init, 101);
+RTE_INIT_PRIO(rte_log_init, LOG);
 static void
 rte_log_init(void)
 {
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 6fb08341a..eb9eded4e 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
  * The constructor has higher priority than PMD constructors.
  */
 #define RTE_REGISTER_BUS(nm, bus) \
-RTE_INIT_PRIO(businitfn_ ##nm, 110); \
+RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
 static void businitfn_ ##nm(void) \
 {\
 	(bus).name = RTE_STR(nm);\
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index c7803e41c..99a799d6d 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
  */
 #define RTE_SET_USED(x) (void)(x)
 
+#define RTE_PRIORITY_LOG 101
+#define RTE_PRIORITY_BUS 110
+
+#define RTE_PRIO(prio) \
+	RTE_PRIORITY_ ## prio
+
 /**
  * Run function before main() with low priority.
  *
@@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
  *   Lowest number is the first to run.
  */
 #define RTE_INIT_PRIO(func, prio) \
-static void __attribute__((constructor(prio), used)) func(void)
+static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
  * Force a function to be inlined
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 03/20] eal: introduce dtor macros
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 01/20] kvargs: build before EAL Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 02/20] eal: list acceptable init priorities Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 04/20] eal: introduce device class abstraction Gaetan Rivet
                         ` (17 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 99a799d6d..bdccc2553 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -111,6 +111,29 @@ static void __attribute__((constructor, used)) func(void)
 static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+static void __attribute__((destructor, used)) func(void)
+
+/**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 04/20] eal: introduce device class abstraction
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (2 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 03/20] eal: introduce dtor macros Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 05/20] eal/class: register destructor Gaetan Rivet
                         ` (16 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 7 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index dd455e671..17ff1ac45 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 75776d3e2..607ae0447 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..b5e550a34
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index bdccc2553..d8ee35e2d 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 
 #define RTE_PRIO(prio) \
 	RTE_PRIORITY_ ## prio
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 7e5bbe889..a3edbbe76 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index d12360235..910cb23c9 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -215,6 +215,8 @@ EXPERIMENTAL {
 	global:
 
 	rte_eal_cleanup;
+	rte_class_register;
+	rte_class_unregister;
 	rte_eal_devargs_insert;
 	rte_eal_devargs_parse;
 	rte_eal_devargs_remove;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 05/20] eal/class: register destructor
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (3 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 04/20] eal: introduce device class abstraction Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 06/20] eal/dev: add device iterator interface Gaetan Rivet
                         ` (15 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index b5e550a34..e8176f5e1 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 06/20] eal/dev: add device iterator interface
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (4 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 05/20] eal/class: register destructor Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 07/20] eal/class: add device iteration Gaetan Rivet
                         ` (14 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index b688f1efd..937ff6079 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -263,6 +263,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 07/20] eal/class: add device iteration
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (5 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 06/20] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 08/20] eal/bus: " Gaetan Rivet
                         ` (13 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index e8176f5e1..9d5b06807 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 08/20] eal/bus: add device iteration
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (6 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 07/20] eal/class: add device iteration Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization Gaetan Rivet
                         ` (12 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (7 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 08/20] eal/bus: " Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-30 15:22         ` Wiles, Keith
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 10/20] eal/dev: implement device iteration Gaetan Rivet
                         ` (11 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@6wind.com>
---
 lib/Makefile                            |   1 +
 lib/librte_eal/bsdapp/eal/Makefile      |   1 +
 lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  23 +++++
 lib/librte_eal/linuxapp/eal/Makefile    |   1 +
 lib/librte_eal/rte_eal_version.map      |   1 +
 6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
+}
+
+int __rte_experimental
+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..7ce13e068 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -310,6 +310,29 @@ 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.
+ */
+int __rte_experimental
+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 a3edbbe76..87caa23a1 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 910cb23c9..921da3075 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -228,6 +228,7 @@ EXPERIMENTAL {
 	rte_mp_sendmsg;
 	rte_mp_request;
 	rte_mp_reply;
+	rte_dev_iterator_init;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 10/20] eal/dev: implement device iteration
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (8 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-04-09  7:28         ` Matan Azrad
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 11/20] kvargs: add generic string matching callback Gaetan Rivet
                         ` (10 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 187 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  25 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 213 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 1f6df2351..ae56f2a15 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -20,6 +20,28 @@
 
 #include "eal_private.h"
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -354,3 +376,168 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 	}
 	return -rte_errno;
 }
+
+/* '\0' forbidden in sym */
+static const char *
+strfirstof(const char *str,
+	   const char *sym)
+{
+	const char *s;
+
+	for (s = str; s[0] != '\0'; s++) {
+		const char *c;
+
+		for (c = sym; c[0] != '\0'; c++) {
+			if (c[0] == s[0])
+				return s;
+		}
+	}
+	return NULL;
+}
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	const char *end;
+	char *copy;
+
+	end = strfirstof(str, ",/");
+	if (end != NULL &&
+	    end[0] == ',') {
+		copy = strdup(end + 1);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	/* If an error occured previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	/* If an error occured previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_copy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_copy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 7ce13e068..dfb5d696f 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -333,6 +333,31 @@ typedef void *(*rte_dev_iterate_t)(const void *start,
 int __rte_experimental
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+struct rte_device * __rte_experimental
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 921da3075..925efcb6d 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -229,6 +229,7 @@ EXPERIMENTAL {
 	rte_mp_request;
 	rte_mp_reply;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_service_attr_get;
 	rte_service_attr_reset_all;
 	rte_service_component_register;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 11/20] kvargs: add generic string matching callback
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (9 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 10/20] eal/dev: implement device iteration Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 12/20] bus/pci: fix find device implementation Gaetan Rivet
                         ` (9 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
 4 files changed, 46 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 1b17526f7..4206485d3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 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
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 0a1abf579..6ee04cbb9 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -180,3 +180,13 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -strcmp(str, value);
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..c07c6fea5 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -121,6 +123,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..e2f663a88 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 12/20] bus/pci: fix find device implementation
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (10 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 11/20] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 13/20] bus/pci: implement device iteration and comparison Gaetan Rivet
                         ` (8 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set, and a device before it matches the data
passed for comparison, then this first device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2a00f365a..2c45f8151 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -459,17 +459,20 @@ static struct rte_device *
 pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		const void *data)
 {
-	struct rte_pci_device *dev;
+	const struct rte_pci_device *pstart;
+	struct rte_pci_device *pdev;
 
-	FOREACH_DEVICE_ON_PCIBUS(dev) {
-		if (start && &dev->device == start) {
-			start = NULL; /* starting point found */
-			continue;
-		}
-		if (cmp(&dev->device, data) == 0)
-			return &dev->device;
+	if (start != NULL) {
+		pstart = RTE_DEV_TO_PCI_CONST(start);
+		pdev = TAILQ_NEXT(pstart, next);
+	} else {
+		pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
+	}
+	while (pdev != NULL) {
+		if (cmp(&pdev->device, data) == 0)
+			return &pdev->device;
+		pdev = TAILQ_NEXT(pdev, next);
 	}
-
 	return NULL;
 }
 
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 357afb912..458e6d076 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -74,6 +74,9 @@ struct rte_pci_device {
  */
 #define RTE_DEV_TO_PCI(ptr) container_of(ptr, struct rte_pci_device, device)
 
+#define RTE_DEV_TO_PCI_CONST(ptr) \
+	container_of(ptr, const struct rte_pci_device, device)
+
 #define RTE_ETH_DEV_TO_PCI(eth_dev)	RTE_DEV_TO_PCI((eth_dev)->device)
 
 /** Any PCI device identifier (vendor, device, ...) */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 13/20] bus/pci: implement device iteration and comparison
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (11 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 12/20] bus/pci: fix find device implementation Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 14/20] bus/pci: add device matching field id Gaetan Rivet
                         ` (7 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index f3df1c4ce..73498dc77 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -50,7 +50,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
 CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2c45f8151..5ce2e5733 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -13,6 +13,7 @@
 
 #include <rte_errno.h>
 #include <rte_interrupts.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
@@ -497,6 +498,46 @@ pci_unplug(struct rte_device *dev)
 	return ret;
 }
 
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char *pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+static void *
+pci_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_device *dev;
+	struct rte_kvargs *kvargs = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = pci_find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 struct rte_pci_bus rte_pci_bus = {
 	.bus = {
 		.scan = rte_pci_scan,
@@ -506,6 +547,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 14/20] bus/pci: add device matching field id
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (12 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 13/20] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 15/20] bus/vdev: fix find device implementation Gaetan Rivet
                         ` (6 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 5ce2e5733..3ccc2941d 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -499,21 +499,45 @@ pci_unplug(struct rte_device *dev)
 }
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char *pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return rte_pci_addr_cmp(addr1, addr2);
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 15/20] bus/vdev: fix find device implementation
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (13 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 14/20] bus/pci: add device matching field id Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 16/20] bus/vdev: implement device iteration Gaetan Rivet
                         ` (5 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set and a device before it matches the data,
this device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/vdev/rte_bus_vdev.h b/drivers/bus/vdev/rte_bus_vdev.h
index f9d8a2383..4da9967c6 100644
--- a/drivers/bus/vdev/rte_bus_vdev.h
+++ b/drivers/bus/vdev/rte_bus_vdev.h
@@ -53,6 +53,9 @@ struct rte_vdev_device {
 #define RTE_DEV_TO_VDEV(ptr) \
 	container_of(ptr, struct rte_vdev_device, device)
 
+#define RTE_DEV_TO_VDEV_CONST(ptr) \
+	container_of(ptr, const struct rte_vdev_device, device)
+
 static inline const char *
 rte_vdev_device_name(const struct rte_vdev_device *dev)
 {
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 7eae319cb..66fe63e85 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -386,15 +386,19 @@ static struct rte_device *
 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		 const void *data)
 {
+	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
 
-	TAILQ_FOREACH(dev, &vdev_device_list, next) {
-		if (start && &dev->device == start) {
-			start = NULL;
-			continue;
-		}
+	if (start != NULL) {
+		vstart = RTE_DEV_TO_VDEV_CONST(start);
+		dev = TAILQ_NEXT(vstart, next);
+	} else {
+		dev = TAILQ_FIRST(&vdev_device_list);
+	}
+	while (dev != NULL) {
 		if (cmp(&dev->device, data) == 0)
 			return &dev->device;
+		dev = TAILQ_NEXT(dev, next);
 	}
 	return NULL;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 16/20] bus/vdev: implement device iteration
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (14 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 15/20] bus/vdev: fix find device implementation Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 17/20] bus/vdev: add device matching field driver Gaetan Rivet
                         ` (4 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 24d424a38..52728833c 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 66fe63e85..5d77cc369 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -43,6 +43,7 @@
 #include <rte_bus.h>
 #include <rte_common.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
 #include <rte_memory.h>
 #include <rte_tailq.h>
 #include <rte_spinlock.h>
@@ -415,6 +416,46 @@ vdev_unplug(struct rte_device *dev)
 	return rte_vdev_uninit(dev->name);
 }
 
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char *vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+static void *
+vdev_dev_iterate(const void *start,
+		 const char *str,
+		 const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
@@ -422,6 +463,7 @@ static struct rte_bus rte_vdev_bus = {
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 17/20] bus/vdev: add device matching field driver
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (15 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 16/20] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class Gaetan Rivet
                         ` (3 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  1 +
 drivers/bus/vdev/vdev.c   | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 52728833c..db6bee98a 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -10,6 +10,7 @@ LIB = librte_bus_vdev.a
 
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 # versioning export map
 EXPORT_MAP := rte_bus_vdev_version.map
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 5d77cc369..d0ba1965f 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -417,10 +417,12 @@ vdev_unplug(struct rte_device *dev)
 }
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char *vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -429,9 +431,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		&rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (16 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 17/20] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-04-09  7:41         ` Matan Azrad
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 19/20] ethdev: add device matching field name Gaetan Rivet
                         ` (2 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                     |  2 +-
 lib/librte_ether/Makefile        |  3 +-
 lib/librte_ether/rte_class_eth.c | 73 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 76 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_ether/rte_class_eth.c

diff --git a/lib/Makefile b/lib/Makefile
index 4206485d3..47513f03f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf
+DEPDIRS-librte_ether += librte_mbuf librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 3ca5782bb..a1a0393de 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 8
 
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
new file mode 100644
index 000000000..97d24781d
--- /dev/null
+++ b/lib/librte_ether/rte_class_eth.c
@@ -0,0 +1,73 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char *eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+static int
+eth_dev_match(struct rte_eth_dev *edev,
+	      struct rte_kvargs *kvlist)
+{
+	(void) kvlist;
+	(void) edev;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *_start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	const struct rte_eth_dev *start = _start;
+	struct rte_device *dev = it->device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+	uint16_t p = 0;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	if (start)
+		p = start->data->port_id + 1;
+	for (p = rte_eth_find_next(p);
+	     p < RTE_MAX_ETHPORTS;
+	     p = rte_eth_find_next(p + 1)) {
+		edev = &rte_eth_devices[p];
+		if (dev != edev->device)
+			goto next_ethdev;
+		if (eth_dev_match(edev, kvargs) == 0)
+			break;
+next_ethdev:
+		edev = NULL;
+	}
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 19/20] ethdev: add device matching field name
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (17 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 20/20] app/testpmd: add show device command Gaetan Rivet
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/rte_class_eth.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
index 97d24781d..99aff372e 100644
--- a/lib/librte_ether/rte_class_eth.c
+++ b/lib/librte_ether/rte_class_eth.c
@@ -14,10 +14,12 @@
 #include "rte_ethdev_core.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char *eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -25,8 +27,12 @@ static int
 eth_dev_match(struct rte_eth_dev *edev,
 	      struct rte_kvargs *kvlist)
 {
-	(void) kvlist;
-	(void) edev;
+	struct rte_eth_dev_data *data;
+
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			&rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v4 20/20] app/testpmd: add show device command
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (18 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 19/20] ethdev: add device matching field name Gaetan Rivet
@ 2018-03-29 21:23       ` Gaetan Rivet
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-03-29 21:23 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..8ac5fb3ca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device "
+		"<device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-03-30 15:22         ` Wiles, Keith
  2018-03-30 15:53           ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Wiles, Keith @ 2018-03-30 15:22 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev



> On Mar 29, 2018, at 4:23 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> 
> 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.rivet@6wind.com>
> ---
> lib/Makefile                            |   1 +
> lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> lib/librte_eal/common/include/rte_dev.h |  23 +++++
> lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> lib/librte_eal/rte_eal_version.map      |   1 +
> 6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> +}
> +
> +int __rte_experimental
> +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;

This one could just return -EINVAL; instead of calling 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”);

Maybe spell it out in the log ‘Out of Memory’.
> +			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);

I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.

Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.

I stopped reviewing the code as it became difficult to read IMO and just causing me a headache.

This problem needs to be addressed by the TSC IMO.
> +		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..7ce13e068 100644
> --- a/lib/librte_eal/common/include/rte_dev.h
> +++ b/lib/librte_eal/common/include/rte_dev.h
> @@ -310,6 +310,29 @@ 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.
> + */
> +int __rte_experimental
> +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 a3edbbe76..87caa23a1 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 910cb23c9..921da3075 100644
> --- a/lib/librte_eal/rte_eal_version.map
> +++ b/lib/librte_eal/rte_eal_version.map
> @@ -228,6 +228,7 @@ EXPERIMENTAL {
> 	rte_mp_sendmsg;
> 	rte_mp_request;
> 	rte_mp_reply;
> +	rte_dev_iterator_init;
> 	rte_service_attr_get;
> 	rte_service_attr_reset_all;
> 	rte_service_component_register;
> -- 
> 2.11.0
> 

Regards,
Keith


^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization
  2018-03-30 15:22         ` Wiles, Keith
@ 2018-03-30 15:53           ` Gaëtan Rivet
  2018-03-30 16:22             ` Wiles, Keith
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-30 15:53 UTC (permalink / raw)
  To: Wiles, Keith; +Cc: dev

Hello Keith,

On Fri, Mar 30, 2018 at 03:22:59PM +0000, Wiles, Keith wrote:
> 
> 
> > On Mar 29, 2018, at 4:23 PM, Gaetan Rivet <gaetan.rivet@6wind.com> wrote:
> > 
> > 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.rivet@6wind.com>
> > ---
> > lib/Makefile                            |   1 +
> > lib/librte_eal/bsdapp/eal/Makefile      |   1 +
> > lib/librte_eal/common/eal_common_dev.c  | 147 ++++++++++++++++++++++++++++++++
> > lib/librte_eal/common/include/rte_dev.h |  23 +++++
> > lib/librte_eal/linuxapp/eal/Makefile    |   1 +
> > lib/librte_eal/rte_eal_version.map      |   1 +
> > 6 files changed, 174 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 17ff1ac45..f6cea7fc2 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..1f6df2351 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,147 @@ 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;
> > +}
> > +
> > +int __rte_experimental
> > +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;
> 
> This one could just return -EINVAL; instead of calling 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”);
> 
> Maybe spell it out in the log ‘Out of Memory’.

Will do.

> > +			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);
> 
> I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.
> 
> Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.
> 

I understand. What I dislike is having inconsistencies in the layout of
the code.

"Paragraphs", for lack of a better word, are high subjective and a
matter of taste.

Given that subjectivity is not helpful in review and taste is hard to
debate, I prefer to have a single terse rule, that is to avoid any
additional bytes beside the bare minimum to respect checkpatch.

When I feel the need to have a new "conceptual group", then I am forced
to add a comment to explain what is happening. By not allowing blank
lines, I thus feel the pressure for space and explanation more acutely.

Also, this makes a patch context as information-rich as possible.

> I stopped reviewing the code as it became difficult to read IMO and just causing me a headache.
> 
> This problem needs to be addressed by the TSC IMO.

Sorry that it made it more difficult than necessary.
It would be interesting if an addendum to the kernel coding style was
made regarding blank lines.

Regards,
-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization
  2018-03-30 15:53           ` Gaëtan Rivet
@ 2018-03-30 16:22             ` Wiles, Keith
  2018-03-31 15:33               ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Wiles, Keith @ 2018-03-30 16:22 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev



> On Mar 30, 2018, at 10:53 AM, Gaëtan Rivet <gaetan.rivet@6wind.com> wrote:
> 
> Hello Keith,

Hello Gaëtan,

>>> +		layers[i].kvlist = rte_kvargs_parse(copy, NULL);
>>> +		free(copy);
>> 
>> I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.
>> 
>> Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.
>> 
> 
> I understand. What I dislike is having inconsistencies in the layout of
> the code.
> 
> "Paragraphs", for lack of a better word, are high subjective and a
> matter of taste.

I bet your teacher(s) would disagree with that statement with one single paragraph in your book reports :-)
> 
> Given that subjectivity is not helpful in review and taste is hard to
> debate, I prefer to have a single terse rule, that is to avoid any
> additional bytes beside the bare minimum to respect checkpatch.

Taste is hard to debate, but you have gone the extreme route with only the bare minimum blank lines and that is not good as well. A silly script does not read code or understand code we the humans have to make the code readable.
> 
> When I feel the need to have a new "conceptual group", then I am forced
> to add a comment to explain what is happening. By not allowing blank
> lines, I thus feel the pressure for space and explanation more acutely.

A blank can give somewhat convey the same information without a comment, but not in all cases. Even a blank before a group of lines can convey this is a new logic section. I do not buy the point for needing the same terse rule here as most of the coding style is free form and allows for reading between the lines a bit.

We can make a rule here, but no blank lines in a function this size and the patch of this size is making DPDK not as professional looking as it could be.

I am not asking for a blank line after every statement, but when I see functions of this size without a blank lines it means we are not addressing readability for future developers to read this code. If you have to put a comment before a section of code then normally a blank line before the comment is reasonable.

Look at the rest of DPDK code and tell me that we do not use blank lines wisely or no blank lines other then what the silly checkpatch script flags.


Below I added a few blank lines not many, but just few to help the reader detect sections and breaks in the code. Even if you added a few lines or removed a few lines I would think this is much more readable in the long run.

(Wish I could remove the ‘+’ it would help to make my point clearer, but afraid email will left justify the code). 

+int __rte_experimental
+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;
+}

> 
> Also, this makes a patch context as information-rich as possible.
> 
>> I stopped reviewing the code as it became difficult to read IMO and just causing me a headache.
>> 
>> This problem needs to be addressed by the TSC IMO.
> 
> Sorry that it made it more difficult than necessary.
> It would be interesting if an addendum to the kernel coding style was
> made regarding blank lines.
> 
> Regards,
> -- 
> Gaëtan Rivet
> 6WIND

Regards,
Keith


^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization
  2018-03-30 16:22             ` Wiles, Keith
@ 2018-03-31 15:33               ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-03-31 15:33 UTC (permalink / raw)
  To: Wiles, Keith; +Cc: dev

On Fri, Mar 30, 2018 at 04:22:15PM +0000, Wiles, Keith wrote:
> 
> 
> > On Mar 30, 2018, at 10:53 AM, Gaëtan Rivet <gaetan.rivet@6wind.com> wrote:
> > 
> > Hello Keith,
> 
> Hello Gaëtan,
> 
> >>> +		layers[i].kvlist = rte_kvargs_parse(copy, NULL);
> >>> +		free(copy);
> >> 
> >> I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.
> >> 
> >> Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.
> >> 
> > 
> > I understand. What I dislike is having inconsistencies in the layout of
> > the code.
> > 
> > "Paragraphs", for lack of a better word, are high subjective and a
> > matter of taste.
> 
> I bet your teacher(s) would disagree with that statement with one single paragraph in your book reports :-)

The utility of using paragraph is not a matter of subjectivity.
How to use them and how to structure information is what I deemed
subjective.

> > 
> > Given that subjectivity is not helpful in review and taste is hard to
> > debate, I prefer to have a single terse rule, that is to avoid any
> > additional bytes beside the bare minimum to respect checkpatch.
> 
> Taste is hard to debate, but you have gone the extreme route with only the bare minimum blank lines and that is not good as well. A silly script does not read code or understand code we the humans have to make the code readable.
> > 
> > When I feel the need to have a new "conceptual group", then I am forced
> > to add a comment to explain what is happening. By not allowing blank
> > lines, I thus feel the pressure for space and explanation more acutely.
> 
> A blank can give somewhat convey the same information without a comment, but not in all cases. Even a blank before a group of lines can convey this is a new logic section. I do not buy the point for needing the same terse rule here as most of the coding style is free form and allows for reading between the lines a bit.
> 
> We can make a rule here, but no blank lines in a function this size and the patch of this size is making DPDK not as professional looking as it could be.
> 

I think one of the main issue anyway is that this function is simply too
large as it is.

As it turns out, I am working on the second side of this work, which is
revamping the device declaration path.

This function will be split in different parts, that will be shorter and
more palatable.

This is a big work, still in progress (the device declaration, not the
split of this function).

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 10/20] eal/dev: implement device iteration
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 10/20] eal/dev: implement device iteration Gaetan Rivet
@ 2018-04-09  7:28         ` Matan Azrad
  2018-04-09  8:16           ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Matan Azrad @ 2018-04-09  7:28 UTC (permalink / raw)
  To: Gaetan Rivet, dev

HI Gaetan

From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
> +/* '\0' forbidden in sym */
> +static const char *
> +strfirstof(const char *str,
> +	   const char *sym)
> +{
> +	const char *s;
> +
> +	for (s = str; s[0] != '\0'; s++) {
> +		const char *c;
> +
> +		for (c = sym; c[0] != '\0'; c++) {
> +			if (c[0] == s[0])
> +				return s;
> +		}
> +	}
> +	return NULL;
> +}
> +

I think you can use strcspn() instead...

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-04-09  7:41         ` Matan Azrad
  2018-04-09  7:47           ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Matan Azrad @ 2018-04-09  7:41 UTC (permalink / raw)
  To: Gaetan Rivet, dev

Hi Gaetan

From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/Makefile                     |  2 +-
>  lib/librte_ether/Makefile        |  3 +-
>  lib/librte_ether/rte_class_eth.c | 73
> ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 76 insertions(+), 2 deletions(-)  create mode 100644
> lib/librte_ether/rte_class_eth.c
> 
> diff --git a/lib/Makefile b/lib/Makefile index 4206485d3..47513f03f 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
> librte_cmdline  DEPDIRS-librte_cmdline := librte_eal
>  DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether  DEPDIRS-librte_ether
> := librte_net librte_eal librte_mempool librte_ring -DEPDIRS-librte_ether +=
> librte_mbuf
> +DEPDIRS-librte_ether += librte_mbuf librte_kvargs
>  DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev  DEPDIRS-
> librte_bbdev := librte_eal librte_mempool librte_mbuf
>  DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev diff --git
> a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index
> 3ca5782bb..a1a0393de 100644
> --- a/lib/librte_ether/Makefile
> +++ b/lib/librte_ether/Makefile
> @@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API  CFLAGS
> += -O3  CFLAGS += $(WERROR_FLAGS)  LDLIBS += -lrte_net -lrte_eal -
> lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf
> +LDLIBS += -lrte_mbuf -lrte_kvargs
> 
>  EXPORT_MAP := rte_ethdev_version.map
> 
>  LIBABIVER := 8
> 
>  SRCS-y += rte_ethdev.c
> +SRCS-y += rte_class_eth.c
>  SRCS-y += rte_flow.c
>  SRCS-y += rte_tm.c
>  SRCS-y += rte_mtr.c
> diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
> new file mode 100644
> index 000000000..97d24781d
> --- /dev/null
> +++ b/lib/librte_ether/rte_class_eth.c
> @@ -0,0 +1,73 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Gaëtan Rivet
> + */
> +
> +#include <string.h>
> +
> +#include <rte_class.h>
> +#include <rte_compat.h>
> +#include <rte_errno.h>
> +#include <rte_kvargs.h>
> +#include <rte_log.h>
> +
> +#include "rte_ethdev.h"
> +#include "rte_ethdev_core.h"
> +
> +enum eth_params {
> +	RTE_ETH_PARAMS_MAX,
> +};
> +
> +static const char *eth_params_keys[] = {
> +	[RTE_ETH_PARAMS_MAX] = NULL,
> +};
> +
> +static int
> +eth_dev_match(struct rte_eth_dev *edev,
> +	      struct rte_kvargs *kvlist)
> +{
> +	(void) kvlist;
> +	(void) edev;
> +	return 0;
> +}
> +
> +static void *
> +eth_dev_iterate(const void *_start,
> +		const char *str,
> +		const struct rte_dev_iterator *it)
> +{
> +	const struct rte_eth_dev *start = _start;
> +	struct rte_device *dev = it->device;
> +	struct rte_kvargs *kvargs = NULL;
> +	struct rte_eth_dev *edev = NULL;
> +	uint16_t p = 0;
> +
> +	if (str != NULL) {
> +		kvargs = rte_kvargs_parse(str, eth_params_keys);
> +		if (kvargs == NULL) {
> +			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
> +			rte_errno = EINVAL;
> +			return NULL;
> +		}
> +	}
> +	if (start)
> +		p = start->data->port_id + 1;
> +	for (p = rte_eth_find_next(p);
> +	     p < RTE_MAX_ETHPORTS;
> +	     p = rte_eth_find_next(p + 1)) {

What are about differed\owned\bonded devices?
What is actually the use cases of this iterator? 
DPDK internal management or applications?

> +		edev = &rte_eth_devices[p];
> +		if (dev != edev->device)
> +			goto next_ethdev;
> +		if (eth_dev_match(edev, kvargs) == 0)
> +			break;
> +next_ethdev:
> +		edev = NULL;
> +	}
> +	rte_kvargs_free(kvargs);
> +	return edev;
> +}
> +
> +struct rte_class rte_class_eth = {
> +	.dev_iterate = eth_dev_iterate,
> +};
> +
> +RTE_REGISTER_CLASS(eth, rte_class_eth);
> --
> 2.11.0


^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class
  2018-04-09  7:41         ` Matan Azrad
@ 2018-04-09  7:47           ` Gaëtan Rivet
  2018-04-09  7:58             ` Matan Azrad
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-09  7:47 UTC (permalink / raw)
  To: Matan Azrad; +Cc: dev

Hi Matan,

On Mon, Apr 09, 2018 at 07:41:58AM +0000, Matan Azrad wrote:
> Hi Gaetan
> 
> From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >  lib/Makefile                     |  2 +-
> >  lib/librte_ether/Makefile        |  3 +-
> >  lib/librte_ether/rte_class_eth.c | 73
> > ++++++++++++++++++++++++++++++++++++++++
> >  3 files changed, 76 insertions(+), 2 deletions(-)  create mode 100644
> > lib/librte_ether/rte_class_eth.c
> > 
> > diff --git a/lib/Makefile b/lib/Makefile index 4206485d3..47513f03f 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
> > librte_cmdline  DEPDIRS-librte_cmdline := librte_eal
> >  DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether  DEPDIRS-librte_ether
> > := librte_net librte_eal librte_mempool librte_ring -DEPDIRS-librte_ether +=
> > librte_mbuf
> > +DEPDIRS-librte_ether += librte_mbuf librte_kvargs
> >  DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev  DEPDIRS-
> > librte_bbdev := librte_eal librte_mempool librte_mbuf
> >  DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev diff --git
> > a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index
> > 3ca5782bb..a1a0393de 100644
> > --- a/lib/librte_ether/Makefile
> > +++ b/lib/librte_ether/Makefile
> > @@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API  CFLAGS
> > += -O3  CFLAGS += $(WERROR_FLAGS)  LDLIBS += -lrte_net -lrte_eal -
> > lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf
> > +LDLIBS += -lrte_mbuf -lrte_kvargs
> > 
> >  EXPORT_MAP := rte_ethdev_version.map
> > 
> >  LIBABIVER := 8
> > 
> >  SRCS-y += rte_ethdev.c
> > +SRCS-y += rte_class_eth.c
> >  SRCS-y += rte_flow.c
> >  SRCS-y += rte_tm.c
> >  SRCS-y += rte_mtr.c
> > diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
> > new file mode 100644
> > index 000000000..97d24781d
> > --- /dev/null
> > +++ b/lib/librte_ether/rte_class_eth.c
> > @@ -0,0 +1,73 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2018 Gaëtan Rivet
> > + */
> > +
> > +#include <string.h>
> > +
> > +#include <rte_class.h>
> > +#include <rte_compat.h>
> > +#include <rte_errno.h>
> > +#include <rte_kvargs.h>
> > +#include <rte_log.h>
> > +
> > +#include "rte_ethdev.h"
> > +#include "rte_ethdev_core.h"
> > +
> > +enum eth_params {
> > +	RTE_ETH_PARAMS_MAX,
> > +};
> > +
> > +static const char *eth_params_keys[] = {
> > +	[RTE_ETH_PARAMS_MAX] = NULL,
> > +};
> > +
> > +static int
> > +eth_dev_match(struct rte_eth_dev *edev,
> > +	      struct rte_kvargs *kvlist)
> > +{
> > +	(void) kvlist;
> > +	(void) edev;
> > +	return 0;
> > +}
> > +
> > +static void *
> > +eth_dev_iterate(const void *_start,
> > +		const char *str,
> > +		const struct rte_dev_iterator *it)
> > +{
> > +	const struct rte_eth_dev *start = _start;
> > +	struct rte_device *dev = it->device;
> > +	struct rte_kvargs *kvargs = NULL;
> > +	struct rte_eth_dev *edev = NULL;
> > +	uint16_t p = 0;
> > +
> > +	if (str != NULL) {
> > +		kvargs = rte_kvargs_parse(str, eth_params_keys);
> > +		if (kvargs == NULL) {
> > +			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
> > +			rte_errno = EINVAL;
> > +			return NULL;
> > +		}
> > +	}
> > +	if (start)
> > +		p = start->data->port_id + 1;
> > +	for (p = rte_eth_find_next(p);
> > +	     p < RTE_MAX_ETHPORTS;
> > +	     p = rte_eth_find_next(p + 1)) {
> 
> What are about differed\owned\bonded devices?
> What is actually the use cases of this iterator? 
> DPDK internal management or applications?
> 

This API is public, so anyone can use it.
It should be primarily used by internal systems however.
I do not think Applications would be interested in calling the
dev_iterate ops.

The EAL would provide a way to list interfaces from each layers. Then
DPDK libraries (such as librte_ether) would translate this following
their internal rules. librte_ether would thus for example here translate
an rte_eth_dev handle to a port_id, that an application could use. If
there was a need to filter by owner_id, then it would be the job of
librte_ether.

The EAL cannot keep track of layers specifics, it can only provide
generic APIs.

> > +		edev = &rte_eth_devices[p];
> > +		if (dev != edev->device)
> > +			goto next_ethdev;
> > +		if (eth_dev_match(edev, kvargs) == 0)
> > +			break;
> > +next_ethdev:
> > +		edev = NULL;
> > +	}
> > +	rte_kvargs_free(kvargs);
> > +	return edev;
> > +}
> > +
> > +struct rte_class rte_class_eth = {
> > +	.dev_iterate = eth_dev_iterate,
> > +};
> > +
> > +RTE_REGISTER_CLASS(eth, rte_class_eth);
> > --
> > 2.11.0
> 

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class
  2018-04-09  7:47           ` Gaëtan Rivet
@ 2018-04-09  7:58             ` Matan Azrad
  2018-04-09  8:12               ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Matan Azrad @ 2018-04-09  7:58 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev

Hi Gaetan

From: Gaëtan Rivet, Monday, April 9, 2018 10:47 AM
> Hi Matan,
> 
> On Mon, Apr 09, 2018 at 07:41:58AM +0000, Matan Azrad wrote:
> > Hi Gaetan
> >
> > From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > ---
> > >  lib/Makefile                     |  2 +-
> > >  lib/librte_ether/Makefile        |  3 +-
> > >  lib/librte_ether/rte_class_eth.c | 73
> > > ++++++++++++++++++++++++++++++++++++++++
> > >  3 files changed, 76 insertions(+), 2 deletions(-)  create mode
> > > 100644 lib/librte_ether/rte_class_eth.c
> > >
> > > diff --git a/lib/Makefile b/lib/Makefile index 4206485d3..47513f03f
> > > 100644
> > > --- a/lib/Makefile
> > > +++ b/lib/Makefile
> > > @@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
> > > librte_cmdline  DEPDIRS-librte_cmdline := librte_eal
> > >  DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
> > > DEPDIRS-librte_ether := librte_net librte_eal librte_mempool
> > > librte_ring -DEPDIRS-librte_ether += librte_mbuf
> > > +DEPDIRS-librte_ether += librte_mbuf librte_kvargs
> > >  DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev  DEPDIRS-
> > > librte_bbdev := librte_eal librte_mempool librte_mbuf
> > >  DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev diff --git
> > > a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index
> > > 3ca5782bb..a1a0393de 100644
> > > --- a/lib/librte_ether/Makefile
> > > +++ b/lib/librte_ether/Makefile
> > > @@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
> CFLAGS
> > > += -O3  CFLAGS += $(WERROR_FLAGS)  LDLIBS += -lrte_net -lrte_eal -
> > > lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf
> > > +LDLIBS += -lrte_mbuf -lrte_kvargs
> > >
> > >  EXPORT_MAP := rte_ethdev_version.map
> > >
> > >  LIBABIVER := 8
> > >
> > >  SRCS-y += rte_ethdev.c
> > > +SRCS-y += rte_class_eth.c
> > >  SRCS-y += rte_flow.c
> > >  SRCS-y += rte_tm.c
> > >  SRCS-y += rte_mtr.c
> > > diff --git a/lib/librte_ether/rte_class_eth.c
> > > b/lib/librte_ether/rte_class_eth.c
> > > new file mode 100644
> > > index 000000000..97d24781d
> > > --- /dev/null
> > > +++ b/lib/librte_ether/rte_class_eth.c
> > > @@ -0,0 +1,73 @@
> > > +/* SPDX-License-Identifier: BSD-3-Clause
> > > + * Copyright(c) 2018 Gaëtan Rivet
> > > + */
> > > +
> > > +#include <string.h>
> > > +
> > > +#include <rte_class.h>
> > > +#include <rte_compat.h>
> > > +#include <rte_errno.h>
> > > +#include <rte_kvargs.h>
> > > +#include <rte_log.h>
> > > +
> > > +#include "rte_ethdev.h"
> > > +#include "rte_ethdev_core.h"
> > > +
> > > +enum eth_params {
> > > +	RTE_ETH_PARAMS_MAX,
> > > +};
> > > +
> > > +static const char *eth_params_keys[] = {
> > > +	[RTE_ETH_PARAMS_MAX] = NULL,
> > > +};
> > > +
> > > +static int
> > > +eth_dev_match(struct rte_eth_dev *edev,
> > > +	      struct rte_kvargs *kvlist)
> > > +{
> > > +	(void) kvlist;
> > > +	(void) edev;
> > > +	return 0;
> > > +}
> > > +
> > > +static void *
> > > +eth_dev_iterate(const void *_start,
> > > +		const char *str,
> > > +		const struct rte_dev_iterator *it) {
> > > +	const struct rte_eth_dev *start = _start;
> > > +	struct rte_device *dev = it->device;
> > > +	struct rte_kvargs *kvargs = NULL;
> > > +	struct rte_eth_dev *edev = NULL;
> > > +	uint16_t p = 0;
> > > +
> > > +	if (str != NULL) {
> > > +		kvargs = rte_kvargs_parse(str, eth_params_keys);
> > > +		if (kvargs == NULL) {
> > > +			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
> > > +			rte_errno = EINVAL;
> > > +			return NULL;
> > > +		}
> > > +	}
> > > +	if (start)
> > > +		p = start->data->port_id + 1;
> > > +	for (p = rte_eth_find_next(p);
> > > +	     p < RTE_MAX_ETHPORTS;
> > > +	     p = rte_eth_find_next(p + 1)) {
> >
> > What are about differed\owned\bonded devices?
> > What is actually the use cases of this iterator?
> > DPDK internal management or applications?
> >
> 
> This API is public, so anyone can use it.
> It should be primarily used by internal systems however.
> I do not think Applications would be interested in calling the dev_iterate ops.
> 
> The EAL would provide a way to list interfaces from each layers. Then DPDK
> libraries (such as librte_ether) would translate this following their internal
> rules. librte_ether would thus for example here translate an rte_eth_dev
> handle to a port_id, that an application could use. If there was a need to filter
> by owner_id, then it would be the job of librte_ether.
> 
> The EAL cannot keep track of layers specifics, it can only provide generic APIs.

This is exactly what I'm asking, what is the right behavior here?

Now, The code is skipping DEFFERED devices but iterating over owned\bonded devices.
Looks like any USED port should be iterated...

Moreover, looks like there is chance to iterate over EAL device more than 1 time for loop, Is it OK?

> > > +		edev = &rte_eth_devices[p];
> > > +		if (dev != edev->device)
> > > +			goto next_ethdev;
> > > +		if (eth_dev_match(edev, kvargs) == 0)
> > > +			break;
> > > +next_ethdev:
> > > +		edev = NULL;
> > > +	}
> > > +	rte_kvargs_free(kvargs);
> > > +	return edev;
> > > +}
> > > +
> > > +struct rte_class rte_class_eth = {
> > > +	.dev_iterate = eth_dev_iterate,
> > > +};
> > > +
> > > +RTE_REGISTER_CLASS(eth, rte_class_eth);
> > > --
> > > 2.11.0
> >
> 
> --
> Gaëtan Rivet
> 6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class
  2018-04-09  7:58             ` Matan Azrad
@ 2018-04-09  8:12               ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-09  8:12 UTC (permalink / raw)
  To: Matan Azrad; +Cc: dev

On Mon, Apr 09, 2018 at 07:58:08AM +0000, Matan Azrad wrote:
> Hi Gaetan
> 
> From: Gaëtan Rivet, Monday, April 9, 2018 10:47 AM
> > Hi Matan,
> > 
> > On Mon, Apr 09, 2018 at 07:41:58AM +0000, Matan Azrad wrote:
> > > Hi Gaetan
> > >
> > > From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
> > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > ---
> > > >  lib/Makefile                     |  2 +-
> > > >  lib/librte_ether/Makefile        |  3 +-
> > > >  lib/librte_ether/rte_class_eth.c | 73
> > > > ++++++++++++++++++++++++++++++++++++++++
> > > >  3 files changed, 76 insertions(+), 2 deletions(-)  create mode
> > > > 100644 lib/librte_ether/rte_class_eth.c
> > > >
> > > > diff --git a/lib/Makefile b/lib/Makefile index 4206485d3..47513f03f
> > > > 100644
> > > > --- a/lib/Makefile
> > > > +++ b/lib/Makefile
> > > > @@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
> > > > librte_cmdline  DEPDIRS-librte_cmdline := librte_eal
> > > >  DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
> > > > DEPDIRS-librte_ether := librte_net librte_eal librte_mempool
> > > > librte_ring -DEPDIRS-librte_ether += librte_mbuf
> > > > +DEPDIRS-librte_ether += librte_mbuf librte_kvargs
> > > >  DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev  DEPDIRS-
> > > > librte_bbdev := librte_eal librte_mempool librte_mbuf
> > > >  DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev diff --git
> > > > a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index
> > > > 3ca5782bb..a1a0393de 100644
> > > > --- a/lib/librte_ether/Makefile
> > > > +++ b/lib/librte_ether/Makefile
> > > > @@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
> > CFLAGS
> > > > += -O3  CFLAGS += $(WERROR_FLAGS)  LDLIBS += -lrte_net -lrte_eal -
> > > > lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf
> > > > +LDLIBS += -lrte_mbuf -lrte_kvargs
> > > >
> > > >  EXPORT_MAP := rte_ethdev_version.map
> > > >
> > > >  LIBABIVER := 8
> > > >
> > > >  SRCS-y += rte_ethdev.c
> > > > +SRCS-y += rte_class_eth.c
> > > >  SRCS-y += rte_flow.c
> > > >  SRCS-y += rte_tm.c
> > > >  SRCS-y += rte_mtr.c
> > > > diff --git a/lib/librte_ether/rte_class_eth.c
> > > > b/lib/librte_ether/rte_class_eth.c
> > > > new file mode 100644
> > > > index 000000000..97d24781d
> > > > --- /dev/null
> > > > +++ b/lib/librte_ether/rte_class_eth.c
> > > > @@ -0,0 +1,73 @@
> > > > +/* SPDX-License-Identifier: BSD-3-Clause
> > > > + * Copyright(c) 2018 Gaëtan Rivet
> > > > + */
> > > > +
> > > > +#include <string.h>
> > > > +
> > > > +#include <rte_class.h>
> > > > +#include <rte_compat.h>
> > > > +#include <rte_errno.h>
> > > > +#include <rte_kvargs.h>
> > > > +#include <rte_log.h>
> > > > +
> > > > +#include "rte_ethdev.h"
> > > > +#include "rte_ethdev_core.h"
> > > > +
> > > > +enum eth_params {
> > > > +	RTE_ETH_PARAMS_MAX,
> > > > +};
> > > > +
> > > > +static const char *eth_params_keys[] = {
> > > > +	[RTE_ETH_PARAMS_MAX] = NULL,
> > > > +};
> > > > +
> > > > +static int
> > > > +eth_dev_match(struct rte_eth_dev *edev,
> > > > +	      struct rte_kvargs *kvlist)
> > > > +{
> > > > +	(void) kvlist;
> > > > +	(void) edev;
> > > > +	return 0;
> > > > +}
> > > > +
> > > > +static void *
> > > > +eth_dev_iterate(const void *_start,
> > > > +		const char *str,
> > > > +		const struct rte_dev_iterator *it) {
> > > > +	const struct rte_eth_dev *start = _start;
> > > > +	struct rte_device *dev = it->device;
> > > > +	struct rte_kvargs *kvargs = NULL;
> > > > +	struct rte_eth_dev *edev = NULL;
> > > > +	uint16_t p = 0;
> > > > +
> > > > +	if (str != NULL) {
> > > > +		kvargs = rte_kvargs_parse(str, eth_params_keys);
> > > > +		if (kvargs == NULL) {
> > > > +			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
> > > > +			rte_errno = EINVAL;
> > > > +			return NULL;
> > > > +		}
> > > > +	}
> > > > +	if (start)
> > > > +		p = start->data->port_id + 1;
> > > > +	for (p = rte_eth_find_next(p);
> > > > +	     p < RTE_MAX_ETHPORTS;
> > > > +	     p = rte_eth_find_next(p + 1)) {
> > >
> > > What are about differed\owned\bonded devices?
> > > What is actually the use cases of this iterator?
> > > DPDK internal management or applications?
> > >
> > 
> > This API is public, so anyone can use it.
> > It should be primarily used by internal systems however.
> > I do not think Applications would be interested in calling the dev_iterate ops.
> > 
> > The EAL would provide a way to list interfaces from each layers. Then DPDK
> > libraries (such as librte_ether) would translate this following their internal
> > rules. librte_ether would thus for example here translate an rte_eth_dev
> > handle to a port_id, that an application could use. If there was a need to filter
> > by owner_id, then it would be the job of librte_ether.
> > 
> > The EAL cannot keep track of layers specifics, it can only provide generic APIs.
> 
> This is exactly what I'm asking, what is the right behavior here?
> 

>From the EAL PoV: The layer should be perfectly transparent: all
internal objects should be returned.

> Now, The code is skipping DEFFERED devices but iterating over owned\bonded devices.
> Looks like any USED port should be iterated...
> 

Right, actually DEFERRED devices should probably be returned as well,
good catch.

> Moreover, looks like there is chance to iterate over EAL device more than 1 time for loop, Is it OK?
> 

If by EAL device you mean rte_device, then yes, this is OK.
Due to mlx4 PMD, it is now possible for PMDs to spawn several
rte_eth_dev per rte_pci_device. A single rte_pci_device is a
specialization of an rte_device. So an rte_device can be shared by
several rte_eth_dev, and would be returned several times if need be.

Each time however, the rte_eth_dev layer should iterate over its
internal object, meaning that even if the rte_device is the same, the
overall context would still change.

> > > > +		edev = &rte_eth_devices[p];
> > > > +		if (dev != edev->device)
> > > > +			goto next_ethdev;
> > > > +		if (eth_dev_match(edev, kvargs) == 0)
> > > > +			break;
> > > > +next_ethdev:
> > > > +		edev = NULL;
> > > > +	}
> > > > +	rte_kvargs_free(kvargs);
> > > > +	return edev;
> > > > +}
> > > > +
> > > > +struct rte_class rte_class_eth = {
> > > > +	.dev_iterate = eth_dev_iterate,
> > > > +};
> > > > +
> > > > +RTE_REGISTER_CLASS(eth, rte_class_eth);
> > > > --
> > > > 2.11.0
> > >
> > 
> > --
> > Gaëtan Rivet
> > 6WIND

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v4 10/20] eal/dev: implement device iteration
  2018-04-09  7:28         ` Matan Azrad
@ 2018-04-09  8:16           ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-09  8:16 UTC (permalink / raw)
  To: Matan Azrad; +Cc: dev

On Mon, Apr 09, 2018 at 07:28:00AM +0000, Matan Azrad wrote:
> HI Gaetan
> 
> From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
> > +/* '\0' forbidden in sym */
> > +static const char *
> > +strfirstof(const char *str,
> > +	   const char *sym)
> > +{
> > +	const char *s;
> > +
> > +	for (s = str; s[0] != '\0'; s++) {
> > +		const char *c;
> > +
> > +		for (c = sym; c[0] != '\0'; c++) {
> > +			if (c[0] == s[0])
> > +				return s;
> > +		}
> > +	}
> > +	return NULL;
> > +}
> > +
> 
> I think you can use strcspn() instead...
> 

Indeed, didn't know about it, I will change it.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 00/21] Device querying
  2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
                         ` (19 preceding siblings ...)
  2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 20/20] app/testpmd: add show device command Gaetan Rivet
@ 2018-04-11  0:04       ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 01/21] kvargs: build before EAL Gaetan Rivet
                           ` (20 more replies)
  20 siblings, 21 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman, Keith Wiles, Matan Azrad

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.

v5:

  * Rebased on master
  * Use strcspn instead of custom function.
  * Introduce private generic rte_eth_dev iterator.
    This could be generalized to other iterators
    (port_next, owner_id-aware, etc).
  * Attempted to support meson.build.
    Got lost in the implicit variables declared
    when inversing dependencies between kvargs and EAL.
    Removed anything related to meson.
  * Postponed genericization of work from
    device query to device declaration.
    Much bigger than anticipated, will let this
    part get in first and iterate over it.

Gaetan Rivet (21):
  kvargs: build before EAL
  eal: list acceptable init priorities
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: fix find device implementation
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: fix find device implementation
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: add private generic device iterator
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                             |  52 ++++
 drivers/bus/pci/Makefile                           |   2 +-
 drivers/bus/pci/pci_common.c                       |  87 +++++-
 drivers/bus/pci/rte_bus_pci.h                      |   3 +
 drivers/bus/vdev/Makefile                          |   3 +-
 drivers/bus/vdev/rte_bus_vdev.h                    |   3 +
 drivers/bus/vdev/vdev.c                            |  66 ++++-
 lib/Makefile                                       |   7 +-
 lib/librte_eal/bsdapp/eal/Makefile                 |   2 +
 lib/librte_eal/common/Makefile                     |   4 +-
 lib/librte_eal/common/eal_common_class.c           |  62 ++++
 lib/librte_eal/common/eal_common_dev.c             | 316 +++++++++++++++++++++
 lib/librte_eal/common/eal_common_log.c             |   2 +-
 lib/librte_eal/common/include/rte_bus.h            |   3 +-
 lib/librte_eal/common/include/rte_class.h          | 127 +++++++++
 lib/librte_eal/common/include/rte_common.h         |  32 ++-
 lib/librte_eal/common/include/rte_dev.h            |  97 +++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   2 +
 lib/librte_eal/rte_eal_version.map                 |   4 +
 lib/librte_ether/Makefile                          |   4 +-
 lib/librte_ether/eth_private.c                     |  32 +++
 lib/librte_ether/eth_private.h                     |  26 ++
 lib/librte_ether/rte_class_eth.c                   |  86 ++++++
 lib/librte_kvargs/Makefile                         |   3 +-
 lib/librte_kvargs/rte_kvargs.c                     |  12 +-
 lib/librte_kvargs/rte_kvargs.h                     |  28 ++
 lib/librte_kvargs/rte_kvargs_version.map           |   7 +
 .../include => librte_kvargs}/rte_string_fns.h     |   0
 28 files changed, 1045 insertions(+), 27 deletions(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ether/eth_private.c
 create mode 100644 lib/librte_ether/eth_private.h
 create mode 100644 lib/librte_ether/rte_class_eth.c
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 01/21] kvargs: build before EAL
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities Gaetan Rivet
                           ` (19 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                                                      | 3 +--
 lib/librte_eal/common/Makefile                                    | 2 +-
 lib/librte_kvargs/Makefile                                        | 3 ++-
 lib/librte_kvargs/rte_kvargs.c                                    | 2 +-
 lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
 5 files changed, 5 insertions(+), 5 deletions(-)
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a606..fc7a55a37 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -71,8 +72,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index ea824a3a8..75776d3e2 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -9,7 +9,7 @@ INC += rte_errno.h rte_launch.h rte_lcore.h
 INC += rte_log.h rte_memory.h rte_memzone.h
 INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
+INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 4eaa9334d..e026ecc21 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -37,7 +37,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c
 
 # install includes
 INCS := rte_kvargs.h
+INCS += rte_string_fns.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS)
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..0a1abf579 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -7,8 +7,8 @@
 #include <stdlib.h>
 
 #include <rte_log.h>
-#include <rte_string_fns.h>
 
+#include "rte_string_fns.h"
 #include "rte_kvargs.h"
 
 /*
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_kvargs/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_kvargs/rte_string_fns.h
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 01/21] kvargs: build before EAL Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-12 11:28           ` Neil Horman
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 03/21] eal: introduce dtor macros Gaetan Rivet
                           ` (18 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Build a central list to quickly see each used priorities for
constructors, allowing to verify that they are both above 100 and in the
proper order.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
 lib/librte_eal/common/eal_common_log.c     | 2 +-
 lib/librte_eal/common/include/rte_bus.h    | 2 +-
 lib/librte_eal/common/include/rte_common.h | 8 +++++++-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index a27192620..36b9d6e08 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
 };
 
 /* Logging should be first initializer (before drivers and bus) */
-RTE_INIT_PRIO(rte_log_init, 101);
+RTE_INIT_PRIO(rte_log_init, LOG);
 static void
 rte_log_init(void)
 {
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 6fb08341a..eb9eded4e 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
  * The constructor has higher priority than PMD constructors.
  */
 #define RTE_REGISTER_BUS(nm, bus) \
-RTE_INIT_PRIO(businitfn_ ##nm, 110); \
+RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
 static void businitfn_ ##nm(void) \
 {\
 	(bus).name = RTE_STR(nm);\
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 6c5bc5a76..8f04518f7 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
  */
 #define RTE_SET_USED(x) (void)(x)
 
+#define RTE_PRIORITY_LOG 101
+#define RTE_PRIORITY_BUS 110
+
+#define RTE_PRIO(prio) \
+	RTE_PRIORITY_ ## prio
+
 /**
  * Run function before main() with low priority.
  *
@@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
  *   Lowest number is the first to run.
  */
 #define RTE_INIT_PRIO(func, prio) \
-static void __attribute__((constructor(prio), used)) func(void)
+static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
  * Force a function to be inlined
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 03/21] eal: introduce dtor macros
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 01/21] kvargs: build before EAL Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 04/21] eal: introduce device class abstraction Gaetan Rivet
                           ` (17 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 8f04518f7..f326e1c30 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -111,6 +111,29 @@ static void __attribute__((constructor, used)) func(void)
 static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+static void __attribute__((destructor, used)) func(void)
+
+/**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 04/21] eal: introduce device class abstraction
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (2 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 03/21] eal: introduce dtor macros Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 05/21] eal/class: register destructor Gaetan Rivet
                           ` (16 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 7 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index ed1d17b44..c7d5abcd9 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 75776d3e2..607ae0447 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..b5e550a34
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index f326e1c30..a3e7d582c 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 
 #define RTE_PRIO(prio) \
 	RTE_PRIORITY_ ## prio
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index b9c7727c8..06ab30cad 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -56,6 +56,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index dd38783a2..afe6ce1b9 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -218,6 +218,8 @@ EXPERIMENTAL {
 	rte_eal_devargs_insert;
 	rte_eal_devargs_parse;
 	rte_eal_devargs_remove;
+	rte_class_register;
+	rte_class_unregister;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
 	rte_eal_mbuf_user_pool_ops;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 05/21] eal/class: register destructor
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (3 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 04/21] eal: introduce device class abstraction Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 06/21] eal/dev: add device iterator interface Gaetan Rivet
                           ` (15 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index b5e550a34..e8176f5e1 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 06/21] eal/dev: add device iterator interface
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (4 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 05/21] eal/class: register destructor Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 07/21] eal/class: add device iteration Gaetan Rivet
                           ` (14 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index b688f1efd..937ff6079 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -263,6 +263,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 07/21] eal/class: add device iteration
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (5 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 06/21] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 08/21] eal/bus: " Gaetan Rivet
                           ` (13 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index e8176f5e1..9d5b06807 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 08/21] eal/bus: add device iteration
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (6 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 07/21] eal/class: add device iteration Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 09/21] eal/dev: implement device iteration initialization Gaetan Rivet
                           ` (12 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 09/21] eal/dev: implement device iteration initialization
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (7 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 08/21] eal/bus: " Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 10/21] eal/dev: implement device iteration Gaetan Rivet
                           ` (11 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@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

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 10/21] eal/dev: implement device iteration
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (8 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 09/21] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 11/21] kvargs: add generic string matching callback Gaetan Rivet
                           ` (10 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  26 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 195 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 1a671758a..645cb2ce8 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -20,6 +20,28 @@
 
 #include "eal_private.h"
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -355,3 +377,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 	}
 	return -rte_errno;
 }
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	size_t end;
+	char *copy;
+
+	end = strcspn(str, ",/");
+	if (str[end] == ',') {
+		copy = strdup(&str[end + 1]);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_copy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_copy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index f84128e5c..b35fa3cd9 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -334,6 +334,32 @@ __rte_experimental
 int
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index cad24376f..f75aa7245 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -221,6 +221,7 @@ EXPERIMENTAL {
 	rte_class_register;
 	rte_class_unregister;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
 	rte_eal_mbuf_user_pool_ops;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 11/21] kvargs: add generic string matching callback
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (9 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 10/21] eal/dev: implement device iteration Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 12/21] bus/pci: fix find device implementation Gaetan Rivet
                           ` (9 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
 4 files changed, 46 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 1b17526f7..4206485d3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 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
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 0a1abf579..6ee04cbb9 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -180,3 +180,13 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -strcmp(str, value);
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..c07c6fea5 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -121,6 +123,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..e2f663a88 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 12/21] bus/pci: fix find device implementation
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (10 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 11/21] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 13/21] bus/pci: implement device iteration and comparison Gaetan Rivet
                           ` (8 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set, and a device before it matches the data
passed for comparison, then this first device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2a00f365a..2c45f8151 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -459,17 +459,20 @@ static struct rte_device *
 pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		const void *data)
 {
-	struct rte_pci_device *dev;
+	const struct rte_pci_device *pstart;
+	struct rte_pci_device *pdev;
 
-	FOREACH_DEVICE_ON_PCIBUS(dev) {
-		if (start && &dev->device == start) {
-			start = NULL; /* starting point found */
-			continue;
-		}
-		if (cmp(&dev->device, data) == 0)
-			return &dev->device;
+	if (start != NULL) {
+		pstart = RTE_DEV_TO_PCI_CONST(start);
+		pdev = TAILQ_NEXT(pstart, next);
+	} else {
+		pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
+	}
+	while (pdev != NULL) {
+		if (cmp(&pdev->device, data) == 0)
+			return &pdev->device;
+		pdev = TAILQ_NEXT(pdev, next);
 	}
-
 	return NULL;
 }
 
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 357afb912..458e6d076 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -74,6 +74,9 @@ struct rte_pci_device {
  */
 #define RTE_DEV_TO_PCI(ptr) container_of(ptr, struct rte_pci_device, device)
 
+#define RTE_DEV_TO_PCI_CONST(ptr) \
+	container_of(ptr, const struct rte_pci_device, device)
+
 #define RTE_ETH_DEV_TO_PCI(eth_dev)	RTE_DEV_TO_PCI((eth_dev)->device)
 
 /** Any PCI device identifier (vendor, device, ...) */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 13/21] bus/pci: implement device iteration and comparison
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (11 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 12/21] bus/pci: fix find device implementation Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 14/21] bus/pci: add device matching field id Gaetan Rivet
                           ` (7 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index f3df1c4ce..73498dc77 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -50,7 +50,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common
 CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2c45f8151..bd9ecddc6 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -13,6 +13,7 @@
 
 #include <rte_errno.h>
 #include <rte_interrupts.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
@@ -497,6 +498,46 @@ pci_unplug(struct rte_device *dev)
 	return ret;
 }
 
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+static void *
+pci_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_device *dev;
+	struct rte_kvargs *kvargs = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = pci_find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 struct rte_pci_bus rte_pci_bus = {
 	.bus = {
 		.scan = rte_pci_scan,
@@ -506,6 +547,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 14/21] bus/pci: add device matching field id
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (12 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 13/21] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 15/21] bus/vdev: fix find device implementation Gaetan Rivet
                           ` (6 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index bd9ecddc6..3666e4caa 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -499,21 +499,45 @@ pci_unplug(struct rte_device *dev)
 }
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return rte_pci_addr_cmp(addr1, addr2);
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 15/21] bus/vdev: fix find device implementation
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (13 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 14/21] bus/pci: add device matching field id Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 16/21] bus/vdev: implement device iteration Gaetan Rivet
                           ` (5 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set and a device before it matches the data,
this device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/vdev/rte_bus_vdev.h b/drivers/bus/vdev/rte_bus_vdev.h
index f9d8a2383..4da9967c6 100644
--- a/drivers/bus/vdev/rte_bus_vdev.h
+++ b/drivers/bus/vdev/rte_bus_vdev.h
@@ -53,6 +53,9 @@ struct rte_vdev_device {
 #define RTE_DEV_TO_VDEV(ptr) \
 	container_of(ptr, struct rte_vdev_device, device)
 
+#define RTE_DEV_TO_VDEV_CONST(ptr) \
+	container_of(ptr, const struct rte_vdev_device, device)
+
 static inline const char *
 rte_vdev_device_name(const struct rte_vdev_device *dev)
 {
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 7eae319cb..66fe63e85 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -386,15 +386,19 @@ static struct rte_device *
 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		 const void *data)
 {
+	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
 
-	TAILQ_FOREACH(dev, &vdev_device_list, next) {
-		if (start && &dev->device == start) {
-			start = NULL;
-			continue;
-		}
+	if (start != NULL) {
+		vstart = RTE_DEV_TO_VDEV_CONST(start);
+		dev = TAILQ_NEXT(vstart, next);
+	} else {
+		dev = TAILQ_FIRST(&vdev_device_list);
+	}
+	while (dev != NULL) {
 		if (cmp(&dev->device, data) == 0)
 			return &dev->device;
+		dev = TAILQ_NEXT(dev, next);
 	}
 	return NULL;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 16/21] bus/vdev: implement device iteration
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (14 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 15/21] bus/vdev: fix find device implementation Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 17/21] bus/vdev: add device matching field driver Gaetan Rivet
                           ` (4 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 24d424a38..52728833c 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 66fe63e85..1cc469da0 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -43,6 +43,7 @@
 #include <rte_bus.h>
 #include <rte_common.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
 #include <rte_memory.h>
 #include <rte_tailq.h>
 #include <rte_spinlock.h>
@@ -415,6 +416,46 @@ vdev_unplug(struct rte_device *dev)
 	return rte_vdev_uninit(dev->name);
 }
 
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+static void *
+vdev_dev_iterate(const void *start,
+		 const char *str,
+		 const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
@@ -422,6 +463,7 @@ static struct rte_bus rte_vdev_bus = {
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 17/21] bus/vdev: add device matching field driver
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (15 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 16/21] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 18/21] ethdev: add private generic device iterator Gaetan Rivet
                           ` (3 subsequent siblings)
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  1 +
 drivers/bus/vdev/vdev.c   | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 52728833c..db6bee98a 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -10,6 +10,7 @@ LIB = librte_bus_vdev.a
 
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 # versioning export map
 EXPORT_MAP := rte_bus_vdev_version.map
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 1cc469da0..fae75d285 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -417,10 +417,12 @@ vdev_unplug(struct rte_device *dev)
 }
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -429,9 +431,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 18/21] ethdev: add private generic device iterator
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (16 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 17/21] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  8:41           ` Gaëtan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 19/21] ethdev: register ether layer as a class Gaetan Rivet
                           ` (2 subsequent siblings)
  20 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This iterator can be customized with a comparison function that will
trigger a stopping condition.

It can be leveraged to write several different iterators that have
similar but non-identical purposes.

It is private to librte_ether.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/Makefile      |  1 +
 lib/librte_ether/eth_private.c | 32 ++++++++++++++++++++++++++++++++
 lib/librte_ether/eth_private.h | 26 ++++++++++++++++++++++++++
 3 files changed, 59 insertions(+)
 create mode 100644 lib/librte_ether/eth_private.c
 create mode 100644 lib/librte_ether/eth_private.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c2f2f7d82..2fa133fbc 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 9
 
+SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
diff --git a/lib/librte_ether/eth_private.c b/lib/librte_ether/eth_private.c
new file mode 100644
index 000000000..311c5d6b2
--- /dev/null
+++ b/lib/librte_ether/eth_private.c
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan
+ */
+
+#include "rte_ethdev.h"
+#include "eth_private.h"
+
+struct rte_eth_dev *
+eth_find_device(const void *_start, rte_eth_cmp_t cmp,
+		const void *data)
+{
+	const struct rte_eth_dev *start = _start;
+	struct rte_eth_dev *edev;
+	ptrdiff_t idx;
+
+	/* Avoid Undefined Behaviour */
+	if (start != NULL &&
+	    (start < &rte_eth_devices[0] ||
+	     start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+		return NULL;
+	if (start != NULL)
+		idx = start - &rte_eth_devices[0] + 1;
+	else
+		idx = 0;
+	for (; idx < RTE_MAX_ETHPORTS; idx++) {
+		edev = &rte_eth_devices[idx];
+		if (cmp(edev, data) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
diff --git a/lib/librte_ether/eth_private.h b/lib/librte_ether/eth_private.h
new file mode 100644
index 000000000..c3c831dc9
--- /dev/null
+++ b/lib/librte_ether/eth_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan
+ */
+
+#ifndef _ETH_PRIVATE_H_
+#define _ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const void *_start, rte_eth_cmp_t cmp,
+		const void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _ETH_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 19/21] ethdev: register ether layer as a class
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (17 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 18/21] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 20/21] ethdev: add device matching field name Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 21/21] app/testpmd: add show device command Gaetan Rivet
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                     |  2 +-
 lib/librte_ether/Makefile        |  3 +-
 lib/librte_ether/rte_class_eth.c | 79 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_ether/rte_class_eth.c

diff --git a/lib/Makefile b/lib/Makefile
index 4206485d3..47513f03f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf
+DEPDIRS-librte_ether += librte_mbuf librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 2fa133fbc..d4c3a8d06 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
@@ -20,6 +20,7 @@ LIBABIVER := 9
 
 SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
new file mode 100644
index 000000000..32c736d32
--- /dev/null
+++ b/lib/librte_ether/rte_class_eth.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "eth_private.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+	struct rte_device *device;
+	struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+	(&(const struct eth_dev_match_arg) { \
+		.device = (d), \
+		.kvlist = (k), \
+	})
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+	      const void *_arg)
+{
+	const struct eth_dev_match_arg *arg = _arg;
+	const struct rte_kvargs *kvlist = arg->kvlist;
+
+	if (edev->state == RTE_ETH_DEV_UNUSED)
+		return -1;
+	if (edev->device != arg->device)
+		return -1;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	edev = eth_find_device(start, eth_dev_match,
+			       eth_dev_match_arg(it->device, kvargs));
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 20/21] ethdev: add device matching field name
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (18 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 19/21] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 21/21] app/testpmd: add show device command Gaetan Rivet
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
index 32c736d32..d8d8e8845 100644
--- a/lib/librte_ether/rte_class_eth.c
+++ b/lib/librte_ether/rte_class_eth.c
@@ -15,10 +15,12 @@
 #include "eth_private.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -39,6 +41,7 @@ eth_dev_match(const struct rte_eth_dev *edev,
 {
 	const struct eth_dev_match_arg *arg = _arg;
 	const struct rte_kvargs *kvlist = arg->kvlist;
+	struct rte_eth_dev_data *data;
 
 	if (edev->state == RTE_ETH_DEV_UNUSED)
 		return -1;
@@ -47,6 +50,10 @@ eth_dev_match(const struct rte_eth_dev *edev,
 	if (kvlist == NULL)
 		/* Empty string matches everything. */
 		return 0;
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v5 21/21] app/testpmd: add show device command
  2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
                           ` (19 preceding siblings ...)
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 20/21] ethdev: add device matching field name Gaetan Rivet
@ 2018-04-11  0:04         ` Gaetan Rivet
  20 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-11  0:04 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..8ac5fb3ca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device "
+		"<device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 18/21] ethdev: add private generic device iterator
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 18/21] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-04-11  8:41           ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-11  8:41 UTC (permalink / raw)
  To: dev

On Wed, Apr 11, 2018 at 02:04:19AM +0200, Gaetan Rivet wrote:
> This iterator can be customized with a comparison function that will
> trigger a stopping condition.
> 
> It can be leveraged to write several different iterators that have
> similar but non-identical purposes.
> 
> It is private to librte_ether.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/librte_ether/Makefile      |  1 +
>  lib/librte_ether/eth_private.c | 32 ++++++++++++++++++++++++++++++++
>  lib/librte_ether/eth_private.h | 26 ++++++++++++++++++++++++++
>  3 files changed, 59 insertions(+)
>  create mode 100644 lib/librte_ether/eth_private.c
>  create mode 100644 lib/librte_ether/eth_private.h
> 
> diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
> index c2f2f7d82..2fa133fbc 100644
> --- a/lib/librte_ether/Makefile
> +++ b/lib/librte_ether/Makefile
> @@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
>  
>  LIBABIVER := 9
>  
> +SRCS-y += eth_private.c
>  SRCS-y += rte_ethdev.c
>  SRCS-y += rte_flow.c
>  SRCS-y += rte_tm.c
> diff --git a/lib/librte_ether/eth_private.c b/lib/librte_ether/eth_private.c
> new file mode 100644
> index 000000000..311c5d6b2
> --- /dev/null
> +++ b/lib/librte_ether/eth_private.c
> @@ -0,0 +1,32 @@
> +/* SPDX-License-Identifier: BSD-3-Clause
> + * Copyright(c) 2018 Gaëtan

Forgot something here.

> + */
> +
> +#include "rte_ethdev.h"
> +#include "eth_private.h"
> +
> +struct rte_eth_dev *
> +eth_find_device(const void *_start, rte_eth_cmp_t cmp,

_start should be of type (const struct rte_eth_dev *), will update this
patch.

Same changes to eth_private.h

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities Gaetan Rivet
@ 2018-04-12 11:28           ` Neil Horman
  2018-04-12 21:57             ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-04-12 11:28 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
> Build a central list to quickly see each used priorities for
> constructors, allowing to verify that they are both above 100 and in the
> proper order.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> Acked-by: Neil Horman <nhorman@tuxdriver.com>
> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> ---
>  lib/librte_eal/common/eal_common_log.c     | 2 +-
>  lib/librte_eal/common/include/rte_bus.h    | 2 +-
>  lib/librte_eal/common/include/rte_common.h | 8 +++++++-
>  3 files changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> index a27192620..36b9d6e08 100644
> --- a/lib/librte_eal/common/eal_common_log.c
> +++ b/lib/librte_eal/common/eal_common_log.c
> @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
>  };
>  
>  /* Logging should be first initializer (before drivers and bus) */
> -RTE_INIT_PRIO(rte_log_init, 101);
> +RTE_INIT_PRIO(rte_log_init, LOG);
>  static void
>  rte_log_init(void)
>  {
> diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> index 6fb08341a..eb9eded4e 100644
> --- a/lib/librte_eal/common/include/rte_bus.h
> +++ b/lib/librte_eal/common/include/rte_bus.h
> @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
>   * The constructor has higher priority than PMD constructors.
>   */
>  #define RTE_REGISTER_BUS(nm, bus) \
> -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
>  static void businitfn_ ##nm(void) \
>  {\
>  	(bus).name = RTE_STR(nm);\
> diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> index 6c5bc5a76..8f04518f7 100644
> --- a/lib/librte_eal/common/include/rte_common.h
> +++ b/lib/librte_eal/common/include/rte_common.h
> @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
>   */
>  #define RTE_SET_USED(x) (void)(x)
>  
> +#define RTE_PRIORITY_LOG 101
> +#define RTE_PRIORITY_BUS 110
> +
> +#define RTE_PRIO(prio) \
> +	RTE_PRIORITY_ ## prio
> +
>  /**
>   * Run function before main() with low priority.
>   *
> @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
>   *   Lowest number is the first to run.
>   */
>  #define RTE_INIT_PRIO(func, prio) \
> -static void __attribute__((constructor(prio), used)) func(void)
> +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
>  
It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
presume that constructors with no explicit priority run last, but the gcc
manual doesn't explicitly say that.  It would be a heck of a bug to track down
if somehow unprioritized constructors ran early.

Neil

>  /**
>   * Force a function to be inlined
> -- 
> 2.11.0
> 
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-12 11:28           ` Neil Horman
@ 2018-04-12 21:57             ` Gaëtan Rivet
  2018-04-13 11:42               ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-12 21:57 UTC (permalink / raw)
  To: Neil Horman; +Cc: dev

Hello Neil,

On Thu, Apr 12, 2018 at 07:28:26AM -0400, Neil Horman wrote:
> On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
> > Build a central list to quickly see each used priorities for
> > constructors, allowing to verify that they are both above 100 and in the
> > proper order.
> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> > ---
> >  lib/librte_eal/common/eal_common_log.c     | 2 +-
> >  lib/librte_eal/common/include/rte_bus.h    | 2 +-
> >  lib/librte_eal/common/include/rte_common.h | 8 +++++++-
> >  3 files changed, 9 insertions(+), 3 deletions(-)
> > 
> > diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> > index a27192620..36b9d6e08 100644
> > --- a/lib/librte_eal/common/eal_common_log.c
> > +++ b/lib/librte_eal/common/eal_common_log.c
> > @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
> >  };
> >  
> >  /* Logging should be first initializer (before drivers and bus) */
> > -RTE_INIT_PRIO(rte_log_init, 101);
> > +RTE_INIT_PRIO(rte_log_init, LOG);
> >  static void
> >  rte_log_init(void)
> >  {
> > diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> > index 6fb08341a..eb9eded4e 100644
> > --- a/lib/librte_eal/common/include/rte_bus.h
> > +++ b/lib/librte_eal/common/include/rte_bus.h
> > @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
> >   * The constructor has higher priority than PMD constructors.
> >   */
> >  #define RTE_REGISTER_BUS(nm, bus) \
> > -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> > +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
> >  static void businitfn_ ##nm(void) \
> >  {\
> >  	(bus).name = RTE_STR(nm);\
> > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > index 6c5bc5a76..8f04518f7 100644
> > --- a/lib/librte_eal/common/include/rte_common.h
> > +++ b/lib/librte_eal/common/include/rte_common.h
> > @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
> >   */
> >  #define RTE_SET_USED(x) (void)(x)
> >  
> > +#define RTE_PRIORITY_LOG 101
> > +#define RTE_PRIORITY_BUS 110
> > +
> > +#define RTE_PRIO(prio) \
> > +	RTE_PRIORITY_ ## prio
> > +
> >  /**
> >   * Run function before main() with low priority.
> >   *
> > @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
> >   *   Lowest number is the first to run.
> >   */
> >  #define RTE_INIT_PRIO(func, prio) \
> > -static void __attribute__((constructor(prio), used)) func(void)
> > +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> >  
> It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
> and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
> presume that constructors with no explicit priority run last, but the gcc
> manual doesn't explicitly say that.  It would be a heck of a bug to track down
> if somehow unprioritized constructors ran early.
> 
> Neil
> 

While certainly poorly documented, the behavior is well-defined. I don't see
a situation where the bug you describe could arise.

Adding RTE_PRIORITY_LAST is pretty harmless, but I'm not sure it's
justified to add it. If you still think it is useful, I will do it.

I'd be curious to hear if anyone has had issues of this kind.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-12 21:57             ` Gaëtan Rivet
@ 2018-04-13 11:42               ` Neil Horman
  2018-04-13 12:52                 ` Shreyansh Jain
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-04-13 11:42 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev

On Thu, Apr 12, 2018 at 11:57:47PM +0200, Gaëtan Rivet wrote:
> Hello Neil,
> 
> On Thu, Apr 12, 2018 at 07:28:26AM -0400, Neil Horman wrote:
> > On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
> > > Build a central list to quickly see each used priorities for
> > > constructors, allowing to verify that they are both above 100 and in the
> > > proper order.
> > > 
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> > > ---
> > >  lib/librte_eal/common/eal_common_log.c     | 2 +-
> > >  lib/librte_eal/common/include/rte_bus.h    | 2 +-
> > >  lib/librte_eal/common/include/rte_common.h | 8 +++++++-
> > >  3 files changed, 9 insertions(+), 3 deletions(-)
> > > 
> > > diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> > > index a27192620..36b9d6e08 100644
> > > --- a/lib/librte_eal/common/eal_common_log.c
> > > +++ b/lib/librte_eal/common/eal_common_log.c
> > > @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
> > >  };
> > >  
> > >  /* Logging should be first initializer (before drivers and bus) */
> > > -RTE_INIT_PRIO(rte_log_init, 101);
> > > +RTE_INIT_PRIO(rte_log_init, LOG);
> > >  static void
> > >  rte_log_init(void)
> > >  {
> > > diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> > > index 6fb08341a..eb9eded4e 100644
> > > --- a/lib/librte_eal/common/include/rte_bus.h
> > > +++ b/lib/librte_eal/common/include/rte_bus.h
> > > @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
> > >   * The constructor has higher priority than PMD constructors.
> > >   */
> > >  #define RTE_REGISTER_BUS(nm, bus) \
> > > -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> > > +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
> > >  static void businitfn_ ##nm(void) \
> > >  {\
> > >  	(bus).name = RTE_STR(nm);\
> > > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > > index 6c5bc5a76..8f04518f7 100644
> > > --- a/lib/librte_eal/common/include/rte_common.h
> > > +++ b/lib/librte_eal/common/include/rte_common.h
> > > @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
> > >   */
> > >  #define RTE_SET_USED(x) (void)(x)
> > >  
> > > +#define RTE_PRIORITY_LOG 101
> > > +#define RTE_PRIORITY_BUS 110
> > > +
> > > +#define RTE_PRIO(prio) \
> > > +	RTE_PRIORITY_ ## prio
> > > +
> > >  /**
> > >   * Run function before main() with low priority.
> > >   *
> > > @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
> > >   *   Lowest number is the first to run.
> > >   */
> > >  #define RTE_INIT_PRIO(func, prio) \
> > > -static void __attribute__((constructor(prio), used)) func(void)
> > > +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> > >  
> > It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
> > and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
> > presume that constructors with no explicit priority run last, but the gcc
> > manual doesn't explicitly say that.  It would be a heck of a bug to track down
> > if somehow unprioritized constructors ran early.
> > 
> > Neil
> > 
> 
> While certainly poorly documented, the behavior is well-defined. I don't see
> a situation where the bug you describe could arise.
> 
> Adding RTE_PRIORITY_LAST is pretty harmless, but I'm not sure it's
> justified to add it. If you still think it is useful, I will do it.
> 
It was more just a way to unify the macros is all, probably not important.

> I'd be curious to hear if anyone has had issues of this kind.
> 
I've not had any, but I was suprised to see that the gcc manual didn't
explicitly call out the implied priority of unprioritized constructors

Neil

> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-13 11:42               ` Neil Horman
@ 2018-04-13 12:52                 ` Shreyansh Jain
  2018-04-13 12:55                   ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Shreyansh Jain @ 2018-04-13 12:52 UTC (permalink / raw)
  To: Neil Horman, Gaëtan Rivet; +Cc: dev

On Friday 13 April 2018 05:12 PM, Neil Horman wrote:
> On Thu, Apr 12, 2018 at 11:57:47PM +0200, Gaëtan Rivet wrote:
>> Hello Neil,
>>
>> On Thu, Apr 12, 2018 at 07:28:26AM -0400, Neil Horman wrote:
>>> On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
>>>> Build a central list to quickly see each used priorities for
>>>> constructors, allowing to verify that they are both above 100 and in the
>>>> proper order.
>>>>
>>>> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
>>>> Acked-by: Neil Horman <nhorman@tuxdriver.com>
>>>> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
>>>> ---
>>>>   lib/librte_eal/common/eal_common_log.c     | 2 +-
>>>>   lib/librte_eal/common/include/rte_bus.h    | 2 +-
>>>>   lib/librte_eal/common/include/rte_common.h | 8 +++++++-
>>>>   3 files changed, 9 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
>>>> index a27192620..36b9d6e08 100644
>>>> --- a/lib/librte_eal/common/eal_common_log.c
>>>> +++ b/lib/librte_eal/common/eal_common_log.c
>>>> @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
>>>>   };
>>>>   
>>>>   /* Logging should be first initializer (before drivers and bus) */
>>>> -RTE_INIT_PRIO(rte_log_init, 101);
>>>> +RTE_INIT_PRIO(rte_log_init, LOG);
>>>>   static void
>>>>   rte_log_init(void)
>>>>   {
>>>> diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
>>>> index 6fb08341a..eb9eded4e 100644
>>>> --- a/lib/librte_eal/common/include/rte_bus.h
>>>> +++ b/lib/librte_eal/common/include/rte_bus.h
>>>> @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
>>>>    * The constructor has higher priority than PMD constructors.
>>>>    */
>>>>   #define RTE_REGISTER_BUS(nm, bus) \
>>>> -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
>>>> +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
>>>>   static void businitfn_ ##nm(void) \
>>>>   {\
>>>>   	(bus).name = RTE_STR(nm);\
>>>> diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
>>>> index 6c5bc5a76..8f04518f7 100644
>>>> --- a/lib/librte_eal/common/include/rte_common.h
>>>> +++ b/lib/librte_eal/common/include/rte_common.h
>>>> @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
>>>>    */
>>>>   #define RTE_SET_USED(x) (void)(x)
>>>>   
>>>> +#define RTE_PRIORITY_LOG 101
>>>> +#define RTE_PRIORITY_BUS 110
>>>> +
>>>> +#define RTE_PRIO(prio) \
>>>> +	RTE_PRIORITY_ ## prio
>>>> +
>>>>   /**
>>>>    * Run function before main() with low priority.
>>>>    *
>>>> @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
>>>>    *   Lowest number is the first to run.
>>>>    */
>>>>   #define RTE_INIT_PRIO(func, prio) \
>>>> -static void __attribute__((constructor(prio), used)) func(void)
>>>> +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
>>>>   
>>> It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
>>> and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
>>> presume that constructors with no explicit priority run last, but the gcc
>>> manual doesn't explicitly say that.  It would be a heck of a bug to track down
>>> if somehow unprioritized constructors ran early.
>>>
>>> Neil
>>>
>>
>> While certainly poorly documented, the behavior is well-defined. I don't see
>> a situation where the bug you describe could arise.
>>
>> Adding RTE_PRIORITY_LAST is pretty harmless, but I'm not sure it's
>> justified to add it. If you still think it is useful, I will do it.
>>
> It was more just a way to unify the macros is all, probably not important.
> 
>> I'd be curious to hear if anyone has had issues of this kind.
>>
> I've not had any, but I was suprised to see that the gcc manual didn't
> explicitly call out the implied priority of unprioritized constructors

I (tried to) looked into the gcc code base. It seems that when priority 
is not defined, DEFAULT_INIT_PRIORITY 65536, is used.

--->8--- gcc/collect2.c ---
   /* Extract init_p number from ctor/dtor name.  */
   pri = atoi (name + pos);
   return pri ? pri : DEFAULT_INIT_PRIORITY;
--->8---

Though, I couldn't find any documentation for this fact - and, I can 
never be confident about gcc code.

I found one of the ARM compiler (clang) does has a policy for using 
non-specified priority as lower than specified priority. [1]

[1] 
https://developer.arm.com/docs/dui0774/latest/compiler-specific-function-variable-and-type-attributes/__attribute__constructorpriority-function-attribute

A specified value for RTE_PRIORITY_LAST is not a bad option - it would 
help in keeping the priorities bound without relying on the unknown of 
priority for unspecified constructors.

> 
> Neil
> 
>> -- 
>> Gaëtan Rivet
>> 6WIND
>>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-13 12:52                 ` Shreyansh Jain
@ 2018-04-13 12:55                   ` Gaëtan Rivet
  2018-04-14 18:45                     ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-13 12:55 UTC (permalink / raw)
  To: Shreyansh Jain; +Cc: Neil Horman, dev

Hi Shreyansh,

On Fri, Apr 13, 2018 at 06:22:43PM +0530, Shreyansh Jain wrote:
> On Friday 13 April 2018 05:12 PM, Neil Horman wrote:
> > On Thu, Apr 12, 2018 at 11:57:47PM +0200, Gaëtan Rivet wrote:
> > > Hello Neil,
> > > 
> > > On Thu, Apr 12, 2018 at 07:28:26AM -0400, Neil Horman wrote:
> > > > On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
> > > > > Build a central list to quickly see each used priorities for
> > > > > constructors, allowing to verify that they are both above 100 and in the
> > > > > proper order.
> > > > > 
> > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> > > > > ---
> > > > >   lib/librte_eal/common/eal_common_log.c     | 2 +-
> > > > >   lib/librte_eal/common/include/rte_bus.h    | 2 +-
> > > > >   lib/librte_eal/common/include/rte_common.h | 8 +++++++-
> > > > >   3 files changed, 9 insertions(+), 3 deletions(-)
> > > > > 
> > > > > diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> > > > > index a27192620..36b9d6e08 100644
> > > > > --- a/lib/librte_eal/common/eal_common_log.c
> > > > > +++ b/lib/librte_eal/common/eal_common_log.c
> > > > > @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
> > > > >   };
> > > > >   /* Logging should be first initializer (before drivers and bus) */
> > > > > -RTE_INIT_PRIO(rte_log_init, 101);
> > > > > +RTE_INIT_PRIO(rte_log_init, LOG);
> > > > >   static void
> > > > >   rte_log_init(void)
> > > > >   {
> > > > > diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> > > > > index 6fb08341a..eb9eded4e 100644
> > > > > --- a/lib/librte_eal/common/include/rte_bus.h
> > > > > +++ b/lib/librte_eal/common/include/rte_bus.h
> > > > > @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
> > > > >    * The constructor has higher priority than PMD constructors.
> > > > >    */
> > > > >   #define RTE_REGISTER_BUS(nm, bus) \
> > > > > -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> > > > > +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
> > > > >   static void businitfn_ ##nm(void) \
> > > > >   {\
> > > > >   	(bus).name = RTE_STR(nm);\
> > > > > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > > > > index 6c5bc5a76..8f04518f7 100644
> > > > > --- a/lib/librte_eal/common/include/rte_common.h
> > > > > +++ b/lib/librte_eal/common/include/rte_common.h
> > > > > @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
> > > > >    */
> > > > >   #define RTE_SET_USED(x) (void)(x)
> > > > > +#define RTE_PRIORITY_LOG 101
> > > > > +#define RTE_PRIORITY_BUS 110
> > > > > +
> > > > > +#define RTE_PRIO(prio) \
> > > > > +	RTE_PRIORITY_ ## prio
> > > > > +
> > > > >   /**
> > > > >    * Run function before main() with low priority.
> > > > >    *
> > > > > @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
> > > > >    *   Lowest number is the first to run.
> > > > >    */
> > > > >   #define RTE_INIT_PRIO(func, prio) \
> > > > > -static void __attribute__((constructor(prio), used)) func(void)
> > > > > +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> > > > It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
> > > > and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
> > > > presume that constructors with no explicit priority run last, but the gcc
> > > > manual doesn't explicitly say that.  It would be a heck of a bug to track down
> > > > if somehow unprioritized constructors ran early.
> > > > 
> > > > Neil
> > > > 
> > > 
> > > While certainly poorly documented, the behavior is well-defined. I don't see
> > > a situation where the bug you describe could arise.
> > > 
> > > Adding RTE_PRIORITY_LAST is pretty harmless, but I'm not sure it's
> > > justified to add it. If you still think it is useful, I will do it.
> > > 
> > It was more just a way to unify the macros is all, probably not important.
> > 
> > > I'd be curious to hear if anyone has had issues of this kind.
> > > 
> > I've not had any, but I was suprised to see that the gcc manual didn't
> > explicitly call out the implied priority of unprioritized constructors
> 
> I (tried to) looked into the gcc code base. It seems that when priority is
> not defined, DEFAULT_INIT_PRIORITY 65536, is used.
> 
> --->8--- gcc/collect2.c ---
>   /* Extract init_p number from ctor/dtor name.  */
>   pri = atoi (name + pos);
>   return pri ? pri : DEFAULT_INIT_PRIORITY;
> --->8---
> 
> Though, I couldn't find any documentation for this fact - and, I can never
> be confident about gcc code.
> 
> I found one of the ARM compiler (clang) does has a policy for using
> non-specified priority as lower than specified priority. [1]
> 
> [1] https://developer.arm.com/docs/dui0774/latest/compiler-specific-function-variable-and-type-attributes/__attribute__constructorpriority-function-attribute
> 
> A specified value for RTE_PRIORITY_LAST is not a bad option - it would help
> in keeping the priorities bound without relying on the unknown of priority
> for unspecified constructors.

This is interesting, thanks for looking up the GCC code.
Ok, unless someone has a strong reason not to, I will add
RTE_PRIORITY_LAST. Not really convinced about it but not
opposed enough either :) .

Regards,
-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 00/22] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (19 preceding siblings ...)
  2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
@ 2018-04-13 13:22 ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 01/22] kvargs: build before EAL Gaetan Rivet
                     ` (21 more replies)
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                   ` (4 subsequent siblings)
  25 siblings, 22 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.

v5:

  * Rebased on master
  * Use strcspn instead of custom function.
  * Introduce private generic rte_eth_dev iterator.
    This could be generalized to other iterators
    (port_next, owner_id-aware, etc).
  * Attempted to support meson.build.
    Got lost in the implicit variables declared
    when inversing dependencies between kvargs and EAL.
    Removed anything related to meson.
  * Postponed genericization of work from
    device query to device declaration.
    Much bigger than anticipated, will let this
    part get in first and iterate over it.

v6:

  * Rebased on master
  * Introduce RTE_PRIORITY_LAST, to explicitly set
    the lowest constructor priority.
  * Fix copyright notice for eth_privage.* files.

Gaetan Rivet (22):
  kvargs: build before EAL
  eal: list acceptable init priorities
  eal: add last init priority
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: fix find device implementation
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: fix find device implementation
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: add private generic device iterator
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                             |  52 ++++
 drivers/bus/pci/Makefile                           |   2 +-
 drivers/bus/pci/pci_common.c                       |  87 +++++-
 drivers/bus/pci/rte_bus_pci.h                      |   3 +
 drivers/bus/vdev/Makefile                          |   3 +-
 drivers/bus/vdev/rte_bus_vdev.h                    |   3 +
 drivers/bus/vdev/vdev.c                            |  66 ++++-
 lib/Makefile                                       |   7 +-
 lib/librte_eal/bsdapp/eal/Makefile                 |   2 +
 lib/librte_eal/common/Makefile                     |   4 +-
 lib/librte_eal/common/eal_common_class.c           |  62 ++++
 lib/librte_eal/common/eal_common_dev.c             | 316 +++++++++++++++++++++
 lib/librte_eal/common/eal_common_log.c             |   2 +-
 lib/librte_eal/common/include/rte_bus.h            |   3 +-
 lib/librte_eal/common/include/rte_class.h          | 127 +++++++++
 lib/librte_eal/common/include/rte_common.h         |  53 +++-
 lib/librte_eal/common/include/rte_dev.h            |  97 +++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   2 +
 lib/librte_eal/rte_eal_version.map                 |   4 +
 lib/librte_ether/Makefile                          |   4 +-
 lib/librte_ether/eth_private.c                     |  31 ++
 lib/librte_ether/eth_private.h                     |  26 ++
 lib/librte_ether/rte_class_eth.c                   |  86 ++++++
 lib/librte_kvargs/Makefile                         |   3 +-
 lib/librte_kvargs/rte_kvargs.c                     |  12 +-
 lib/librte_kvargs/rte_kvargs.h                     |  28 ++
 lib/librte_kvargs/rte_kvargs_version.map           |   7 +
 .../include => librte_kvargs}/rte_string_fns.h     |   0
 28 files changed, 1055 insertions(+), 37 deletions(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ether/eth_private.c
 create mode 100644 lib/librte_ether/eth_private.h
 create mode 100644 lib/librte_ether/rte_class_eth.c
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 01/22] kvargs: build before EAL
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 02/22] eal: list acceptable init priorities Gaetan Rivet
                     ` (20 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                                                      | 3 +--
 lib/librte_eal/common/Makefile                                    | 2 +-
 lib/librte_kvargs/Makefile                                        | 3 ++-
 lib/librte_kvargs/rte_kvargs.c                                    | 2 +-
 lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
 5 files changed, 5 insertions(+), 5 deletions(-)
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a606..fc7a55a37 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -71,8 +72,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 48f870f24..dbd19331b 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -9,7 +9,7 @@ INC += rte_errno.h rte_launch.h rte_lcore.h
 INC += rte_log.h rte_memory.h rte_memzone.h
 INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
+INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 4eaa9334d..e026ecc21 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -37,7 +37,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c
 
 # install includes
 INCS := rte_kvargs.h
+INCS += rte_string_fns.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS)
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..0a1abf579 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -7,8 +7,8 @@
 #include <stdlib.h>
 
 #include <rte_log.h>
-#include <rte_string_fns.h>
 
+#include "rte_string_fns.h"
 #include "rte_kvargs.h"
 
 /*
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_kvargs/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_kvargs/rte_string_fns.h
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 02/22] eal: list acceptable init priorities
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 01/22] kvargs: build before EAL Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 03/22] eal: add last init priority Gaetan Rivet
                     ` (19 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Build a central list to quickly see each used priorities for
constructors, allowing to verify that they are both above 100 and in the
proper order.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
 lib/librte_eal/common/eal_common_log.c     | 2 +-
 lib/librte_eal/common/include/rte_bus.h    | 2 +-
 lib/librte_eal/common/include/rte_common.h | 8 +++++++-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index a27192620..36b9d6e08 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
 };
 
 /* Logging should be first initializer (before drivers and bus) */
-RTE_INIT_PRIO(rte_log_init, 101);
+RTE_INIT_PRIO(rte_log_init, LOG);
 static void
 rte_log_init(void)
 {
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 6fb08341a..eb9eded4e 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
  * The constructor has higher priority than PMD constructors.
  */
 #define RTE_REGISTER_BUS(nm, bus) \
-RTE_INIT_PRIO(businitfn_ ##nm, 110); \
+RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
 static void businitfn_ ##nm(void) \
 {\
 	(bus).name = RTE_STR(nm);\
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 6c5bc5a76..8f04518f7 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
  */
 #define RTE_SET_USED(x) (void)(x)
 
+#define RTE_PRIORITY_LOG 101
+#define RTE_PRIORITY_BUS 110
+
+#define RTE_PRIO(prio) \
+	RTE_PRIORITY_ ## prio
+
 /**
  * Run function before main() with low priority.
  *
@@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
  *   Lowest number is the first to run.
  */
 #define RTE_INIT_PRIO(func, prio) \
-static void __attribute__((constructor(prio), used)) func(void)
+static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
  * Force a function to be inlined
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 03/22] eal: add last init priority
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 01/22] kvargs: build before EAL Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 02/22] eal: list acceptable init priorities Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 04/22] eal: introduce dtor macros Gaetan Rivet
                     ` (18 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Add the priority RTE_PRIORITY_LAST, used for initialization routines
meant to be run after all other constructors.

This priority becomes the default priority for all DPDK constructors.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 8f04518f7..69e5ed1e3 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,22 +83,12 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
 	RTE_PRIORITY_ ## prio
 
 /**
- * Run function before main() with low priority.
- *
- * The constructor will be run after prioritized constructors.
- *
- * @param func
- *   Constructor function.
- */
-#define RTE_INIT(func) \
-static void __attribute__((constructor, used)) func(void)
-
-/**
  * Run function before main() with high priority.
  *
  * @param func
@@ -111,6 +101,17 @@ static void __attribute__((constructor, used)) func(void)
 static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
+ * Run function before main() with low priority.
+ *
+ * The constructor will be run after prioritized constructors.
+ *
+ * @param func
+ *   Constructor function.
+ */
+#define RTE_INIT(func) \
+	RTE_INIT_PRIO(func, LAST)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 04/22] eal: introduce dtor macros
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (2 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 03/22] eal: add last init priority Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 05/22] eal: introduce device class abstraction Gaetan Rivet
                     ` (17 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 69e5ed1e3..d48e0ec56 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -112,6 +112,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 	RTE_INIT_PRIO(func, LAST)
 
 /**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+	RTE_FINI_PRIO(func, LAST)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 05/22] eal: introduce device class abstraction
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (3 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 04/22] eal: introduce dtor macros Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 06/22] eal/class: register destructor Gaetan Rivet
                     ` (16 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 7 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index 200285e01..de0e6d166 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -51,6 +51,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index dbd19331b..f9d17e7ec 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..b5e550a34
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index d48e0ec56..ab6b4cf2a 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 #define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 45517a27b..b11f92e03 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -59,6 +59,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index d02d80b8a..75121b08d 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -221,6 +221,8 @@ EXPERIMENTAL {
 	rte_eal_devargs_insert;
 	rte_eal_devargs_parse;
 	rte_eal_devargs_remove;
+	rte_class_register;
+	rte_class_unregister;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
 	rte_eal_mbuf_user_pool_ops;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 06/22] eal/class: register destructor
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (4 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 05/22] eal: introduce device class abstraction Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 07/22] eal/dev: add device iterator interface Gaetan Rivet
                     ` (15 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index b5e550a34..e8176f5e1 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 07/22] eal/dev: add device iterator interface
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (5 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 06/22] eal/class: register destructor Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 08/22] eal/class: add device iteration Gaetan Rivet
                     ` (14 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 0955e9adb..a789defc3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -282,6 +282,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 08/22] eal/class: add device iteration
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (6 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 07/22] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 09/22] eal/bus: " Gaetan Rivet
                     ` (13 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index e8176f5e1..9d5b06807 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 09/22] eal/bus: add device iteration
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (7 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 08/22] eal/class: add device iteration Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 10/22] eal/dev: implement device iteration initialization Gaetan Rivet
                     ` (12 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 10/22] eal/dev: implement device iteration initialization
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (8 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 09/22] eal/bus: " Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 11/22] eal/dev: implement device iteration Gaetan Rivet
                     ` (11 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@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 de0e6d166..35f98448c 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 149e9ad72..d8e306926 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 <rte_spinlock.h>
 #include <rte_malloc.h>
@@ -368,3 +371,148 @@ dev_callback_process(char *device_name, enum rte_dev_event_type event)
 	}
 	rte_spinlock_unlock(&dev_event_lock);
 }
+
+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 a789defc3..eb1ad6182 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -329,6 +329,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 b11f92e03..47fd07323 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 75121b08d..1a41e9413 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -223,6 +223,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

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 11/22] eal/dev: implement device iteration
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (9 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 10/22] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 12/22] kvargs: add generic string matching callback Gaetan Rivet
                     ` (10 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  26 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 195 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index d8e306926..9d180f881 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
 /* spinlock for device callbacks */
 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -516,3 +538,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 	}
 	return -rte_errno;
 }
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	size_t end;
+	char *copy;
+
+	end = strcspn(str, ",/");
+	if (str[end] == ',') {
+		copy = strdup(&str[end + 1]);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_copy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_copy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index eb1ad6182..bfa57287a 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -353,6 +353,32 @@ __rte_experimental
 int
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 1a41e9413..483ed94c4 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -224,6 +224,7 @@ EXPERIMENTAL {
 	rte_class_register;
 	rte_class_unregister;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
 	rte_eal_mbuf_user_pool_ops;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 12/22] kvargs: add generic string matching callback
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (10 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 11/22] eal/dev: implement device iteration Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 14:49     ` Shreyansh Jain
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 13/22] bus/pci: fix find device implementation Gaetan Rivet
                     ` (9 subsequent siblings)
  21 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
 4 files changed, 46 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 1b17526f7..4206485d3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 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
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 0a1abf579..6ee04cbb9 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -180,3 +180,13 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -strcmp(str, value);
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..c07c6fea5 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -121,6 +123,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..e2f663a88 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 13/22] bus/pci: fix find device implementation
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (11 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 12/22] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 14/22] bus/pci: implement device iteration and comparison Gaetan Rivet
                     ` (8 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set, and a device before it matches the data
passed for comparison, then this first device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2a00f365a..2c45f8151 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -459,17 +459,20 @@ static struct rte_device *
 pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		const void *data)
 {
-	struct rte_pci_device *dev;
+	const struct rte_pci_device *pstart;
+	struct rte_pci_device *pdev;
 
-	FOREACH_DEVICE_ON_PCIBUS(dev) {
-		if (start && &dev->device == start) {
-			start = NULL; /* starting point found */
-			continue;
-		}
-		if (cmp(&dev->device, data) == 0)
-			return &dev->device;
+	if (start != NULL) {
+		pstart = RTE_DEV_TO_PCI_CONST(start);
+		pdev = TAILQ_NEXT(pstart, next);
+	} else {
+		pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
+	}
+	while (pdev != NULL) {
+		if (cmp(&pdev->device, data) == 0)
+			return &pdev->device;
+		pdev = TAILQ_NEXT(pdev, next);
 	}
-
 	return NULL;
 }
 
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 357afb912..458e6d076 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -74,6 +74,9 @@ struct rte_pci_device {
  */
 #define RTE_DEV_TO_PCI(ptr) container_of(ptr, struct rte_pci_device, device)
 
+#define RTE_DEV_TO_PCI_CONST(ptr) \
+	container_of(ptr, const struct rte_pci_device, device)
+
 #define RTE_ETH_DEV_TO_PCI(eth_dev)	RTE_DEV_TO_PCI((eth_dev)->device)
 
 /** Any PCI device identifier (vendor, device, ...) */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 14/22] bus/pci: implement device iteration and comparison
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (12 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 13/22] bus/pci: fix find device implementation Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 15/22] bus/pci: add device matching field id Gaetan Rivet
                     ` (7 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index 804a198d1..bbda567c1 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -53,7 +53,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2c45f8151..bd9ecddc6 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -13,6 +13,7 @@
 
 #include <rte_errno.h>
 #include <rte_interrupts.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
@@ -497,6 +498,46 @@ pci_unplug(struct rte_device *dev)
 	return ret;
 }
 
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+static void *
+pci_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_device *dev;
+	struct rte_kvargs *kvargs = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = pci_find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 struct rte_pci_bus rte_pci_bus = {
 	.bus = {
 		.scan = rte_pci_scan,
@@ -506,6 +547,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 15/22] bus/pci: add device matching field id
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (13 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 14/22] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 16/22] bus/vdev: fix find device implementation Gaetan Rivet
                     ` (6 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index bd9ecddc6..3666e4caa 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -499,21 +499,45 @@ pci_unplug(struct rte_device *dev)
 }
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return rte_pci_addr_cmp(addr1, addr2);
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 16/22] bus/vdev: fix find device implementation
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (14 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 15/22] bus/pci: add device matching field id Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 17/22] bus/vdev: implement device iteration Gaetan Rivet
                     ` (5 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set and a device before it matches the data,
this device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/vdev/rte_bus_vdev.h b/drivers/bus/vdev/rte_bus_vdev.h
index 646d6c090..f9b5eb596 100644
--- a/drivers/bus/vdev/rte_bus_vdev.h
+++ b/drivers/bus/vdev/rte_bus_vdev.h
@@ -25,6 +25,9 @@ struct rte_vdev_device {
 #define RTE_DEV_TO_VDEV(ptr) \
 	container_of(ptr, struct rte_vdev_device, device)
 
+#define RTE_DEV_TO_VDEV_CONST(ptr) \
+	container_of(ptr, const struct rte_vdev_device, device)
+
 static inline const char *
 rte_vdev_device_name(const struct rte_vdev_device *dev)
 {
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index f8dd1f5e6..c135554c0 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -358,15 +358,19 @@ static struct rte_device *
 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		 const void *data)
 {
+	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
 
-	TAILQ_FOREACH(dev, &vdev_device_list, next) {
-		if (start && &dev->device == start) {
-			start = NULL;
-			continue;
-		}
+	if (start != NULL) {
+		vstart = RTE_DEV_TO_VDEV_CONST(start);
+		dev = TAILQ_NEXT(vstart, next);
+	} else {
+		dev = TAILQ_FIRST(&vdev_device_list);
+	}
+	while (dev != NULL) {
 		if (cmp(&dev->device, data) == 0)
 			return &dev->device;
+		dev = TAILQ_NEXT(dev, next);
 	}
 	return NULL;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 17/22] bus/vdev: implement device iteration
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (15 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 16/22] bus/vdev: fix find device implementation Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 18/22] bus/vdev: add device matching field driver Gaetan Rivet
                     ` (4 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 24d424a38..52728833c 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index c135554c0..5bb87af28 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -15,6 +15,7 @@
 #include <rte_bus.h>
 #include <rte_common.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
 #include <rte_memory.h>
 #include <rte_tailq.h>
 #include <rte_spinlock.h>
@@ -387,6 +388,46 @@ vdev_unplug(struct rte_device *dev)
 	return rte_vdev_uninit(dev->name);
 }
 
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+static void *
+vdev_dev_iterate(const void *start,
+		 const char *str,
+		 const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
@@ -394,6 +435,7 @@ static struct rte_bus rte_vdev_bus = {
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 18/22] bus/vdev: add device matching field driver
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (16 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 17/22] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 19/22] ethdev: add private generic device iterator Gaetan Rivet
                     ` (3 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  1 +
 drivers/bus/vdev/vdev.c   | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 52728833c..db6bee98a 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -10,6 +10,7 @@ LIB = librte_bus_vdev.a
 
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 # versioning export map
 EXPORT_MAP := rte_bus_vdev_version.map
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 5bb87af28..84192d79b 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -389,10 +389,12 @@ vdev_unplug(struct rte_device *dev)
 }
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -401,9 +403,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 19/22] ethdev: add private generic device iterator
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (17 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 18/22] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 20/22] ethdev: register ether layer as a class Gaetan Rivet
                     ` (2 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This iterator can be customized with a comparison function that will
trigger a stopping condition.

It can be leveraged to write several different iterators that have
similar but non-identical purposes.

It is private to librte_ether.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/Makefile      |  1 +
 lib/librte_ether/eth_private.c | 31 +++++++++++++++++++++++++++++++
 lib/librte_ether/eth_private.h | 26 ++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)
 create mode 100644 lib/librte_ether/eth_private.c
 create mode 100644 lib/librte_ether/eth_private.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c2f2f7d82..2fa133fbc 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 9
 
+SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
diff --git a/lib/librte_ether/eth_private.c b/lib/librte_ether/eth_private.c
new file mode 100644
index 000000000..d565568a0
--- /dev/null
+++ b/lib/librte_ether/eth_private.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include "rte_ethdev.h"
+#include "eth_private.h"
+
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
+		const void *data)
+{
+	struct rte_eth_dev *edev;
+	ptrdiff_t idx;
+
+	/* Avoid Undefined Behaviour */
+	if (start != NULL &&
+	    (start < &rte_eth_devices[0] ||
+	     start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+		return NULL;
+	if (start != NULL)
+		idx = start - &rte_eth_devices[0] + 1;
+	else
+		idx = 0;
+	for (; idx < RTE_MAX_ETHPORTS; idx++) {
+		edev = &rte_eth_devices[idx];
+		if (cmp(edev, data) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
diff --git a/lib/librte_ether/eth_private.h b/lib/librte_ether/eth_private.h
new file mode 100644
index 000000000..0f5c6d5c4
--- /dev/null
+++ b/lib/librte_ether/eth_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_ETH_PRIVATE_H_
+#define _RTE_ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
+		const void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 20/22] ethdev: register ether layer as a class
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (18 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 19/22] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 21/22] ethdev: add device matching field name Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 22/22] app/testpmd: add show device command Gaetan Rivet
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                     |  2 +-
 lib/librte_ether/Makefile        |  3 +-
 lib/librte_ether/rte_class_eth.c | 79 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_ether/rte_class_eth.c

diff --git a/lib/Makefile b/lib/Makefile
index 4206485d3..47513f03f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf
+DEPDIRS-librte_ether += librte_mbuf librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 2fa133fbc..d4c3a8d06 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
@@ -20,6 +20,7 @@ LIBABIVER := 9
 
 SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
new file mode 100644
index 000000000..32c736d32
--- /dev/null
+++ b/lib/librte_ether/rte_class_eth.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "eth_private.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+	struct rte_device *device;
+	struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+	(&(const struct eth_dev_match_arg) { \
+		.device = (d), \
+		.kvlist = (k), \
+	})
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+	      const void *_arg)
+{
+	const struct eth_dev_match_arg *arg = _arg;
+	const struct rte_kvargs *kvlist = arg->kvlist;
+
+	if (edev->state == RTE_ETH_DEV_UNUSED)
+		return -1;
+	if (edev->device != arg->device)
+		return -1;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	edev = eth_find_device(start, eth_dev_match,
+			       eth_dev_match_arg(it->device, kvargs));
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 21/22] ethdev: add device matching field name
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (19 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 20/22] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 22/22] app/testpmd: add show device command Gaetan Rivet
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
index 32c736d32..d8d8e8845 100644
--- a/lib/librte_ether/rte_class_eth.c
+++ b/lib/librte_ether/rte_class_eth.c
@@ -15,10 +15,12 @@
 #include "eth_private.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -39,6 +41,7 @@ eth_dev_match(const struct rte_eth_dev *edev,
 {
 	const struct eth_dev_match_arg *arg = _arg;
 	const struct rte_kvargs *kvlist = arg->kvlist;
+	struct rte_eth_dev_data *data;
 
 	if (edev->state == RTE_ETH_DEV_UNUSED)
 		return -1;
@@ -47,6 +50,10 @@ eth_dev_match(const struct rte_eth_dev *edev,
 	if (kvlist == NULL)
 		/* Empty string matches everything. */
 		return 0;
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v6 22/22] app/testpmd: add show device command
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
                     ` (20 preceding siblings ...)
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 21/22] ethdev: add device matching field name Gaetan Rivet
@ 2018-04-13 13:22   ` Gaetan Rivet
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-13 13:22 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..8ac5fb3ca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device "
+		"<device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v6 12/22] kvargs: add generic string matching callback
  2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 12/22] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-04-13 14:49     ` Shreyansh Jain
  2018-04-13 15:06       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Shreyansh Jain @ 2018-04-13 14:49 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Friday 13 April 2018 06:52 PM, Gaetan Rivet wrote:
> This function can be used as a callback to
> rte_kvargs_process.
> 
> This should reduce code duplication.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>   lib/Makefile                             |  1 +
>   lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
>   lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
>   lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
>   4 files changed, 46 insertions(+)
> 
> diff --git a/lib/Makefile b/lib/Makefile
> index 1b17526f7..4206485d3 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
>   
>   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
> diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
> index 0a1abf579..6ee04cbb9 100644
> --- a/lib/librte_kvargs/rte_kvargs.c
> +++ b/lib/librte_kvargs/rte_kvargs.c
> @@ -180,3 +180,13 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
>   
>   	return kvlist;
>   }
> +
> +__rte_experimental
> +int
> +rte_kvargs_strcmp(const char *key __rte_unused,
> +		  const char *value, void *opaque)
> +{
> +	const char *str = opaque;
> +
> +	return -strcmp(str, value);
> +}
> diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
> index 51b8120b8..c07c6fea5 100644
> --- a/lib/librte_kvargs/rte_kvargs.h
> +++ b/lib/librte_kvargs/rte_kvargs.h
> @@ -25,6 +25,8 @@
>   extern "C" {
>   #endif
>   
> +#include <rte_compat.h>
> +
>   /** Maximum number of key/value associations */
>   #define RTE_KVARGS_MAX 32
>   
> @@ -121,6 +123,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
>   unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
>   	const char *key_match);
>   
> +/**
> + * Generic kvarg handler for string comparison.
> + *
> + * This function can be used for a generic string comparison processing
> + * on a list of kvargs.
> + *
> + * @param key
> + *   kvarg pair key.
> + *
> + * @param value
> + *   kvarg pair value.
> + *
> + * @param opaque
> + *   Opaque pointer to a string.
> + *
> + * @return
> + *   0 if the strings match.
> + *   !0 otherwise or on error.
> + *
> + *   Unless strcmp, comparison ordering is not kept.
> + *   In order for rte_kvargs_process to stop processing on match error,
> + *   a negative value is returned even if strcmp had returned a positive one.

Is the above comment valid?

 > +	return -strcmp(str, value);

In case a negative is returned (when key opaque < value), this function 
would return a positive. So, effectively you have only reversed the 
values. Is that the expectation?

In 21/22:

--->8--- rte_kvargs_process ---
     for (i = 0; i < kvlist->count; i++) {
         pair = &kvlist->pairs[i];
         if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
             if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
                 return -1;
         }
     }
--->8---

This would only cause the opaque < value case to continue ahead but not 
the reverse.

> + */
> +__rte_experimental
> +int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
> index 2030ec46c..e2f663a88 100644
> --- a/lib/librte_kvargs/rte_kvargs_version.map
> +++ b/lib/librte_kvargs/rte_kvargs_version.map
> @@ -8,3 +8,10 @@ DPDK_2.0 {
>   
>   	local: *;
>   };
> +
> +EXPERIMENTAL {
> +	global:
> +
> +	rte_kvargs_strcmp;
> +
> +} DPDK_2.0;
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v6 12/22] kvargs: add generic string matching callback
  2018-04-13 14:49     ` Shreyansh Jain
@ 2018-04-13 15:06       ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-13 15:06 UTC (permalink / raw)
  To: Shreyansh Jain; +Cc: dev

On Fri, Apr 13, 2018 at 08:19:16PM +0530, Shreyansh Jain wrote:
> On Friday 13 April 2018 06:52 PM, Gaetan Rivet wrote:
> > This function can be used as a callback to
> > rte_kvargs_process.
> > 
> > This should reduce code duplication.
> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >   lib/Makefile                             |  1 +
> >   lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
> >   lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
> >   lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
> >   4 files changed, 46 insertions(+)
> > 
> > diff --git a/lib/Makefile b/lib/Makefile
> > index 1b17526f7..4206485d3 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
> >   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
> > diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
> > index 0a1abf579..6ee04cbb9 100644
> > --- a/lib/librte_kvargs/rte_kvargs.c
> > +++ b/lib/librte_kvargs/rte_kvargs.c
> > @@ -180,3 +180,13 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
> >   	return kvlist;
> >   }
> > +
> > +__rte_experimental
> > +int
> > +rte_kvargs_strcmp(const char *key __rte_unused,
> > +		  const char *value, void *opaque)
> > +{
> > +	const char *str = opaque;
> > +
> > +	return -strcmp(str, value);
> > +}
> > diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
> > index 51b8120b8..c07c6fea5 100644
> > --- a/lib/librte_kvargs/rte_kvargs.h
> > +++ b/lib/librte_kvargs/rte_kvargs.h
> > @@ -25,6 +25,8 @@
> >   extern "C" {
> >   #endif
> > +#include <rte_compat.h>
> > +
> >   /** Maximum number of key/value associations */
> >   #define RTE_KVARGS_MAX 32
> > @@ -121,6 +123,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
> >   unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
> >   	const char *key_match);
> > +/**
> > + * Generic kvarg handler for string comparison.
> > + *
> > + * This function can be used for a generic string comparison processing
> > + * on a list of kvargs.
> > + *
> > + * @param key
> > + *   kvarg pair key.
> > + *
> > + * @param value
> > + *   kvarg pair value.
> > + *
> > + * @param opaque
> > + *   Opaque pointer to a string.
> > + *
> > + * @return
> > + *   0 if the strings match.
> > + *   !0 otherwise or on error.
> > + *
> > + *   Unless strcmp, comparison ordering is not kept.
> > + *   In order for rte_kvargs_process to stop processing on match error,
> > + *   a negative value is returned even if strcmp had returned a positive one.
> 
> Is the above comment valid?
> 
> > +	return -strcmp(str, value);
> 
> In case a negative is returned (when key opaque < value), this function
> would return a positive. So, effectively you have only reversed the values.
> Is that the expectation?
> 
> In 21/22:
> 
> --->8--- rte_kvargs_process ---
>     for (i = 0; i < kvlist->count; i++) {
>         pair = &kvlist->pairs[i];
>         if (key_match == NULL || strcmp(pair->key, key_match) == 0) {
>             if ((*handler)(pair->key, pair->value, opaque_arg) < 0)
>                 return -1;
>         }
>     }
> --->8---
> 
> This would only cause the opaque < value case to continue ahead but not the
> reverse.
> 

Ah! yes, you're right of course.
This is not the expectation, I will fix this.

Thanks,

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-13 12:55                   ` Gaëtan Rivet
@ 2018-04-14 18:45                     ` Neil Horman
  2018-04-15 15:13                       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Neil Horman @ 2018-04-14 18:45 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Shreyansh Jain, dev

On Fri, Apr 13, 2018 at 02:55:11PM +0200, Gaëtan Rivet wrote:
> Hi Shreyansh,
> 
> On Fri, Apr 13, 2018 at 06:22:43PM +0530, Shreyansh Jain wrote:
> > On Friday 13 April 2018 05:12 PM, Neil Horman wrote:
> > > On Thu, Apr 12, 2018 at 11:57:47PM +0200, Gaëtan Rivet wrote:
> > > > Hello Neil,
> > > > 
> > > > On Thu, Apr 12, 2018 at 07:28:26AM -0400, Neil Horman wrote:
> > > > > On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
> > > > > > Build a central list to quickly see each used priorities for
> > > > > > constructors, allowing to verify that they are both above 100 and in the
> > > > > > proper order.
> > > > > > 
> > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > > > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> > > > > > ---
> > > > > >   lib/librte_eal/common/eal_common_log.c     | 2 +-
> > > > > >   lib/librte_eal/common/include/rte_bus.h    | 2 +-
> > > > > >   lib/librte_eal/common/include/rte_common.h | 8 +++++++-
> > > > > >   3 files changed, 9 insertions(+), 3 deletions(-)
> > > > > > 
> > > > > > diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> > > > > > index a27192620..36b9d6e08 100644
> > > > > > --- a/lib/librte_eal/common/eal_common_log.c
> > > > > > +++ b/lib/librte_eal/common/eal_common_log.c
> > > > > > @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
> > > > > >   };
> > > > > >   /* Logging should be first initializer (before drivers and bus) */
> > > > > > -RTE_INIT_PRIO(rte_log_init, 101);
> > > > > > +RTE_INIT_PRIO(rte_log_init, LOG);
> > > > > >   static void
> > > > > >   rte_log_init(void)
> > > > > >   {
> > > > > > diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> > > > > > index 6fb08341a..eb9eded4e 100644
> > > > > > --- a/lib/librte_eal/common/include/rte_bus.h
> > > > > > +++ b/lib/librte_eal/common/include/rte_bus.h
> > > > > > @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
> > > > > >    * The constructor has higher priority than PMD constructors.
> > > > > >    */
> > > > > >   #define RTE_REGISTER_BUS(nm, bus) \
> > > > > > -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> > > > > > +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
> > > > > >   static void businitfn_ ##nm(void) \
> > > > > >   {\
> > > > > >   	(bus).name = RTE_STR(nm);\
> > > > > > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > > > > > index 6c5bc5a76..8f04518f7 100644
> > > > > > --- a/lib/librte_eal/common/include/rte_common.h
> > > > > > +++ b/lib/librte_eal/common/include/rte_common.h
> > > > > > @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
> > > > > >    */
> > > > > >   #define RTE_SET_USED(x) (void)(x)
> > > > > > +#define RTE_PRIORITY_LOG 101
> > > > > > +#define RTE_PRIORITY_BUS 110
> > > > > > +
> > > > > > +#define RTE_PRIO(prio) \
> > > > > > +	RTE_PRIORITY_ ## prio
> > > > > > +
> > > > > >   /**
> > > > > >    * Run function before main() with low priority.
> > > > > >    *
> > > > > > @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
> > > > > >    *   Lowest number is the first to run.
> > > > > >    */
> > > > > >   #define RTE_INIT_PRIO(func, prio) \
> > > > > > -static void __attribute__((constructor(prio), used)) func(void)
> > > > > > +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> > > > > It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
> > > > > and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
> > > > > presume that constructors with no explicit priority run last, but the gcc
> > > > > manual doesn't explicitly say that.  It would be a heck of a bug to track down
> > > > > if somehow unprioritized constructors ran early.
> > > > > 
> > > > > Neil
> > > > > 
> > > > 
> > > > While certainly poorly documented, the behavior is well-defined. I don't see
> > > > a situation where the bug you describe could arise.
> > > > 
> > > > Adding RTE_PRIORITY_LAST is pretty harmless, but I'm not sure it's
> > > > justified to add it. If you still think it is useful, I will do it.
> > > > 
> > > It was more just a way to unify the macros is all, probably not important.
> > > 
> > > > I'd be curious to hear if anyone has had issues of this kind.
> > > > 
> > > I've not had any, but I was suprised to see that the gcc manual didn't
> > > explicitly call out the implied priority of unprioritized constructors
> > 
> > I (tried to) looked into the gcc code base. It seems that when priority is
> > not defined, DEFAULT_INIT_PRIORITY 65536, is used.
> > 
> > --->8--- gcc/collect2.c ---
> >   /* Extract init_p number from ctor/dtor name.  */
> >   pri = atoi (name + pos);
> >   return pri ? pri : DEFAULT_INIT_PRIORITY;
> > --->8---
> > 
> > Though, I couldn't find any documentation for this fact - and, I can never
> > be confident about gcc code.
> > 
> > I found one of the ARM compiler (clang) does has a policy for using
> > non-specified priority as lower than specified priority. [1]
> > 
> > [1] https://developer.arm.com/docs/dui0774/latest/compiler-specific-function-variable-and-type-attributes/__attribute__constructorpriority-function-attribute
> > 
> > A specified value for RTE_PRIORITY_LAST is not a bad option - it would help
> > in keeping the priorities bound without relying on the unknown of priority
> > for unspecified constructors.
> 
> This is interesting, thanks for looking up the GCC code.
> Ok, unless someone has a strong reason not to, I will add
> RTE_PRIORITY_LAST. Not really convinced about it but not
> opposed enough either :) .
> 
I concur.  It sounds like gcc is safe, but clangs priority scheme makes me want
our priorities to be explicit.

Neil

> Regards,
> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 00/22] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (20 preceding siblings ...)
  2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
@ 2018-04-15 15:07 ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 01/22] kvargs: build before EAL Gaetan Rivet
                     ` (22 more replies)
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                   ` (3 subsequent siblings)
  25 siblings, 23 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.

v5:

  * Rebased on master
  * Use strcspn instead of custom function.
  * Introduce private generic rte_eth_dev iterator.
    This could be generalized to other iterators
    (port_next, owner_id-aware, etc).
  * Attempted to support meson.build.
    Got lost in the implicit variables declared
    when inversing dependencies between kvargs and EAL.
    Removed anything related to meson.
  * Postponed genericization of work from
    device query to device declaration.
    Much bigger than anticipated, will let this
    part get in first and iterate over it.

v6:

  * Rebased on master
  * Introduce RTE_PRIORITY_LAST, to explicitly set
    the lowest constructor priority.
  * Fix copyright notice for eth_privage.* files.

v7:

  * Rebased on master
  * Fix rte_kvargs_strcmp return value.
  * Fix layer parsing error
    devstr "bus=pci/onemorelayer" now tells
    that the additional layer is not recognized.

Gaetan Rivet (22):
  kvargs: build before EAL
  eal: list acceptable init priorities
  eal: add last init priority
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: fix find device implementation
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: fix find device implementation
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: add private generic device iterator
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                             |  52 ++++
 drivers/bus/pci/Makefile                           |   2 +-
 drivers/bus/pci/pci_common.c                       |  87 +++++-
 drivers/bus/pci/rte_bus_pci.h                      |   3 +
 drivers/bus/vdev/Makefile                          |   3 +-
 drivers/bus/vdev/rte_bus_vdev.h                    |   3 +
 drivers/bus/vdev/vdev.c                            |  66 ++++-
 lib/Makefile                                       |   7 +-
 lib/librte_eal/bsdapp/eal/Makefile                 |   2 +
 lib/librte_eal/common/Makefile                     |   4 +-
 lib/librte_eal/common/eal_common_class.c           |  62 ++++
 lib/librte_eal/common/eal_common_dev.c             | 317 +++++++++++++++++++++
 lib/librte_eal/common/eal_common_log.c             |   2 +-
 lib/librte_eal/common/include/rte_bus.h            |   3 +-
 lib/librte_eal/common/include/rte_class.h          | 127 +++++++++
 lib/librte_eal/common/include/rte_common.h         |  53 +++-
 lib/librte_eal/common/include/rte_dev.h            |  97 +++++++
 lib/librte_eal/linuxapp/eal/Makefile               |   2 +
 lib/librte_eal/rte_eal_version.map                 |   4 +
 lib/librte_ether/Makefile                          |   4 +-
 lib/librte_ether/eth_private.c                     |  31 ++
 lib/librte_ether/eth_private.h                     |  26 ++
 lib/librte_ether/rte_class_eth.c                   |  86 ++++++
 lib/librte_kvargs/Makefile                         |   3 +-
 lib/librte_kvargs/rte_kvargs.c                     |  12 +-
 lib/librte_kvargs/rte_kvargs.h                     |  28 ++
 lib/librte_kvargs/rte_kvargs_version.map           |   7 +
 .../include => librte_kvargs}/rte_string_fns.h     |   0
 28 files changed, 1056 insertions(+), 37 deletions(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ether/eth_private.c
 create mode 100644 lib/librte_ether/eth_private.h
 create mode 100644 lib/librte_ether/rte_class_eth.c
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 01/22] kvargs: build before EAL
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-06-14 14:10     ` Bruce Richardson
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 02/22] eal: list acceptable init priorities Gaetan Rivet
                     ` (21 subsequent siblings)
  22 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                                                      | 3 +--
 lib/librte_eal/common/Makefile                                    | 2 +-
 lib/librte_kvargs/Makefile                                        | 3 ++-
 lib/librte_kvargs/rte_kvargs.c                                    | 2 +-
 lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
 5 files changed, 5 insertions(+), 5 deletions(-)
 rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)

diff --git a/lib/Makefile b/lib/Makefile
index ec965a606..fc7a55a37 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -71,8 +72,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 48f870f24..dbd19331b 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -9,7 +9,7 @@ INC += rte_errno.h rte_launch.h rte_lcore.h
 INC += rte_log.h rte_memory.h rte_memzone.h
 INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
-INC += rte_string_fns.h rte_version.h
+INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
 INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 4eaa9334d..e026ecc21 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -37,7 +37,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
@@ -48,6 +48,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c
 
 # install includes
 INCS := rte_kvargs.h
+INCS += rte_string_fns.h
 SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS)
 
 include $(RTE_SDK)/mk/rte.lib.mk
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..0a1abf579 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -7,8 +7,8 @@
 #include <stdlib.h>
 
 #include <rte_log.h>
-#include <rte_string_fns.h>
 
+#include "rte_string_fns.h"
 #include "rte_kvargs.h"
 
 /*
diff --git a/lib/librte_eal/common/include/rte_string_fns.h b/lib/librte_kvargs/rte_string_fns.h
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_kvargs/rte_string_fns.h
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 02/22] eal: list acceptable init priorities
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 01/22] kvargs: build before EAL Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 03/22] eal: add last init priority Gaetan Rivet
                     ` (20 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Build a central list to quickly see each used priorities for
constructors, allowing to verify that they are both above 100 and in the
proper order.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
 lib/librte_eal/common/eal_common_log.c     | 2 +-
 lib/librte_eal/common/include/rte_bus.h    | 2 +-
 lib/librte_eal/common/include/rte_common.h | 8 +++++++-
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
index a27192620..36b9d6e08 100644
--- a/lib/librte_eal/common/eal_common_log.c
+++ b/lib/librte_eal/common/eal_common_log.c
@@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
 };
 
 /* Logging should be first initializer (before drivers and bus) */
-RTE_INIT_PRIO(rte_log_init, 101);
+RTE_INIT_PRIO(rte_log_init, LOG);
 static void
 rte_log_init(void)
 {
diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index 6fb08341a..eb9eded4e 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
  * The constructor has higher priority than PMD constructors.
  */
 #define RTE_REGISTER_BUS(nm, bus) \
-RTE_INIT_PRIO(businitfn_ ##nm, 110); \
+RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
 static void businitfn_ ##nm(void) \
 {\
 	(bus).name = RTE_STR(nm);\
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 6c5bc5a76..8f04518f7 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
  */
 #define RTE_SET_USED(x) (void)(x)
 
+#define RTE_PRIORITY_LOG 101
+#define RTE_PRIORITY_BUS 110
+
+#define RTE_PRIO(prio) \
+	RTE_PRIORITY_ ## prio
+
 /**
  * Run function before main() with low priority.
  *
@@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
  *   Lowest number is the first to run.
  */
 #define RTE_INIT_PRIO(func, prio) \
-static void __attribute__((constructor(prio), used)) func(void)
+static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
  * Force a function to be inlined
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 03/22] eal: add last init priority
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 01/22] kvargs: build before EAL Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 02/22] eal: list acceptable init priorities Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 04/22] eal: introduce dtor macros Gaetan Rivet
                     ` (19 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Add the priority RTE_PRIORITY_LAST, used for initialization routines
meant to be run after all other constructors.

This priority becomes the default priority for all DPDK constructors.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 8f04518f7..69e5ed1e3 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,22 +83,12 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
 	RTE_PRIORITY_ ## prio
 
 /**
- * Run function before main() with low priority.
- *
- * The constructor will be run after prioritized constructors.
- *
- * @param func
- *   Constructor function.
- */
-#define RTE_INIT(func) \
-static void __attribute__((constructor, used)) func(void)
-
-/**
  * Run function before main() with high priority.
  *
  * @param func
@@ -111,6 +101,17 @@ static void __attribute__((constructor, used)) func(void)
 static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 
 /**
+ * Run function before main() with low priority.
+ *
+ * The constructor will be run after prioritized constructors.
+ *
+ * @param func
+ *   Constructor function.
+ */
+#define RTE_INIT(func) \
+	RTE_INIT_PRIO(func, LAST)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 04/22] eal: introduce dtor macros
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (2 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 03/22] eal: add last init priority Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 05/22] eal: introduce device class abstraction Gaetan Rivet
                     ` (18 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 69e5ed1e3..d48e0ec56 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -112,6 +112,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 	RTE_INIT_PRIO(func, LAST)
 
 /**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+	RTE_FINI_PRIO(func, LAST)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 05/22] eal: introduce device class abstraction
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (3 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 04/22] eal: introduce dtor macros Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 06/22] eal/class: register destructor Gaetan Rivet
                     ` (17 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 7 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index 200285e01..de0e6d166 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -51,6 +51,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index dbd19331b..f9d17e7ec 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..b5e550a34
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index d48e0ec56..ab6b4cf2a 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 #define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 45517a27b..b11f92e03 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -59,6 +59,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index d02d80b8a..75121b08d 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -221,6 +221,8 @@ EXPERIMENTAL {
 	rte_eal_devargs_insert;
 	rte_eal_devargs_parse;
 	rte_eal_devargs_remove;
+	rte_class_register;
+	rte_class_unregister;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
 	rte_eal_mbuf_user_pool_ops;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 06/22] eal/class: register destructor
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (4 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 05/22] eal: introduce device class abstraction Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 07/22] eal/dev: add device iterator interface Gaetan Rivet
                     ` (16 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index b5e550a34..e8176f5e1 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 07/22] eal/dev: add device iterator interface
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (5 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 06/22] eal/class: register destructor Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 08/22] eal/class: add device iteration Gaetan Rivet
                     ` (15 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 0955e9adb..a789defc3 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -282,6 +282,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 08/22] eal/class: add device iteration
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (6 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 07/22] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 09/22] eal/bus: " Gaetan Rivet
                     ` (14 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index e8176f5e1..9d5b06807 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 09/22] eal/bus: add device iteration
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (7 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 08/22] eal/class: add device iteration Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 10/22] eal/dev: implement device iteration initialization Gaetan Rivet
                     ` (13 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 10/22] eal/dev: implement device iteration initialization
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (8 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 09/22] eal/bus: " Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 11/22] eal/dev: implement device iteration Gaetan Rivet
                     ` (12 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@6wind.com>
---
 lib/Makefile                            |   1 +
 lib/librte_eal/bsdapp/eal/Makefile      |   1 +
 lib/librte_eal/common/eal_common_dev.c  | 149 ++++++++++++++++++++++++++++++++
 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, 177 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 de0e6d166..35f98448c 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 149e9ad72..9b6d8bab7 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 <rte_spinlock.h>
 #include <rte_malloc.h>
@@ -368,3 +371,149 @@ dev_callback_process(char *device_name, enum rte_dev_event_type event)
 	}
 	rte_spinlock_unlock(&dev_event_lock);
 }
+
+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) ||
+		    i >= nblayer) {
+			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 a789defc3..eb1ad6182 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -329,6 +329,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 b11f92e03..47fd07323 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 75121b08d..1a41e9413 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -223,6 +223,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

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 11/22] eal/dev: implement device iteration
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (9 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 10/22] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 12/22] kvargs: add generic string matching callback Gaetan Rivet
                     ` (11 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  26 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 195 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 9b6d8bab7..5a8cabfc4 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
 /* spinlock for device callbacks */
 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -517,3 +539,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 	}
 	return -rte_errno;
 }
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	size_t end;
+	char *copy;
+
+	end = strcspn(str, ",/");
+	if (str[end] == ',') {
+		copy = strdup(&str[end + 1]);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_copy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_copy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index eb1ad6182..bfa57287a 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -353,6 +353,32 @@ __rte_experimental
 int
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 1a41e9413..483ed94c4 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -224,6 +224,7 @@ EXPERIMENTAL {
 	rte_class_register;
 	rte_class_unregister;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_eal_hotplug_add;
 	rte_eal_hotplug_remove;
 	rte_eal_mbuf_user_pool_ops;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 12/22] kvargs: add generic string matching callback
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (10 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 11/22] eal/dev: implement device iteration Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 13/22] bus/pci: fix find device implementation Gaetan Rivet
                     ` (10 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
 4 files changed, 46 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 1b17526f7..4206485d3 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 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
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 0a1abf579..056754214 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -180,3 +180,13 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -abs(strcmp(str, value));
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..c07c6fea5 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -121,6 +123,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..e2f663a88 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 13/22] bus/pci: fix find device implementation
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (11 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 12/22] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 14/22] bus/pci: implement device iteration and comparison Gaetan Rivet
                     ` (9 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set, and a device before it matches the data
passed for comparison, then this first device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2a00f365a..2c45f8151 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -459,17 +459,20 @@ static struct rte_device *
 pci_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		const void *data)
 {
-	struct rte_pci_device *dev;
+	const struct rte_pci_device *pstart;
+	struct rte_pci_device *pdev;
 
-	FOREACH_DEVICE_ON_PCIBUS(dev) {
-		if (start && &dev->device == start) {
-			start = NULL; /* starting point found */
-			continue;
-		}
-		if (cmp(&dev->device, data) == 0)
-			return &dev->device;
+	if (start != NULL) {
+		pstart = RTE_DEV_TO_PCI_CONST(start);
+		pdev = TAILQ_NEXT(pstart, next);
+	} else {
+		pdev = TAILQ_FIRST(&rte_pci_bus.device_list);
+	}
+	while (pdev != NULL) {
+		if (cmp(&pdev->device, data) == 0)
+			return &pdev->device;
+		pdev = TAILQ_NEXT(pdev, next);
 	}
-
 	return NULL;
 }
 
diff --git a/drivers/bus/pci/rte_bus_pci.h b/drivers/bus/pci/rte_bus_pci.h
index 357afb912..458e6d076 100644
--- a/drivers/bus/pci/rte_bus_pci.h
+++ b/drivers/bus/pci/rte_bus_pci.h
@@ -74,6 +74,9 @@ struct rte_pci_device {
  */
 #define RTE_DEV_TO_PCI(ptr) container_of(ptr, struct rte_pci_device, device)
 
+#define RTE_DEV_TO_PCI_CONST(ptr) \
+	container_of(ptr, const struct rte_pci_device, device)
+
 #define RTE_ETH_DEV_TO_PCI(eth_dev)	RTE_DEV_TO_PCI((eth_dev)->device)
 
 /** Any PCI device identifier (vendor, device, ...) */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 14/22] bus/pci: implement device iteration and comparison
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (12 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 13/22] bus/pci: fix find device implementation Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 15/22] bus/pci: add device matching field id Gaetan Rivet
                     ` (8 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index 804a198d1..bbda567c1 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -53,7 +53,7 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 2c45f8151..bd9ecddc6 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -13,6 +13,7 @@
 
 #include <rte_errno.h>
 #include <rte_interrupts.h>
+#include <rte_kvargs.h>
 #include <rte_log.h>
 #include <rte_bus.h>
 #include <rte_pci.h>
@@ -497,6 +498,46 @@ pci_unplug(struct rte_device *dev)
 	return ret;
 }
 
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+static void *
+pci_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_device *dev;
+	struct rte_kvargs *kvargs = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = pci_find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 struct rte_pci_bus rte_pci_bus = {
 	.bus = {
 		.scan = rte_pci_scan,
@@ -506,6 +547,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 15/22] bus/pci: add device matching field id
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (13 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 14/22] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 16/22] bus/vdev: fix find device implementation Gaetan Rivet
                     ` (7 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index bd9ecddc6..3666e4caa 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -499,21 +499,45 @@ pci_unplug(struct rte_device *dev)
 }
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return rte_pci_addr_cmp(addr1, addr2);
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 16/22] bus/vdev: fix find device implementation
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (14 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 15/22] bus/pci: add device matching field id Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 17/22] bus/vdev: implement device iteration Gaetan Rivet
                     ` (6 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, stable

If start is set and a device before it matches the data,
this device is returned.

This induces potentially infinite loops.

Fixes: c7fe1eea8a74 ("bus: simplify finding starting point")
Cc: stable@dpdk.org

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/drivers/bus/vdev/rte_bus_vdev.h b/drivers/bus/vdev/rte_bus_vdev.h
index 646d6c090..f9b5eb596 100644
--- a/drivers/bus/vdev/rte_bus_vdev.h
+++ b/drivers/bus/vdev/rte_bus_vdev.h
@@ -25,6 +25,9 @@ struct rte_vdev_device {
 #define RTE_DEV_TO_VDEV(ptr) \
 	container_of(ptr, struct rte_vdev_device, device)
 
+#define RTE_DEV_TO_VDEV_CONST(ptr) \
+	container_of(ptr, const struct rte_vdev_device, device)
+
 static inline const char *
 rte_vdev_device_name(const struct rte_vdev_device *dev)
 {
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index f8dd1f5e6..c135554c0 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -358,15 +358,19 @@ static struct rte_device *
 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
 		 const void *data)
 {
+	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
 
-	TAILQ_FOREACH(dev, &vdev_device_list, next) {
-		if (start && &dev->device == start) {
-			start = NULL;
-			continue;
-		}
+	if (start != NULL) {
+		vstart = RTE_DEV_TO_VDEV_CONST(start);
+		dev = TAILQ_NEXT(vstart, next);
+	} else {
+		dev = TAILQ_FIRST(&vdev_device_list);
+	}
+	while (dev != NULL) {
 		if (cmp(&dev->device, data) == 0)
 			return &dev->device;
+		dev = TAILQ_NEXT(dev, next);
 	}
 	return NULL;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 17/22] bus/vdev: implement device iteration
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (15 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 16/22] bus/vdev: fix find device implementation Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 18/22] bus/vdev: add device matching field driver Gaetan Rivet
                     ` (5 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 24d424a38..52728833c 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index c135554c0..5bb87af28 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -15,6 +15,7 @@
 #include <rte_bus.h>
 #include <rte_common.h>
 #include <rte_devargs.h>
+#include <rte_kvargs.h>
 #include <rte_memory.h>
 #include <rte_tailq.h>
 #include <rte_spinlock.h>
@@ -387,6 +388,46 @@ vdev_unplug(struct rte_device *dev)
 	return rte_vdev_uninit(dev->name);
 }
 
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+static void *
+vdev_dev_iterate(const void *start,
+		 const char *str,
+		 const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
+
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
@@ -394,6 +435,7 @@ static struct rte_bus rte_vdev_bus = {
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 18/22] bus/vdev: add device matching field driver
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (16 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 17/22] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 19/22] ethdev: add private generic device iterator Gaetan Rivet
                     ` (4 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile |  1 +
 drivers/bus/vdev/vdev.c   | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index 52728833c..db6bee98a 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -10,6 +10,7 @@ LIB = librte_bus_vdev.a
 
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
+CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 # versioning export map
 EXPORT_MAP := rte_bus_vdev_version.map
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 5bb87af28..84192d79b 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -389,10 +389,12 @@ vdev_unplug(struct rte_device *dev)
 }
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -401,9 +403,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 19/22] ethdev: add private generic device iterator
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (17 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 18/22] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 20/22] ethdev: register ether layer as a class Gaetan Rivet
                     ` (3 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This iterator can be customized with a comparison function that will
trigger a stopping condition.

It can be leveraged to write several different iterators that have
similar but non-identical purposes.

It is private to librte_ether.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/Makefile      |  1 +
 lib/librte_ether/eth_private.c | 31 +++++++++++++++++++++++++++++++
 lib/librte_ether/eth_private.h | 26 ++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)
 create mode 100644 lib/librte_ether/eth_private.c
 create mode 100644 lib/librte_ether/eth_private.h

diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index c2f2f7d82..2fa133fbc 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 9
 
+SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
diff --git a/lib/librte_ether/eth_private.c b/lib/librte_ether/eth_private.c
new file mode 100644
index 000000000..d565568a0
--- /dev/null
+++ b/lib/librte_ether/eth_private.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include "rte_ethdev.h"
+#include "eth_private.h"
+
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
+		const void *data)
+{
+	struct rte_eth_dev *edev;
+	ptrdiff_t idx;
+
+	/* Avoid Undefined Behaviour */
+	if (start != NULL &&
+	    (start < &rte_eth_devices[0] ||
+	     start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+		return NULL;
+	if (start != NULL)
+		idx = start - &rte_eth_devices[0] + 1;
+	else
+		idx = 0;
+	for (; idx < RTE_MAX_ETHPORTS; idx++) {
+		edev = &rte_eth_devices[idx];
+		if (cmp(edev, data) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
diff --git a/lib/librte_ether/eth_private.h b/lib/librte_ether/eth_private.h
new file mode 100644
index 000000000..0f5c6d5c4
--- /dev/null
+++ b/lib/librte_ether/eth_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_ETH_PRIVATE_H_
+#define _RTE_ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
+		const void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 20/22] ethdev: register ether layer as a class
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (18 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 19/22] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 21/22] ethdev: add device matching field name Gaetan Rivet
                     ` (2 subsequent siblings)
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                     |  2 +-
 lib/librte_ether/Makefile        |  3 +-
 lib/librte_ether/rte_class_eth.c | 79 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 2 deletions(-)
 create mode 100644 lib/librte_ether/rte_class_eth.c

diff --git a/lib/Makefile b/lib/Makefile
index 4206485d3..47513f03f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline
 DEPDIRS-librte_cmdline := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether
 DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring
-DEPDIRS-librte_ether += librte_mbuf
+DEPDIRS-librte_ether += librte_mbuf librte_kvargs
 DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev
 DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf
 DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
diff --git a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile
index 2fa133fbc..d4c3a8d06 100644
--- a/lib/librte_ether/Makefile
+++ b/lib/librte_ether/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
@@ -20,6 +20,7 @@ LIBABIVER := 9
 
 SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
new file mode 100644
index 000000000..32c736d32
--- /dev/null
+++ b/lib/librte_ether/rte_class_eth.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "eth_private.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+	struct rte_device *device;
+	struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+	(&(const struct eth_dev_match_arg) { \
+		.device = (d), \
+		.kvlist = (k), \
+	})
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+	      const void *_arg)
+{
+	const struct eth_dev_match_arg *arg = _arg;
+	const struct rte_kvargs *kvlist = arg->kvlist;
+
+	if (edev->state == RTE_ETH_DEV_UNUSED)
+		return -1;
+	if (edev->device != arg->device)
+		return -1;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	edev = eth_find_device(start, eth_dev_match,
+			       eth_dev_match_arg(it->device, kvargs));
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 21/22] ethdev: add device matching field name
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (19 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 20/22] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device command Gaetan Rivet
  2018-04-22 22:54   ` [dpdk-dev] [PATCH v7 00/22] Device querying Thomas Monjalon
  22 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ether/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/librte_ether/rte_class_eth.c b/lib/librte_ether/rte_class_eth.c
index 32c736d32..d8d8e8845 100644
--- a/lib/librte_ether/rte_class_eth.c
+++ b/lib/librte_ether/rte_class_eth.c
@@ -15,10 +15,12 @@
 #include "eth_private.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -39,6 +41,7 @@ eth_dev_match(const struct rte_eth_dev *edev,
 {
 	const struct eth_dev_match_arg *arg = _arg;
 	const struct rte_kvargs *kvlist = arg->kvlist;
+	struct rte_eth_dev_data *data;
 
 	if (edev->state == RTE_ETH_DEV_UNUSED)
 		return -1;
@@ -47,6 +50,10 @@ eth_dev_match(const struct rte_eth_dev *edev,
 	if (kvlist == NULL)
 		/* Empty string matches everything. */
 		return 0;
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device command
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (20 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 21/22] ethdev: add device matching field name Gaetan Rivet
@ 2018-04-15 15:07   ` Gaetan Rivet
  2018-06-14 10:59     ` Iremonger, Bernard
  2018-04-22 22:54   ` [dpdk-dev] [PATCH v7 00/22] Device querying Thomas Monjalon
  22 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-04-15 15:07 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 40b31ad7e..8ac5fb3ca 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device "
+		"<device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-14 18:45                     ` Neil Horman
@ 2018-04-15 15:13                       ` Gaëtan Rivet
  2018-04-16 11:31                         ` Neil Horman
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-15 15:13 UTC (permalink / raw)
  To: Neil Horman; +Cc: Shreyansh Jain, dev

Hello Neil,

On Sat, Apr 14, 2018 at 02:45:45PM -0400, Neil Horman wrote:
> On Fri, Apr 13, 2018 at 02:55:11PM +0200, Gaëtan Rivet wrote:
> > Hi Shreyansh,
> > 
> > On Fri, Apr 13, 2018 at 06:22:43PM +0530, Shreyansh Jain wrote:
> > > On Friday 13 April 2018 05:12 PM, Neil Horman wrote:
> > > > On Thu, Apr 12, 2018 at 11:57:47PM +0200, Gaëtan Rivet wrote:
> > > > > Hello Neil,
> > > > > 
> > > > > On Thu, Apr 12, 2018 at 07:28:26AM -0400, Neil Horman wrote:
> > > > > > On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
> > > > > > > Build a central list to quickly see each used priorities for
> > > > > > > constructors, allowing to verify that they are both above 100 and in the
> > > > > > > proper order.
> > > > > > > 
> > > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > > > > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> > > > > > > ---
> > > > > > >   lib/librte_eal/common/eal_common_log.c     | 2 +-
> > > > > > >   lib/librte_eal/common/include/rte_bus.h    | 2 +-
> > > > > > >   lib/librte_eal/common/include/rte_common.h | 8 +++++++-
> > > > > > >   3 files changed, 9 insertions(+), 3 deletions(-)
> > > > > > > 
> > > > > > > diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> > > > > > > index a27192620..36b9d6e08 100644
> > > > > > > --- a/lib/librte_eal/common/eal_common_log.c
> > > > > > > +++ b/lib/librte_eal/common/eal_common_log.c
> > > > > > > @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
> > > > > > >   };
> > > > > > >   /* Logging should be first initializer (before drivers and bus) */
> > > > > > > -RTE_INIT_PRIO(rte_log_init, 101);
> > > > > > > +RTE_INIT_PRIO(rte_log_init, LOG);
> > > > > > >   static void
> > > > > > >   rte_log_init(void)
> > > > > > >   {
> > > > > > > diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> > > > > > > index 6fb08341a..eb9eded4e 100644
> > > > > > > --- a/lib/librte_eal/common/include/rte_bus.h
> > > > > > > +++ b/lib/librte_eal/common/include/rte_bus.h
> > > > > > > @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
> > > > > > >    * The constructor has higher priority than PMD constructors.
> > > > > > >    */
> > > > > > >   #define RTE_REGISTER_BUS(nm, bus) \
> > > > > > > -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> > > > > > > +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
> > > > > > >   static void businitfn_ ##nm(void) \
> > > > > > >   {\
> > > > > > >   	(bus).name = RTE_STR(nm);\
> > > > > > > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > > > > > > index 6c5bc5a76..8f04518f7 100644
> > > > > > > --- a/lib/librte_eal/common/include/rte_common.h
> > > > > > > +++ b/lib/librte_eal/common/include/rte_common.h
> > > > > > > @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
> > > > > > >    */
> > > > > > >   #define RTE_SET_USED(x) (void)(x)
> > > > > > > +#define RTE_PRIORITY_LOG 101
> > > > > > > +#define RTE_PRIORITY_BUS 110
> > > > > > > +
> > > > > > > +#define RTE_PRIO(prio) \
> > > > > > > +	RTE_PRIORITY_ ## prio
> > > > > > > +
> > > > > > >   /**
> > > > > > >    * Run function before main() with low priority.
> > > > > > >    *
> > > > > > > @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
> > > > > > >    *   Lowest number is the first to run.
> > > > > > >    */
> > > > > > >   #define RTE_INIT_PRIO(func, prio) \
> > > > > > > -static void __attribute__((constructor(prio), used)) func(void)
> > > > > > > +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> > > > > > It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
> > > > > > and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
> > > > > > presume that constructors with no explicit priority run last, but the gcc
> > > > > > manual doesn't explicitly say that.  It would be a heck of a bug to track down
> > > > > > if somehow unprioritized constructors ran early.
> > > > > > 
> > > > > > Neil
> > > > > > 
> > > > > 
> > > > > While certainly poorly documented, the behavior is well-defined. I don't see
> > > > > a situation where the bug you describe could arise.
> > > > > 
> > > > > Adding RTE_PRIORITY_LAST is pretty harmless, but I'm not sure it's
> > > > > justified to add it. If you still think it is useful, I will do it.
> > > > > 
> > > > It was more just a way to unify the macros is all, probably not important.
> > > > 
> > > > > I'd be curious to hear if anyone has had issues of this kind.
> > > > > 
> > > > I've not had any, but I was suprised to see that the gcc manual didn't
> > > > explicitly call out the implied priority of unprioritized constructors
> > > 
> > > I (tried to) looked into the gcc code base. It seems that when priority is
> > > not defined, DEFAULT_INIT_PRIORITY 65536, is used.
> > > 
> > > --->8--- gcc/collect2.c ---
> > >   /* Extract init_p number from ctor/dtor name.  */
> > >   pri = atoi (name + pos);
> > >   return pri ? pri : DEFAULT_INIT_PRIORITY;
> > > --->8---
> > > 
> > > Though, I couldn't find any documentation for this fact - and, I can never
> > > be confident about gcc code.
> > > 
> > > I found one of the ARM compiler (clang) does has a policy for using
> > > non-specified priority as lower than specified priority. [1]
> > > 
> > > [1] https://developer.arm.com/docs/dui0774/latest/compiler-specific-function-variable-and-type-attributes/__attribute__constructorpriority-function-attribute
> > > 
> > > A specified value for RTE_PRIORITY_LAST is not a bad option - it would help
> > > in keeping the priorities bound without relying on the unknown of priority
> > > for unspecified constructors.
> > 
> > This is interesting, thanks for looking up the GCC code.
> > Ok, unless someone has a strong reason not to, I will add
> > RTE_PRIORITY_LAST. Not really convinced about it but not
> > opposed enough either :) .
> > 
> I concur.  It sounds like gcc is safe, but clangs priority scheme makes me want
> our priorities to be explicit.

Unless I've misunderstood, clang documentation describes the same
behavior as GCC?

Anyway, I've sent a new series with RTE_PRIORITY_LAST:

https://dpdk.org/dev/patchwork/patch/38126/

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities
  2018-04-15 15:13                       ` Gaëtan Rivet
@ 2018-04-16 11:31                         ` Neil Horman
  0 siblings, 0 replies; 364+ messages in thread
From: Neil Horman @ 2018-04-16 11:31 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Shreyansh Jain, dev

On Sun, Apr 15, 2018 at 05:13:13PM +0200, Gaëtan Rivet wrote:
> Hello Neil,
> 
> On Sat, Apr 14, 2018 at 02:45:45PM -0400, Neil Horman wrote:
> > On Fri, Apr 13, 2018 at 02:55:11PM +0200, Gaëtan Rivet wrote:
> > > Hi Shreyansh,
> > > 
> > > On Fri, Apr 13, 2018 at 06:22:43PM +0530, Shreyansh Jain wrote:
> > > > On Friday 13 April 2018 05:12 PM, Neil Horman wrote:
> > > > > On Thu, Apr 12, 2018 at 11:57:47PM +0200, Gaëtan Rivet wrote:
> > > > > > Hello Neil,
> > > > > > 
> > > > > > On Thu, Apr 12, 2018 at 07:28:26AM -0400, Neil Horman wrote:
> > > > > > > On Wed, Apr 11, 2018 at 02:04:03AM +0200, Gaetan Rivet wrote:
> > > > > > > > Build a central list to quickly see each used priorities for
> > > > > > > > constructors, allowing to verify that they are both above 100 and in the
> > > > > > > > proper order.
> > > > > > > > 
> > > > > > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > > > > > Acked-by: Neil Horman <nhorman@tuxdriver.com>
> > > > > > > > Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
> > > > > > > > ---
> > > > > > > >   lib/librte_eal/common/eal_common_log.c     | 2 +-
> > > > > > > >   lib/librte_eal/common/include/rte_bus.h    | 2 +-
> > > > > > > >   lib/librte_eal/common/include/rte_common.h | 8 +++++++-
> > > > > > > >   3 files changed, 9 insertions(+), 3 deletions(-)
> > > > > > > > 
> > > > > > > > diff --git a/lib/librte_eal/common/eal_common_log.c b/lib/librte_eal/common/eal_common_log.c
> > > > > > > > index a27192620..36b9d6e08 100644
> > > > > > > > --- a/lib/librte_eal/common/eal_common_log.c
> > > > > > > > +++ b/lib/librte_eal/common/eal_common_log.c
> > > > > > > > @@ -260,7 +260,7 @@ static const struct logtype logtype_strings[] = {
> > > > > > > >   };
> > > > > > > >   /* Logging should be first initializer (before drivers and bus) */
> > > > > > > > -RTE_INIT_PRIO(rte_log_init, 101);
> > > > > > > > +RTE_INIT_PRIO(rte_log_init, LOG);
> > > > > > > >   static void
> > > > > > > >   rte_log_init(void)
> > > > > > > >   {
> > > > > > > > diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
> > > > > > > > index 6fb08341a..eb9eded4e 100644
> > > > > > > > --- a/lib/librte_eal/common/include/rte_bus.h
> > > > > > > > +++ b/lib/librte_eal/common/include/rte_bus.h
> > > > > > > > @@ -325,7 +325,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);
> > > > > > > >    * The constructor has higher priority than PMD constructors.
> > > > > > > >    */
> > > > > > > >   #define RTE_REGISTER_BUS(nm, bus) \
> > > > > > > > -RTE_INIT_PRIO(businitfn_ ##nm, 110); \
> > > > > > > > +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \
> > > > > > > >   static void businitfn_ ##nm(void) \
> > > > > > > >   {\
> > > > > > > >   	(bus).name = RTE_STR(nm);\
> > > > > > > > diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> > > > > > > > index 6c5bc5a76..8f04518f7 100644
> > > > > > > > --- a/lib/librte_eal/common/include/rte_common.h
> > > > > > > > +++ b/lib/librte_eal/common/include/rte_common.h
> > > > > > > > @@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;
> > > > > > > >    */
> > > > > > > >   #define RTE_SET_USED(x) (void)(x)
> > > > > > > > +#define RTE_PRIORITY_LOG 101
> > > > > > > > +#define RTE_PRIORITY_BUS 110
> > > > > > > > +
> > > > > > > > +#define RTE_PRIO(prio) \
> > > > > > > > +	RTE_PRIORITY_ ## prio
> > > > > > > > +
> > > > > > > >   /**
> > > > > > > >    * Run function before main() with low priority.
> > > > > > > >    *
> > > > > > > > @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)
> > > > > > > >    *   Lowest number is the first to run.
> > > > > > > >    */
> > > > > > > >   #define RTE_INIT_PRIO(func, prio) \
> > > > > > > > -static void __attribute__((constructor(prio), used)) func(void)
> > > > > > > > +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> > > > > > > It just occured to me, that perhaps you should add a RTE_PRORITY_LAST priority,
> > > > > > > and redefine RTE_INIT to RTE_INIT_PRIO(func, RTE_PRIORITY_LAST) for clarity.  I
> > > > > > > presume that constructors with no explicit priority run last, but the gcc
> > > > > > > manual doesn't explicitly say that.  It would be a heck of a bug to track down
> > > > > > > if somehow unprioritized constructors ran early.
> > > > > > > 
> > > > > > > Neil
> > > > > > > 
> > > > > > 
> > > > > > While certainly poorly documented, the behavior is well-defined. I don't see
> > > > > > a situation where the bug you describe could arise.
> > > > > > 
> > > > > > Adding RTE_PRIORITY_LAST is pretty harmless, but I'm not sure it's
> > > > > > justified to add it. If you still think it is useful, I will do it.
> > > > > > 
> > > > > It was more just a way to unify the macros is all, probably not important.
> > > > > 
> > > > > > I'd be curious to hear if anyone has had issues of this kind.
> > > > > > 
> > > > > I've not had any, but I was suprised to see that the gcc manual didn't
> > > > > explicitly call out the implied priority of unprioritized constructors
> > > > 
> > > > I (tried to) looked into the gcc code base. It seems that when priority is
> > > > not defined, DEFAULT_INIT_PRIORITY 65536, is used.
> > > > 
> > > > --->8--- gcc/collect2.c ---
> > > >   /* Extract init_p number from ctor/dtor name.  */
> > > >   pri = atoi (name + pos);
> > > >   return pri ? pri : DEFAULT_INIT_PRIORITY;
> > > > --->8---
> > > > 
> > > > Though, I couldn't find any documentation for this fact - and, I can never
> > > > be confident about gcc code.
> > > > 
> > > > I found one of the ARM compiler (clang) does has a policy for using
> > > > non-specified priority as lower than specified priority. [1]
> > > > 
> > > > [1] https://developer.arm.com/docs/dui0774/latest/compiler-specific-function-variable-and-type-attributes/__attribute__constructorpriority-function-attribute
> > > > 
> > > > A specified value for RTE_PRIORITY_LAST is not a bad option - it would help
> > > > in keeping the priorities bound without relying on the unknown of priority
> > > > for unspecified constructors.
> > > 
> > > This is interesting, thanks for looking up the GCC code.
> > > Ok, unless someone has a strong reason not to, I will add
> > > RTE_PRIORITY_LAST. Not really convinced about it but not
> > > opposed enough either :) .
> > > 
> > I concur.  It sounds like gcc is safe, but clangs priority scheme makes me want
> > our priorities to be explicit.
> 
> Unless I've misunderstood, clang documentation describes the same
> behavior as GCC?
> 
hmm, from the description above, Shreyansh indicates that the default priority
in GCC is 65535, which effectively means "run last".  And in clang, the
documentation above says regardless of value, unprioritized constructors always
run after prioritized constructors.

So, yeah, you're right, the behavior is the same.  Though the fact that it took
me two emails and typing it out to confirm that to myself, probably suggests
spelling it out is best :)

> Anyway, I've sent a new series with RTE_PRIORITY_LAST:
> 
> https://dpdk.org/dev/patchwork/patch/38126/
> 
I think that makes the most sense.  Thanks!

Neil

> -- 
> Gaëtan Rivet
> 6WIND
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization
  2018-03-28 11:17                         ` Neil Horman
@ 2018-04-22 22:29                           ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-04-22 22:29 UTC (permalink / raw)
  To: dev; +Cc: Neil Horman, Gaëtan Rivet, Richardson, Bruce, Wiles, Keith

28/03/2018 13:17, Neil Horman:
> On Wed, Mar 28, 2018 at 10:10:07AM +0200, Gaëtan Rivet wrote:
> > On Tue, Mar 27, 2018 at 07:53:46PM -0400, Neil Horman wrote:
> > > On Tue, Mar 27, 2018 at 08:48:01PM +0000, Richardson, Bruce wrote:
> > > > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com]
> > > > > On Tue, Mar 27, 2018 at 09:28:07PM +0100, Bruce Richardson wrote:
> > > > > > On Tue, Mar 27, 2018 at 10:20:40PM +0200, Gaëtan Rivet wrote:
> > > > > > > Neat. The issue is that rte_log.h is not symlink-ed until librte_eal
> > > > > > > is processed. rte_log cannot be included.
> > > > > > >
> > > > > > Sure it can - just pass -I/path/to/eal as a cflag.
> > > > > >
> > > > > > /Bruce
> > > > > 
> > > > > When you put it this way... :)
> > > > > 
> > > > > Sure, this is a solution, of which early symlink was a genericization.
> > > > > I'm just not a fan of having co-dependent libraries.
> > > > > 
> > > > > But this will probably come to that.
> > > > > 
> > > > 
> > > > The other alternative is what was done with rte_compat.h - create a new lib
> > > > just with a single header file in it. Works ok too, and may seem less hacky
> > > > to some folks.
> > > > 
> > > > /Bruce
> > > > 
> > > This seems like a good alternative to me.  I'm not entirely sure why the logging
> > > functions are integrated to EAL anyway.  
> > > 
> > > Neil
> > >  
> > 
> > As I said earlier:
> > 
> > > > > > > > > Ideally rte_log could be made independent (starting skimming EAL
> > > > > > > > > from all the fat), but this is much less trivial.
> > 
> > rte_log could certainly stand on its own. I quickly attempted to make it
> > a library, but this is too much work at this point. I think the EAL
> > should be broken down, it is too monolithic. Problem is that many
> > other libraries / applications, now relies on parts of the EAL that
> > would need to be moved.
> > 
> > So any effort in this direction will be difficult to undertake (and
> > badly received by the community, with good reasons), especially when
> > the workaround is an additional -I cflag.
> > 
> I'm fine with just adding another include path to the CFLAGS for this purpose in
> the short term, just saying I'm not sure why the log library got integrated into
> EAL in the first place.
> 
> Neil

The log functions must be in EAL because they are different per-environment.
The basic functions are the reason of EAL.
I think the problem is somewhere else: we are trying to implemement the complex
device logic in EAL.
We should move all the bus and device logics outside of EAL, in my opinion.
We should also move all the options parsing outside of EAL, and make it optional.

Anyway, these are considerations for the long run.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v7 00/22] Device querying
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
                     ` (21 preceding siblings ...)
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device command Gaetan Rivet
@ 2018-04-22 22:54   ` Thomas Monjalon
  2018-04-24 10:03     ` Gaëtan Rivet
  22 siblings, 1 reply; 364+ messages in thread
From: Thomas Monjalon @ 2018-04-22 22:54 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

15/04/2018 17:07, Gaetan Rivet:
> This patchset introduces a new EAL API for querying devices,
> filtered by arbitrary properties.
> 
> The following elements are introduced to this end:
> 
>  * A new object, "rte_class", is used to describe
>    the device class abstraction layer (eth, crypto, ...).
> 
>  * Both rte_bus and rte_class now offer a way to
>    list their devices and filter the result
>    using locally defined properties.
> 
>  * The rte_dev API now has an rte_dev_iterator, which
>    is the way for the user to define the device filter
>    and iterate upon the resulting set.
> 
> As an example, the "eth" device class is implemented.
> 
> Additionally, the device filters for
> 
>   + rte_bus_pci
>   + rte_bus_vdev
>   + rte_class_eth
> 
> are implemented and can be used with some
> properties each, to show how to extend those.
> 
> Some example of filters:
> 
>   "bus=pci/class=eth"
>   "bus=pci"
>   "class=eth"
>   "class=eth,name=net_ring0"
>   "bus=pci,id=00:00.0"
>   "bus=vdev,driver=net_ring"

Thanks for the very big work Gaetan.

This series has some cleanups, fixes, and more importantly,
introduces the framework for a generic device syntax.

I am not clear what is missing in the properties parsing?
In various buses and classes implementations?

Are we close of the next step, revisiting -w/-b and --vdev options?

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v7 00/22] Device querying
  2018-04-22 22:54   ` [dpdk-dev] [PATCH v7 00/22] Device querying Thomas Monjalon
@ 2018-04-24 10:03     ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-04-24 10:03 UTC (permalink / raw)
  To: Thomas Monjalon
  Cc: dev, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

On Mon, Apr 23, 2018 at 12:54:54AM +0200, Thomas Monjalon wrote:
> 15/04/2018 17:07, Gaetan Rivet:
> > This patchset introduces a new EAL API for querying devices,
> > filtered by arbitrary properties.
> > 
> > The following elements are introduced to this end:
> > 
> >  * A new object, "rte_class", is used to describe
> >    the device class abstraction layer (eth, crypto, ...).
> > 
> >  * Both rte_bus and rte_class now offer a way to
> >    list their devices and filter the result
> >    using locally defined properties.
> > 
> >  * The rte_dev API now has an rte_dev_iterator, which
> >    is the way for the user to define the device filter
> >    and iterate upon the resulting set.
> > 
> > As an example, the "eth" device class is implemented.
> > 
> > Additionally, the device filters for
> > 
> >   + rte_bus_pci
> >   + rte_bus_vdev
> >   + rte_class_eth
> > 
> > are implemented and can be used with some
> > properties each, to show how to extend those.
> > 
> > Some example of filters:
> > 
> >   "bus=pci/class=eth"
> >   "bus=pci"
> >   "class=eth"
> >   "class=eth,name=net_ring0"
> >   "bus=pci,id=00:00.0"
> >   "bus=vdev,driver=net_ring"
> 
> Thanks for the very big work Gaetan.
> 
> This series has some cleanups, fixes, and more importantly,
> introduces the framework for a generic device syntax.
> 
> I am not clear what is missing in the properties parsing?

For properties, parsing is *mostly* done. The general framework is there
for other devs to populate as they see fit.

A thing that will arise when doing so, is that librte_kvargs is somewhat
cumbersome to use as it is, when the "/" character is not considered
"end-of-string". This adds cruft in a lot of places otherwise. So I
think we need to add some way to configure this (or even have this
behavior by default). Otherwise most things are available.

> In various buses and classes implementations?
> 
> Are we close of the next step, revisiting -w/-b and --vdev options?
> 

I started this part to see the scope. It's quite large.
I have issues with the current device declaration syntax, that needs to
be discussed.

1.

One issue is that buses are working on a best-effort basis to probe
drivers. When the "driver=" layer is given, a driver is then explicitly
choosen by the user. This contradicts the current bus logic. The
"driver" layer is necessary to give any device parameters, and choosing
the proper driver beforehand seems user-hostile.

I think the "driver=" part should actually be dropped altogether, which
would simplify the declaration. We'll see if another solution can be
attained.

2.

A second issue is regarding the standing of the "class" layer. The
parsing of devices goes like this:

  0. bus, class and driver is parsed and put in its relevant part
     in the devargs.
  1. Bus parses the devargs and uses its part within it (necessary to
     find the proper device identifier for example).
  2. Bus probes all drivers to find the one able to handle the device.
     At this point, the devargs is passed down to the driver, with all
     three layers (bus, class, driver) parts.
     Driver uses the driver part for its initialization.
  3. Driver calls the device creation function of a class (passing the
     devargs), for example to spawn an rte_eth_dev.
     The class thus parses the class part of the devargs and uses it for
     initialization.

In matter of layer hierarchy, this is not neat and clean:
  bus -> driver -> class.

Drivers are the one having to choose whether to spawn an eth or crypto
of compress device (or any other, in any numbers). Having the class
initialize after the driver however seems prone to conflicts in
configuration (between the hardware init and the higher device class
properties for example).

Another issue that I sidestepped in the device ident, is how to
recognize and handle ambiguous device declarations. Something like:

  --dev bus=pci

would thus match all PCI devices on the system. All would be probed
(akin to blacklist mode), with default parameters. Not aberrant.

However something like

  --dev class=eth

does not mean anything. This cannot be recognized at devargs parsing
time. Such devargs would not actually identify a specific device on a
bus. PCI might be able to handle such case, vdev not. Other buses might
not as well.

So I think it is necessary that at least the bus identifier is given.
The bus identifier is a bus property that is bus-specific: for PCI it is
the "id" property. For vdev it is "driver" (for driver name). This is
not user-friendly. Requiring the bus identifier is not actually, but
this is what was implicitly done by the current devargs "name" field.

But let's think about possible secondary properties: for example, in PCI
bus the vendor id could be a property. Should a devargs
"bus=pci,vendor=0x8086" be accepted, as a set of PCI device could actually
be matched? If multiple devices match the devargs, should the devargs be
cloned for each? I'm tempted to say no, for the sake of simplicity, but
this might be worth thinking about it.

So, as you see, this work is far from done and there are standing issues
that will I think require some discussion from the community.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device command
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device command Gaetan Rivet
@ 2018-06-14 10:59     ` Iremonger, Bernard
  2018-06-14 11:35       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Iremonger, Bernard @ 2018-06-14 10:59 UTC (permalink / raw)
  To: Gaetan Rivet, dev

Hi Gaetan,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> Sent: Sunday, April 15, 2018 4:08 PM
> To: dev@dpdk.org
> Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> Subject: [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device
> command
> 
> A new interactive command is offered:
> 
>    show device <device description>
> 
> This commands lists all rte_device element matching the device description.
> e.g.:
> 
>    show device bus=pci
>    show device bus=vdev
>    show device bus=vdev/class=eth
>    show device bus=vdev,driver=net_ring/class=eth
>    show device bus=vdev/class=eth,name=net_ring0
> 
> These devices may not be otherwise useful, some buses will spawn devices
> to keep track of their assets without having a driver to use them.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  app/test-pmd/cmdline.c | 52
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 52 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> 40b31ad7e..8ac5fb3ca 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
>  	},
>  };
> 
> +/* *** SHOW DEVICE INFO *** */
> +struct cmd_showdevice_result {
> +	cmdline_fixed_string_t show;
> +	cmdline_fixed_string_t device;
> +	cmdline_fixed_string_t filter;
> +};
> +
> +static void
> +cmd_showdevice_dump_device(const struct rte_device *dev) {
> +	const struct rte_driver *drv = dev->driver;
> +
> +	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
> +		drv ? drv->name : "<nil>");
> +}
> +
> +static void cmd_showdevice_parsed(void *parsed_result,
> +				__attribute__((unused)) struct cmdline *cl,
> +				__attribute__((unused)) void *data) {
> +	struct cmd_showdevice_result *res = parsed_result;
> +	struct rte_dev_iterator it;
> +	const struct rte_device *dev;
> +
> +	RTE_DEV_FOREACH(dev, res->filter, &it)
> +		cmd_showdevice_dump_device(dev);
> +}
> +
> +cmdline_parse_token_string_t cmd_showdevice_show =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +				show, "show");
> +cmdline_parse_token_string_t cmd_showdevice_device =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +				device, "device");
> +cmdline_parse_token_string_t cmd_showdevice_filter =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +			filter, NULL);
> +
> +cmdline_parse_inst_t cmd_showdevice = {
> +	.f = cmd_showdevice_parsed,
> +	.data = NULL,
> +	.help_str = "show device "
> +		"<device string>",

.help_str  should be on one line to avoid checkpatch warning.

> +	.tokens = {
> +		(void *)&cmd_showdevice_show,
> +		(void *)&cmd_showdevice_device,
> +		(void *)&cmd_showdevice_filter,
> +		NULL,
> +	},
> +};
> +
>  /* *** SHOW PORT INFO *** */
>  struct cmd_showport_result {
>  	cmdline_fixed_string_t show;
> @@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
>  	(cmdline_parse_inst_t *)&cmd_help_long,
>  	(cmdline_parse_inst_t *)&cmd_quit,
>  	(cmdline_parse_inst_t *)&cmd_load_from_file,
> +	(cmdline_parse_inst_t *)&cmd_showdevice,
>  	(cmdline_parse_inst_t *)&cmd_showport,
>  	(cmdline_parse_inst_t *)&cmd_showqueue,
>  	(cmdline_parse_inst_t *)&cmd_showportall,
> --
> 2.11.0

This patch fails to compile on dpdk_18.08.rc0

There should probably be an update to the testpmd documentation also in doc/guides/testpmd_app_ug/*.rst

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device command
  2018-06-14 10:59     ` Iremonger, Bernard
@ 2018-06-14 11:35       ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-06-14 11:35 UTC (permalink / raw)
  To: Iremonger, Bernard; +Cc: dev

Hi Bernard,

On Thu, Jun 14, 2018 at 10:59:09AM +0000, Iremonger, Bernard wrote:
> Hi Gaetan,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> > Sent: Sunday, April 15, 2018 4:08 PM
> > To: dev@dpdk.org
> > Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> > Subject: [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device
> > command
> > 
> > A new interactive command is offered:
> > 
> >    show device <device description>
> > 
> > This commands lists all rte_device element matching the device description.
> > e.g.:
> > 
> >    show device bus=pci
> >    show device bus=vdev
> >    show device bus=vdev/class=eth
> >    show device bus=vdev,driver=net_ring/class=eth
> >    show device bus=vdev/class=eth,name=net_ring0
> > 
> > These devices may not be otherwise useful, some buses will spawn devices
> > to keep track of their assets without having a driver to use them.
> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >  app/test-pmd/cmdline.c | 52
> > ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 52 insertions(+)
> > 
> > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> > 40b31ad7e..8ac5fb3ca 100644
> > --- a/app/test-pmd/cmdline.c
> > +++ b/app/test-pmd/cmdline.c
> > @@ -6701,6 +6701,57 @@ cmdline_parse_inst_t cmd_showportall = {
> >  	},
> >  };
> > 
> > +/* *** SHOW DEVICE INFO *** */
> > +struct cmd_showdevice_result {
> > +	cmdline_fixed_string_t show;
> > +	cmdline_fixed_string_t device;
> > +	cmdline_fixed_string_t filter;
> > +};
> > +
> > +static void
> > +cmd_showdevice_dump_device(const struct rte_device *dev) {
> > +	const struct rte_driver *drv = dev->driver;
> > +
> > +	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
> > +		drv ? drv->name : "<nil>");
> > +}
> > +
> > +static void cmd_showdevice_parsed(void *parsed_result,
> > +				__attribute__((unused)) struct cmdline *cl,
> > +				__attribute__((unused)) void *data) {
> > +	struct cmd_showdevice_result *res = parsed_result;
> > +	struct rte_dev_iterator it;
> > +	const struct rte_device *dev;
> > +
> > +	RTE_DEV_FOREACH(dev, res->filter, &it)
> > +		cmd_showdevice_dump_device(dev);
> > +}
> > +
> > +cmdline_parse_token_string_t cmd_showdevice_show =
> > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > +				show, "show");
> > +cmdline_parse_token_string_t cmd_showdevice_device =
> > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > +				device, "device");
> > +cmdline_parse_token_string_t cmd_showdevice_filter =
> > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > +			filter, NULL);
> > +
> > +cmdline_parse_inst_t cmd_showdevice = {
> > +	.f = cmd_showdevice_parsed,
> > +	.data = NULL,
> > +	.help_str = "show device "
> > +		"<device string>",
> 
> .help_str  should be on one line to avoid checkpatch warning.
> 

Thanks, will fix.

> > +	.tokens = {
> > +		(void *)&cmd_showdevice_show,
> > +		(void *)&cmd_showdevice_device,
> > +		(void *)&cmd_showdevice_filter,
> > +		NULL,
> > +	},
> > +};
> > +
> >  /* *** SHOW PORT INFO *** */
> >  struct cmd_showport_result {
> >  	cmdline_fixed_string_t show;
> > @@ -16038,6 +16089,7 @@ cmdline_parse_ctx_t main_ctx[] = {
> >  	(cmdline_parse_inst_t *)&cmd_help_long,
> >  	(cmdline_parse_inst_t *)&cmd_quit,
> >  	(cmdline_parse_inst_t *)&cmd_load_from_file,
> > +	(cmdline_parse_inst_t *)&cmd_showdevice,
> >  	(cmdline_parse_inst_t *)&cmd_showport,
> >  	(cmdline_parse_inst_t *)&cmd_showqueue,
> >  	(cmdline_parse_inst_t *)&cmd_showportall,
> > --
> > 2.11.0
> 
> This patch fails to compile on dpdk_18.08.rc0
> 

I have rebased the series in 18.08-rc0, I will send it as a v8.

> There should probably be an update to the testpmd documentation also in doc/guides/testpmd_app_ug/*.rst

I will look into it.

Regards,

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v7 01/22] kvargs: build before EAL
  2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 01/22] kvargs: build before EAL Gaetan Rivet
@ 2018-06-14 14:10     ` Bruce Richardson
  0 siblings, 0 replies; 364+ messages in thread
From: Bruce Richardson @ 2018-06-14 14:10 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Sun, Apr 15, 2018 at 05:07:30PM +0200, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/Makefile                                                      | 3 +--
>  lib/librte_eal/common/Makefile                                    | 2 +-
>  lib/librte_kvargs/Makefile                                        | 3 ++-
>  lib/librte_kvargs/rte_kvargs.c                                    | 2 +-
>  lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
>  5 files changed, 5 insertions(+), 5 deletions(-)
>  rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)
> 

This fails for me when building DPDK for shared libs, due to the dependency
on rte_log. I think if we to have kvargs built first it needs to be
completely independent.

/Bruce

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 00/21] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (21 preceding siblings ...)
  2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
@ 2018-06-26 16:56 ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 01/21] devargs: add non-variadic parsing function Gaetan Rivet
                     ` (21 more replies)
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                   ` (2 subsequent siblings)
  25 siblings, 22 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.

v5:

  * Rebased on master
  * Use strcspn instead of custom function.
  * Introduce private generic rte_eth_dev iterator.
    This could be generalized to other iterators
    (port_next, owner_id-aware, etc).
  * Attempted to support meson.build.
    Got lost in the implicit variables declared
    when inversing dependencies between kvargs and EAL.
    Removed anything related to meson.
  * Postponed genericization of work from
    device query to device declaration.
    Much bigger than anticipated, will let this
    part get in first and iterate over it.

v6:

  * Rebased on master
  * Introduce RTE_PRIORITY_LAST, to explicitly set
    the lowest constructor priority.
  * Fix copyright notice for eth_privage.* files.

v7:

  * Rebased on master
  * Fix rte_kvargs_strcmp return value.
  * Fix layer parsing error
    devstr "bus=pci/onemorelayer" now tells
    that the additional layer is not recognized.

v8:

  * Rebased on master
  * Cleaned kvargs use: introduced
    a new parser function, that simplifies
    using the library for DPDK devargs.
  * Refactored devargs parsing in a single
    function within rte_devargs.
    This function is useful both for rte_dev
    parsing its iterator, and for rte_devargs
    parsing --dev parameters (not yet implemented).
  * A few small bugfixes.

Gaetan Rivet (21):
  devargs: add non-variadic parsing function
  kvargs: build before EAL
  kvargs: introduce a more flexible parsing function
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  devargs: add function to parse device layers
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: add private generic device iterator
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command

 app/test-pmd/cmdline.c                      |  51 +++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  24 +++
 drivers/bus/pci/Makefile                    |   3 +-
 drivers/bus/pci/pci_common.c                |   3 +-
 drivers/bus/pci/pci_params.c                |  78 ++++++++++
 drivers/bus/pci/private.h                   |  25 +++
 drivers/bus/vdev/Makefile                   |   3 +-
 drivers/bus/vdev/vdev.c                     |  10 +-
 drivers/bus/vdev/vdev_params.c              |  62 ++++++++
 drivers/bus/vdev/vdev_private.h             |  26 ++++
 drivers/net/failsafe/failsafe_args.c        |   2 +-
 drivers/net/failsafe/failsafe_eal.c         |   2 +-
 lib/Makefile                                |   5 +-
 lib/librte_eal/bsdapp/eal/Makefile          |   2 +
 lib/librte_eal/common/Makefile              |   2 +-
 lib/librte_eal/common/eal_common_class.c    |  62 ++++++++
 lib/librte_eal/common/eal_common_dev.c      | 227 +++++++++++++++++++++++++++-
 lib/librte_eal/common/eal_common_devargs.c  | 186 +++++++++++++++++++++--
 lib/librte_eal/common/eal_private.h         |  27 ++++
 lib/librte_eal/common/include/rte_bus.h     |   1 +
 lib/librte_eal/common/include/rte_class.h   | 127 ++++++++++++++++
 lib/librte_eal/common/include/rte_common.h  |  24 +++
 lib/librte_eal/common/include/rte_dev.h     |  97 ++++++++++++
 lib/librte_eal/common/include/rte_devargs.h |  53 ++++++-
 lib/librte_eal/linuxapp/eal/Makefile        |   2 +
 lib/librte_eal/rte_eal_version.map          |   5 +
 lib/librte_ethdev/Makefile                  |   4 +-
 lib/librte_ethdev/eth_private.c             |  31 ++++
 lib/librte_ethdev/eth_private.h             |  26 ++++
 lib/librte_ethdev/rte_class_eth.c           |  86 +++++++++++
 lib/librte_ethdev/rte_ethdev.c              |   2 +-
 lib/librte_kvargs/Makefile                  |   2 +-
 lib/librte_kvargs/rte_kvargs.c              |  35 +++++
 lib/librte_kvargs/rte_kvargs.h              |  58 +++++++
 lib/librte_kvargs/rte_kvargs_version.map    |   8 +
 35 files changed, 1328 insertions(+), 33 deletions(-)
 create mode 100644 drivers/bus/pci/pci_params.c
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 01/21] devargs: add non-variadic parsing function
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 02/21] kvargs: build before EAL Gaetan Rivet
                     ` (20 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose
device strings.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/net/failsafe/failsafe_args.c        |  2 +-
 drivers/net/failsafe/failsafe_eal.c         |  2 +-
 lib/librte_eal/common/eal_common_dev.c      |  4 +--
 lib/librte_eal/common/eal_common_devargs.c  | 42 ++++++++++++++++++++++-------
 lib/librte_eal/common/include/rte_devargs.h | 40 +++++++++++++++++++++++++--
 lib/librte_eal/rte_eal_version.map          |  1 +
 lib/librte_ethdev/rte_ethdev.c              |  2 +-
 7 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/drivers/net/failsafe/failsafe_args.c b/drivers/net/failsafe/failsafe_args.c
index 2c002b164..626883ce2 100644
--- a/drivers/net/failsafe/failsafe_args.c
+++ b/drivers/net/failsafe/failsafe_args.c
@@ -63,7 +63,7 @@ fs_parse_device(struct sub_device *sdev, char *args)
 
 	d = &sdev->devargs;
 	DEBUG("%s", args);
-	ret = rte_devargs_parse(d, "%s", args);
+	ret = rte_devargs_parse(d, args);
 	if (ret) {
 		DEBUG("devargs parsing failed with code %d", ret);
 		return ret;
diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c
index 5672f3961..ce1633f13 100644
--- a/drivers/net/failsafe/failsafe_eal.c
+++ b/drivers/net/failsafe/failsafe_eal.c
@@ -86,7 +86,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			else
 				snprintf(devstr, sizeof(devstr), "%s",
 					 rte_eth_devices[pid].device->name);
-			ret = rte_devargs_parse(da, "%s", devstr);
+			ret = rte_devargs_parse(da, devstr);
 			if (ret) {
 				ERROR("Probed devargs parsing failed with code"
 				      " %d", ret);
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 61cb3b162..ce4b51469 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -138,8 +138,8 @@ int __rte_experimental rte_eal_hotplug_add(const char *busname, const char *devn
 	if (da == NULL)
 		return -ENOMEM;
 
-	ret = rte_devargs_parse(da, "%s:%s,%s",
-				    busname, devname, devargs);
+	ret = rte_devargs_parsef(da, "%s:%s,%s",
+				 busname, devname, devargs);
 	if (ret)
 		goto err_devarg;
 
diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index b0434158b..0a83beb94 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -62,24 +62,18 @@ bus_name_cmp(const struct rte_bus *bus, const void *name)
 	return strncmp(bus->name, name, strlen(bus->name));
 }
 
-int __rte_experimental
-rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev)
 {
 	struct rte_bus *bus = NULL;
-	va_list ap;
-	va_start(ap, format);
-	char dev[vsnprintf(NULL, 0, format, ap) + 1];
 	const char *devname;
 	const size_t maxlen = sizeof(da->name);
 	size_t i;
 
-	va_end(ap);
 	if (da == NULL)
 		return -EINVAL;
 
-	va_start(ap, format);
-	vsnprintf(dev, sizeof(dev), format, ap);
-	va_end(ap);
 	/* Retrieve eventual bus info */
 	do {
 		devname = dev;
@@ -124,6 +118,34 @@ rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
 	return 0;
 }
 
+__rte_experimental
+int
+rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
+{
+	va_list ap;
+	size_t len;
+	char *dev;
+
+	if (da == NULL)
+		return -EINVAL;
+
+	va_start(ap, format);
+	len = vsnprintf(NULL, 0, format, ap);
+	va_end(ap);
+
+	dev = calloc(1, len + 1);
+	if (dev == NULL) {
+		fprintf(stderr, "ERROR: not enough memory to parse device\n");
+		return -ENOMEM;
+	}
+
+	va_start(ap, format);
+	vsnprintf(dev, len, format, ap);
+	va_end(ap);
+
+	return rte_devargs_parse(da, dev);
+}
+
 int __rte_experimental
 rte_devargs_insert(struct rte_devargs *da)
 {
@@ -150,7 +172,7 @@ rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	if (devargs == NULL)
 		goto fail;
 
-	if (rte_devargs_parse(devargs, "%s", dev))
+	if (rte_devargs_parse(devargs, dev))
 		goto fail;
 	devargs->type = devtype;
 	bus = devargs->bus;
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 58fbd90a2..6c3b6326b 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -96,6 +96,42 @@ int rte_eal_parse_devargs_str(const char *devargs_str,
  * in argument. Store which bus will handle the device, its name
  * and the eventual device parameters.
  *
+ * The syntax is:
+ *
+ *     bus:device_identifier,arg1=val1,arg2=val2
+ *
+ * where "bus:" is the bus name followed by any character separator.
+ * The bus name is optional. If no bus name is specified, each bus
+ * will attempt to recognize the device identifier. The first one
+ * to succeed will be used.
+ *
+ * Examples:
+ *
+ *     pci:0000:05.00.0,arg=val
+ *     05.00.0,arg=val
+ *     vdev:net_ring0
+ *
+ * @param da
+ *   The devargs structure holding the device information.
+ *
+ * @param dev
+ *   String describing a device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative errno on error.
+ */
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev);
+
+/**
+ * Parse a device string.
+ *
+ * Verify that a bus is capable of handling the device passed
+ * in argument. Store which bus will handle the device, its name
+ * and the eventual device parameters.
+ *
  * The device string is built with a printf-like syntax.
  *
  * The syntax is:
@@ -124,8 +160,8 @@ int rte_eal_parse_devargs_str(const char *devargs_str,
  */
 __rte_experimental
 int
-rte_devargs_parse(struct rte_devargs *da,
-		  const char *format, ...)
+rte_devargs_parsef(struct rte_devargs *da,
+		   const char *format, ...)
 __attribute__((format(printf, 2, 0)));
 
 /**
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index f7dd0e7bc..1c4db72fa 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -254,6 +254,7 @@ EXPERIMENTAL {
 	rte_devargs_insert;
 	rte_devargs_next;
 	rte_devargs_parse;
+	rte_devargs_parsef;
 	rte_devargs_remove;
 	rte_devargs_type_count;
 	rte_eal_cleanup;
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index a9977df97..cce20d9ae 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -654,7 +654,7 @@ rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
 	}
 
 	/* parse devargs */
-	if (rte_devargs_parse(&da, "%s", devargs))
+	if (rte_devargs_parse(&da, devargs))
 		goto err;
 
 	ret = rte_eal_hotplug_add(da.bus->name, da.name, da.args);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 02/21] kvargs: build before EAL
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 01/21] devargs: add non-variadic parsing function Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 03/21] kvargs: introduce a more flexible parsing function Gaetan Rivet
                     ` (19 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile               | 3 +--
 lib/librte_kvargs/Makefile | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index d82462ba2..e8e903c8f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -76,8 +77,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ethdev
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 39d5ac33d..875939547 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -7,7 +7,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 03/21] kvargs: introduce a more flexible parsing function
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 01/21] devargs: add non-variadic parsing function Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 02/21] kvargs: build before EAL Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 04/21] eal: introduce dtor macros Gaetan Rivet
                     ` (18 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function permits defining additional terminating characters,
ending the parsing to arbitrary delimiters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/rte_kvargs.c           | 25 +++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 30 ++++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
 4 files changed, 63 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index e8e903c8f..8a65525cd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-y += librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
+DEPDIRS-librte_kvargs := librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..cfbee3bd9 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -180,3 +180,28 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+struct rte_kvargs *
+rte_kvargs_parse2(const char *args, const char * const valid_keys[],
+		  const char *valid_ends)
+{
+	struct rte_kvargs *kvlist = NULL;
+	char *copy;
+	size_t len;
+
+	if (valid_ends == NULL)
+		return rte_kvargs_parse(args, valid_keys);
+
+	copy = strdup(args);
+	if (copy == NULL)
+		return NULL;
+
+	len = strcspn(copy, valid_ends);
+	copy[len] = '\0';
+
+	kvlist = rte_kvargs_parse(copy, valid_keys);
+
+	free(copy);
+	return kvlist;
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..defdf10e4 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -72,6 +72,36 @@ struct rte_kvargs *rte_kvargs_parse(const char *args,
 		const char *const valid_keys[]);
 
 /**
+ * Allocate a rte_kvargs and store key/value associations from a string.
+ * This version will consider any byte from valid_ends as a possible
+ * terminating character, and will not parse beyond any of their occurence.
+ *
+ * The function allocates and fills an rte_kvargs structure from a given
+ * string whose format is key1=value1,key2=value2,...
+ *
+ * The structure can be freed with rte_kvargs_free().
+ *
+ * @param args
+ *   The input string containing the key/value associations
+ *
+ * @param valid_keys
+ *   A list of valid keys (table of const char *, the last must be NULL).
+ *   This argument is ignored if NULL
+ *
+ * @param valid_ends
+ *   Acceptable terminating characters.
+ *   If NULL, the behavior is the same as ``rte_kvargs_parse``.
+ *
+ * @return
+ *   - A pointer to an allocated rte_kvargs structure on success
+ *   - NULL on error
+ */
+__rte_experimental
+struct rte_kvargs *rte_kvargs_parse2(const char *args,
+		const char *const valid_keys[],
+		const char *valid_ends);
+
+/**
  * Free a rte_kvargs structure
  *
  * Free a rte_kvargs structure previously allocated with
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..b9fe44b98 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_parse2;
+
+} DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 04/21] eal: introduce dtor macros
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (2 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 03/21] kvargs: introduce a more flexible parsing function Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 05/21] eal: introduce device class abstraction Gaetan Rivet
                     ` (17 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 434adfd45..0dd832728 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -112,6 +112,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 	RTE_INIT_PRIO(func, LAST)
 
 /**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+	RTE_FINI_PRIO(func, LAST)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 05/21] eal: introduce device class abstraction
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (3 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 04/21] eal: introduce dtor macros Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 06/21] eal/class: register destructor Gaetan Rivet
                     ` (16 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 7 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index 3fd33f1e4..b0a1c880a 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -52,6 +52,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 48f870f24..750653093 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..b5e550a34
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 0dd832728..a2e8e6e32 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 #define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 3719ec9d7..babc8617a 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -60,6 +60,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 1c4db72fa..19d36b4c7 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -244,6 +244,8 @@ DPDK_18.05 {
 EXPERIMENTAL {
 	global:
 
+	rte_class_register;
+	rte_class_unregister;
 	rte_ctrl_thread_create;
 	rte_dev_event_callback_register;
 	rte_dev_event_callback_unregister;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 06/21] eal/class: register destructor
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (4 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 05/21] eal: introduce device class abstraction Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 07/21] devargs: add function to parse device layers Gaetan Rivet
                     ` (15 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index b5e550a34..e8176f5e1 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 07/21] devargs: add function to parse device layers
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (5 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 06/21] eal/class: register destructor Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 08/21] eal/dev: add device iterator interface Gaetan Rivet
                     ` (14 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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>
---
 lib/librte_eal/common/eal_common_devargs.c  | 144 ++++++++++++++++++++++++++++
 lib/librte_eal/common/eal_private.h         |  27 ++++++
 lib/librte_eal/common/include/rte_devargs.h |  13 ++-
 3 files changed, 181 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 0a83beb94..9fee2153f 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -13,9 +13,13 @@
 #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_kvargs.h>
+#include <rte_errno.h>
 #include <rte_tailq.h>
 #include "eal_private.h"
 
@@ -56,6 +60,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 *da,
+			 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 (da->data != devstr) {
+		da->data = strdup(devstr);
+		if (da->data == NULL) {
+			RTE_LOG(ERR, EAL, "OOM\n");
+			ret = -ENOMEM;
+			goto get_out;
+		}
+		s = da->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_parse2(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. */
+	da->busstr = layers[0].str;
+	da->clsstr = layers[1].str;
+	da->drvstr = layers[2].str;
+	da->bus = bus;
+	da->cls = cls;
+
+	/* If we own the data, clean up a bit
+	 * the several layers string, to ease
+	 * their parsing afterward.
+	 */
+	if (da->data != devstr) {
+		char *s = (void*)(intptr_t)(da->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)
 {
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index bdadc4d50..c4c9283c8 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -258,4 +258,31 @@ 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.
+ *
+ * Note: if the "data" field of da 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 *da,
+			 const char *devstr);
+
 #endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 6c3b6326b..148600258 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -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 *drvstr;
+	};
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< bus-related part of device string. */
+	const char *data; /**< Device string storage. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 08/21] eal/dev: add device iterator interface
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (6 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 07/21] devargs: add function to parse device layers Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 09/21] eal/class: add device iteration Gaetan Rivet
                     ` (13 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 3879ff3ca..120df729f 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -285,6 +285,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 09/21] eal/class: add device iteration
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (7 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 08/21] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 10/21] eal/bus: " Gaetan Rivet
                     ` (12 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index e8176f5e1..9d5b06807 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 10/21] eal/bus: add device iteration
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (8 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 09/21] eal/class: add device iteration Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 11/21] eal/dev: implement device iteration initialization Gaetan Rivet
                     ` (11 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 11/21] eal/dev: implement device iteration initialization
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (9 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 10/21] eal/bus: " Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 12/21] eal/dev: implement device iteration Gaetan Rivet
                     ` (10 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@6wind.com>
---
 lib/Makefile                            |  1 +
 lib/librte_eal/bsdapp/eal/Makefile      |  1 +
 lib/librte_eal/common/eal_common_dev.c  | 55 +++++++++++++++++++++++++++++++++
 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, 83 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 8a65525cd..afa604e20 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index b0a1c880a..67b10ae0d 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 ce4b51469..5b7956d17 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 <rte_spinlock.h>
 #include <rte_malloc.h>
@@ -343,3 +346,55 @@ dev_callback_process(char *device_name, enum rte_dev_event_type event)
 	}
 	rte_spinlock_unlock(&dev_event_lock);
 }
+
+__rte_experimental
+int
+rte_dev_iterator_init(struct rte_dev_iterator *it,
+		      const char *devstr)
+{
+	struct rte_devargs da;
+	struct rte_class *cls = NULL;
+	struct rte_bus *bus = NULL;
+
+	/* Having both busstr and clsstr NULL is illegal,
+	 * marking this iterator as invalid unless
+	 * everything goes well.
+	 */
+	it->busstr = NULL;
+	it->clsstr = NULL;
+
+	da.data = devstr;
+	if (rte_devargs_layers_parse(&da, devstr))
+		goto get_out;
+
+	bus = da.bus;
+	cls = da.cls;
+	/* 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;
+	}
+	it->busstr = da.busstr;
+	it->clsstr = da.clsstr;
+	it->devstr = devstr;
+	it->bus = bus;
+	it->cls = cls;
+	it->device = NULL;
+	it->class_device = NULL;
+get_out:
+	return -rte_errno;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 120df729f..7b7bd83bc 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -332,6 +332,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 babc8617a..885c48110 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 19d36b4c7..ac04120d6 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -251,6 +251,7 @@ EXPERIMENTAL {
 	rte_dev_event_callback_unregister;
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
+	rte_dev_iterator_init;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 12/21] eal/dev: implement device iteration
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (10 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 11/21] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 13/21] kvargs: add generic string matching callback Gaetan Rivet
                     ` (9 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  26 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 195 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 5b7956d17..3d486a841 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
 /* spinlock for device callbacks */
 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 get_out:
 	return -rte_errno;
 }
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	size_t end;
+	char *copy;
+
+	end = strcspn(str, ",/");
+	if (str[end] == ',') {
+		copy = strdup(&str[end + 1]);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_copy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_copy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 7b7bd83bc..1553c0970 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -356,6 +356,32 @@ __rte_experimental
 int
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index ac04120d6..4cd5ab3df 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -252,6 +252,7 @@ EXPERIMENTAL {
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 13/21] kvargs: add generic string matching callback
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (11 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 12/21] eal/dev: implement device iteration Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 14/21] bus/pci: implement device iteration and comparison Gaetan Rivet
                     ` (8 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  1 +
 3 files changed, 39 insertions(+)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index cfbee3bd9..cf24b939e 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -205,3 +205,13 @@ rte_kvargs_parse2(const char *args, const char * const valid_keys[],
 	free(copy);
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -abs(strcmp(str, value));
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index defdf10e4..5c065c3a8 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -151,6 +153,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index b9fe44b98..6a41a6b65 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -13,5 +13,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_kvargs_parse2;
+	rte_kvargs_strcmp;
 
 } DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 14/21] bus/pci: implement device iteration and comparison
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (12 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 13/21] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 15/21] bus/pci: add device matching field id Gaetan Rivet
                     ` (7 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  3 ++-
 drivers/bus/pci/pci_common.c |  3 +--
 drivers/bus/pci/pci_params.c | 53 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/bus/pci/private.h    | 25 +++++++++++++++++++++
 4 files changed, 81 insertions(+), 3 deletions(-)
 create mode 100644 drivers/bus/pci/pci_params.c

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index cf373068a..4de953f8f 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -26,10 +26,11 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
+SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_params.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common_uio.c
 
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 7215aaec3..3c84207ff 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -26,8 +26,6 @@
 
 #include "private.h"
 
-extern struct rte_pci_bus rte_pci_bus;
-
 #define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
 
 const char *rte_pci_get_sysfs_path(void)
@@ -502,6 +500,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = rte_pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
new file mode 100644
index 000000000..0fde75803
--- /dev/null
+++ b/drivers/bus/pci/pci_params.c
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_bus.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_pci.h>
+
+#include "private.h"
+
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it __rte_unused)
+{
+	rte_bus_find_device_t find_device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	find_device = rte_pci_bus.bus.find_device;
+	dev = find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 88fa587e7..eafaeedc7 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -10,6 +10,8 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 
+extern struct rte_pci_bus rte_pci_bus;
+
 struct rte_pci_driver;
 struct rte_pci_device;
 
@@ -216,4 +218,27 @@ rte_pci_match(const struct rte_pci_driver *pci_drv,
 enum rte_iova_mode
 rte_pci_get_iommu_class(void);
 
+/*
+ * Iterate over internal devices,
+ * matching any device against the provided
+ * string.
+ *
+ * @param start
+ *   Iteration starting point.
+ *
+ * @param str
+ *   Device string to match against.
+ *
+ * @param it
+ *   (unused) iterator structure.
+ *
+ * @return
+ *   A pointer to the next matching device if any.
+ *   NULL otherwise.
+ */
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 15/21] bus/pci: add device matching field id
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (13 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 14/21] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 16/21] bus/vdev: implement device iteration Gaetan Rivet
                     ` (6 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_params.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 0fde75803..7630d4845 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -3,6 +3,7 @@
  */
 
 #include <rte_bus.h>
+#include <rte_bus_pci.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
@@ -11,21 +12,45 @@
 #include "private.h"
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return -abs(rte_pci_addr_cmp(addr1, addr2));
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 16/21] bus/vdev: implement device iteration
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (14 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 15/21] bus/pci: add device matching field id Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 17/21] bus/vdev: add device matching field driver Gaetan Rivet
                     ` (5 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile       |  3 ++-
 drivers/bus/vdev/vdev.c         | 10 ++++----
 drivers/bus/vdev/vdev_params.c  | 51 +++++++++++++++++++++++++++++++++++++++++
 drivers/bus/vdev/vdev_private.h | 26 +++++++++++++++++++++
 4 files changed, 85 insertions(+), 5 deletions(-)
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index bd0bb8955..1f9cd7ebe 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,8 +19,9 @@ EXPORT_MAP := rte_bus_vdev_version.map
 LIBABIVER := 1
 
 SRCS-y += vdev.c
+SRCS-y += vdev_params.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 6139dd551..e8518833d 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -23,6 +23,7 @@
 
 #include "rte_bus_vdev.h"
 #include "vdev_logs.h"
+#include "vdev_private.h"
 
 #define VDEV_MP_KEY	"bus_vdev_mp"
 
@@ -493,9 +494,9 @@ vdev_probe(void)
 	return ret;
 }
 
-static struct rte_device *
-vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
-		 const void *data)
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
+		     const void *data)
 {
 	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
@@ -532,10 +533,11 @@ vdev_unplug(struct rte_device *dev)
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
-	.find_device = vdev_find_device,
+	.find_device = rte_vdev_find_device,
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = rte_vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
new file mode 100644
index 000000000..842a4684e
--- /dev/null
+++ b/drivers/bus/vdev/vdev_params.c
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_dev.h>
+#include <rte_bus.h>
+#include <rte_kvargs.h>
+#include <rte_errno.h>
+
+#include "vdev_logs.h"
+#include "vdev_private.h"
+
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = rte_vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/vdev/vdev_private.h b/drivers/bus/vdev/vdev_private.h
new file mode 100644
index 000000000..ba6dc48ff
--- /dev/null
+++ b/drivers/bus/vdev/vdev_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _VDEV_PRIVATE_H_
+#define _VDEV_PRIVATE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start,
+		     rte_dev_cmp_t cmp,
+		     const void *data);
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VDEV_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 17/21] bus/vdev: add device matching field driver
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (15 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 16/21] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 18/21] ethdev: add private generic device iterator Gaetan Rivet
                     ` (4 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev_params.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
index 842a4684e..2f55f451f 100644
--- a/drivers/bus/vdev/vdev_params.c
+++ b/drivers/bus/vdev/vdev_params.c
@@ -4,6 +4,7 @@
 
 #include <rte_dev.h>
 #include <rte_bus.h>
+#include <rte_bus_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
 
@@ -11,10 +12,12 @@
 #include "vdev_private.h"
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -23,9 +26,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 18/21] ethdev: add private generic device iterator
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (16 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 17/21] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 19/21] ethdev: register ether layer as a class Gaetan Rivet
                     ` (3 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This iterator can be customized with a comparison function that will
trigger a stopping condition.

It can be leveraged to write several different iterators that have
similar but non-identical purposes.

It is private to librte_ethdev.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile      |  1 +
 lib/librte_ethdev/eth_private.c | 31 +++++++++++++++++++++++++++++++
 lib/librte_ethdev/eth_private.h | 26 ++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index c2f2f7d82..2fa133fbc 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 9
 
+SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
diff --git a/lib/librte_ethdev/eth_private.c b/lib/librte_ethdev/eth_private.c
new file mode 100644
index 000000000..d565568a0
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include "rte_ethdev.h"
+#include "eth_private.h"
+
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
+		const void *data)
+{
+	struct rte_eth_dev *edev;
+	ptrdiff_t idx;
+
+	/* Avoid Undefined Behaviour */
+	if (start != NULL &&
+	    (start < &rte_eth_devices[0] ||
+	     start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+		return NULL;
+	if (start != NULL)
+		idx = start - &rte_eth_devices[0] + 1;
+	else
+		idx = 0;
+	for (; idx < RTE_MAX_ETHPORTS; idx++) {
+		edev = &rte_eth_devices[idx];
+		if (cmp(edev, data) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
diff --git a/lib/librte_ethdev/eth_private.h b/lib/librte_ethdev/eth_private.h
new file mode 100644
index 000000000..0f5c6d5c4
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_ETH_PRIVATE_H_
+#define _RTE_ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
+		const void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 19/21] ethdev: register ether layer as a class
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (17 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 18/21] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 20/21] ethdev: add device matching field name Gaetan Rivet
                     ` (2 subsequent siblings)
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile        |  3 +-
 lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index 2fa133fbc..d4c3a8d06 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
@@ -20,6 +20,7 @@ LIBABIVER := 9
 
 SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
new file mode 100644
index 000000000..32c736d32
--- /dev/null
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "eth_private.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+	struct rte_device *device;
+	struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+	(&(const struct eth_dev_match_arg) { \
+		.device = (d), \
+		.kvlist = (k), \
+	})
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+	      const void *_arg)
+{
+	const struct eth_dev_match_arg *arg = _arg;
+	const struct rte_kvargs *kvlist = arg->kvlist;
+
+	if (edev->state == RTE_ETH_DEV_UNUSED)
+		return -1;
+	if (edev->device != arg->device)
+		return -1;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	edev = eth_find_device(start, eth_dev_match,
+			       eth_dev_match_arg(it->device, kvargs));
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 20/21] ethdev: add device matching field name
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (18 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 19/21] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command Gaetan Rivet
  2018-06-27 10:55   ` [dpdk-dev] [PATCH v8 00/21] Device querying Bruce Richardson
  21 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
index 32c736d32..d8d8e8845 100644
--- a/lib/librte_ethdev/rte_class_eth.c
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -15,10 +15,12 @@
 #include "eth_private.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -39,6 +41,7 @@ eth_dev_match(const struct rte_eth_dev *edev,
 {
 	const struct eth_dev_match_arg *arg = _arg;
 	const struct rte_kvargs *kvlist = arg->kvlist;
+	struct rte_eth_dev_data *data;
 
 	if (edev->state == RTE_ETH_DEV_UNUSED)
 		return -1;
@@ -47,6 +50,10 @@ eth_dev_match(const struct rte_eth_dev *edev,
 	if (kvlist == NULL)
 		/* Empty string matches everything. */
 		return 0;
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (19 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 20/21] ethdev: add device matching field name Gaetan Rivet
@ 2018-06-26 16:56   ` Gaetan Rivet
  2018-06-28 10:03     ` Iremonger, Bernard
  2018-06-27 10:55   ` [dpdk-dev] [PATCH v8 00/21] Device querying Bruce Richardson
  21 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-06-26 16:56 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c                      | 51 +++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 27e2aa8c8..872492b88 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -7083,6 +7083,56 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device <device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -17262,6 +17312,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 0d6fd50ca..4f1009a3a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on the port::
 
    testpmd> set port tm hierarchy default (port_id)
 
+Device functions
+----------------
+
+Show devices
+~~~~~~~~~~~~
+
+Display any registered devices::
+
+   testpmd> show device <device_string>
+
+where:
+
+* ``device_string``: Device description string, of the format
+
+  layer[/layer[/layer]]
+
+  where one layer is in the form
+
+  layer_key=layer_name[,key1=value1[,...]]
+
+  Valid layer keys are ``bus`` and ``class``.
+  Their respective values is defined by registered ``bus`` and ``class``
+  drivers.
+
 Filter Functions
 ----------------
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v8 00/21] Device querying
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
                     ` (20 preceding siblings ...)
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command Gaetan Rivet
@ 2018-06-27 10:55   ` Bruce Richardson
  2018-06-27 11:29     ` Gaëtan Rivet
  21 siblings, 1 reply; 364+ messages in thread
From: Bruce Richardson @ 2018-06-27 10:55 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

On Tue, Jun 26, 2018 at 06:56:03PM +0200, Gaetan Rivet wrote:
> This patchset introduces a new EAL API for querying devices,
> filtered by arbitrary properties.
> 
> The following elements are introduced to this end:
> 
>  * A new object, "rte_class", is used to describe
>    the device class abstraction layer (eth, crypto, ...).
> 
>  * Both rte_bus and rte_class now offer a way to
>    list their devices and filter the result
>    using locally defined properties.
> 
>  * The rte_dev API now has an rte_dev_iterator, which
>    is the way for the user to define the device filter
>    and iterate upon the resulting set.
> 
> As an example, the "eth" device class is implemented.
> 
> Additionally, the device filters for
> 
>   + rte_bus_pci
>   + rte_bus_vdev
>   + rte_class_eth
> 
> are implemented and can be used with some
> properties each, to show how to extend those.
> 
> Some example of filters:
> 
>   "bus=pci/class=eth"
>   "bus=pci"
>   "class=eth"
>   "class=eth,name=net_ring0"
>   "bus=pci,id=00:00.0"
>   "bus=vdev,driver=net_ring"
> 
> ---
> 
> v2:
> 
>   * Reworked the dev_iterate callback to simplify
>     its implementation.
> 
>     Now dev_iterate implementation do not need to learn
>     about the intricacies of the rte_dev_iterator.
>     The rte_dev_iterator is managed purely by the
>     rte_dev_iterator_next function. Buses and classes then
>     do not have to care about settings things right.
> 
>     Additionally, dev_iterate implementations do not
>     have to sanitize their dev string anymore, they
>     are prepared by the rte_dev layer prior, which also
>     reduces the number of dynamic allocations.
> 
> v3:
> 
>   * Introduced central constructor priority list.
>   * Removed lightweight kvarg parsing utility,
>     using librte_kvargs instead.
>   * Reversed dependencies of librte_kvargs and
>     librte_eal.
>   * Fixed a few bugs.
>   * @Bruce: I have noted the request for meson support.
>     I will install it and attempt it once the bulk of the work is done.
> 
> v4:
> 
>   * Fixed a few bugs, added relevant acks,
>     fixed some typos.
>   * Made each matching functions actually check for a proper
>     list of accepted properties.
>   * rte_kvargs now includes rte_eal directly and keeps rte_log.
>   * added generic string comparison function to rte_kvargs,
>     as some kind of comparison should probably be shared by many layers.
> 
> v5:
> 
>   * Rebased on master
>   * Use strcspn instead of custom function.
>   * Introduce private generic rte_eth_dev iterator.
>     This could be generalized to other iterators
>     (port_next, owner_id-aware, etc).
>   * Attempted to support meson.build.
>     Got lost in the implicit variables declared
>     when inversing dependencies between kvargs and EAL.
>     Removed anything related to meson.
>   * Postponed genericization of work from
>     device query to device declaration.
>     Much bigger than anticipated, will let this
>     part get in first and iterate over it.
> 
> v6:
> 
>   * Rebased on master
>   * Introduce RTE_PRIORITY_LAST, to explicitly set
>     the lowest constructor priority.
>   * Fix copyright notice for eth_privage.* files.
> 
> v7:
> 
>   * Rebased on master
>   * Fix rte_kvargs_strcmp return value.
>   * Fix layer parsing error
>     devstr "bus=pci/onemorelayer" now tells
>     that the additional layer is not recognized.
> 
> v8:
> 
>   * Rebased on master
>   * Cleaned kvargs use: introduced
>     a new parser function, that simplifies
>     using the library for DPDK devargs.
>   * Refactored devargs parsing in a single
>     function within rte_devargs.
>     This function is useful both for rte_dev
>     parsing its iterator, and for rte_devargs
>     parsing --dev parameters (not yet implemented).
>   * A few small bugfixes.
> 

Hi Gaetan,

did you test building with shared library builds? I get build failures for
shared libs after applying this set. It appears you may still have a
circular dependency between EAL and kvargs libs.

/Bruce

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v8 00/21] Device querying
  2018-06-27 10:55   ` [dpdk-dev] [PATCH v8 00/21] Device querying Bruce Richardson
@ 2018-06-27 11:29     ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-06-27 11:29 UTC (permalink / raw)
  To: Bruce Richardson
  Cc: dev, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

On Wed, Jun 27, 2018 at 11:55:02AM +0100, Bruce Richardson wrote:
> On Tue, Jun 26, 2018 at 06:56:03PM +0200, Gaetan Rivet wrote:
> > This patchset introduces a new EAL API for querying devices,
> > filtered by arbitrary properties.
> > 
> > The following elements are introduced to this end:
> > 
> >  * A new object, "rte_class", is used to describe
> >    the device class abstraction layer (eth, crypto, ...).
> > 
> >  * Both rte_bus and rte_class now offer a way to
> >    list their devices and filter the result
> >    using locally defined properties.
> > 
> >  * The rte_dev API now has an rte_dev_iterator, which
> >    is the way for the user to define the device filter
> >    and iterate upon the resulting set.
> > 
> > As an example, the "eth" device class is implemented.
> > 
> > Additionally, the device filters for
> > 
> >   + rte_bus_pci
> >   + rte_bus_vdev
> >   + rte_class_eth
> > 
> > are implemented and can be used with some
> > properties each, to show how to extend those.
> > 
> > Some example of filters:
> > 
> >   "bus=pci/class=eth"
> >   "bus=pci"
> >   "class=eth"
> >   "class=eth,name=net_ring0"
> >   "bus=pci,id=00:00.0"
> >   "bus=vdev,driver=net_ring"
> > 
> > ---
> > 
> > v2:
> > 
> >   * Reworked the dev_iterate callback to simplify
> >     its implementation.
> > 
> >     Now dev_iterate implementation do not need to learn
> >     about the intricacies of the rte_dev_iterator.
> >     The rte_dev_iterator is managed purely by the
> >     rte_dev_iterator_next function. Buses and classes then
> >     do not have to care about settings things right.
> > 
> >     Additionally, dev_iterate implementations do not
> >     have to sanitize their dev string anymore, they
> >     are prepared by the rte_dev layer prior, which also
> >     reduces the number of dynamic allocations.
> > 
> > v3:
> > 
> >   * Introduced central constructor priority list.
> >   * Removed lightweight kvarg parsing utility,
> >     using librte_kvargs instead.
> >   * Reversed dependencies of librte_kvargs and
> >     librte_eal.
> >   * Fixed a few bugs.
> >   * @Bruce: I have noted the request for meson support.
> >     I will install it and attempt it once the bulk of the work is done.
> > 
> > v4:
> > 
> >   * Fixed a few bugs, added relevant acks,
> >     fixed some typos.
> >   * Made each matching functions actually check for a proper
> >     list of accepted properties.
> >   * rte_kvargs now includes rte_eal directly and keeps rte_log.
> >   * added generic string comparison function to rte_kvargs,
> >     as some kind of comparison should probably be shared by many layers.
> > 
> > v5:
> > 
> >   * Rebased on master
> >   * Use strcspn instead of custom function.
> >   * Introduce private generic rte_eth_dev iterator.
> >     This could be generalized to other iterators
> >     (port_next, owner_id-aware, etc).
> >   * Attempted to support meson.build.
> >     Got lost in the implicit variables declared
> >     when inversing dependencies between kvargs and EAL.
> >     Removed anything related to meson.
> >   * Postponed genericization of work from
> >     device query to device declaration.
> >     Much bigger than anticipated, will let this
> >     part get in first and iterate over it.
> > 
> > v6:
> > 
> >   * Rebased on master
> >   * Introduce RTE_PRIORITY_LAST, to explicitly set
> >     the lowest constructor priority.
> >   * Fix copyright notice for eth_privage.* files.
> > 
> > v7:
> > 
> >   * Rebased on master
> >   * Fix rte_kvargs_strcmp return value.
> >   * Fix layer parsing error
> >     devstr "bus=pci/onemorelayer" now tells
> >     that the additional layer is not recognized.
> > 
> > v8:
> > 
> >   * Rebased on master
> >   * Cleaned kvargs use: introduced
> >     a new parser function, that simplifies
> >     using the library for DPDK devargs.
> >   * Refactored devargs parsing in a single
> >     function within rte_devargs.
> >     This function is useful both for rte_dev
> >     parsing its iterator, and for rte_devargs
> >     parsing --dev parameters (not yet implemented).
> >   * A few small bugfixes.
> > 
> 
> Hi Gaetan,
> 
> did you test building with shared library builds? I get build failures for
> shared libs after applying this set. It appears you may still have a
> circular dependency between EAL and kvargs libs.
> 
> /Bruce

Hi Bruce,

Ha, yes, I forgot about that, there is a simple fix, I will update it.
I have other fixes as well, a v9 is on its way.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command
  2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command Gaetan Rivet
@ 2018-06-28 10:03     ` Iremonger, Bernard
  2018-06-28 10:09       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Iremonger, Bernard @ 2018-06-28 10:03 UTC (permalink / raw)
  To: Gaetan Rivet, dev

Hi Gaetan,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> Sent: Tuesday, June 26, 2018 5:56 PM
> To: dev@dpdk.org
> Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> Subject: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device
> command
> 
> A new interactive command is offered:
> 
>    show device <device description>
> 
> This commands lists all rte_device element matching the device description.
> e.g.:
> 
>    show device bus=pci
>    show device bus=vdev
>    show device bus=vdev/class=eth
>    show device bus=vdev,driver=net_ring/class=eth
>    show device bus=vdev/class=eth,name=net_ring0
> 
> These devices may not be otherwise useful, some buses will spawn devices
> to keep track of their assets without having a driver to use them.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  app/test-pmd/cmdline.c                      | 51
> +++++++++++++++++++++++++++++
>  doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
>  2 files changed, 75 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> 27e2aa8c8..872492b88 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -7083,6 +7083,56 @@ cmdline_parse_inst_t cmd_showportall = {
>  	},
>  };
> 
> +/* *** SHOW DEVICE INFO *** */
> +struct cmd_showdevice_result {
> +	cmdline_fixed_string_t show;
> +	cmdline_fixed_string_t device;
> +	cmdline_fixed_string_t filter;
> +};
> +
> +static void
> +cmd_showdevice_dump_device(const struct rte_device *dev) {
> +	const struct rte_driver *drv = dev->driver;
> +
> +	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
> +		drv ? drv->name : "<nil>");
> +}
> +
> +static void cmd_showdevice_parsed(void *parsed_result,
> +				__attribute__((unused)) struct cmdline *cl,
> +				__attribute__((unused)) void *data) {
> +	struct cmd_showdevice_result *res = parsed_result;
> +	struct rte_dev_iterator it;
> +	const struct rte_device *dev;
> +
> +	RTE_DEV_FOREACH(dev, res->filter, &it)
> +		cmd_showdevice_dump_device(dev);
> +}
> +
> +cmdline_parse_token_string_t cmd_showdevice_show =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +				show, "show");
> +cmdline_parse_token_string_t cmd_showdevice_device =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +				device, "device");
> +cmdline_parse_token_string_t cmd_showdevice_filter =
> +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> +			filter, NULL);
> +
> +cmdline_parse_inst_t cmd_showdevice = {
> +	.f = cmd_showdevice_parsed,
> +	.data = NULL,
> +	.help_str = "show device <device string>",
> +	.tokens = {
> +		(void *)&cmd_showdevice_show,
> +		(void *)&cmd_showdevice_device,
> +		(void *)&cmd_showdevice_filter,
> +		NULL,
> +	},
> +};
> +
>  /* *** SHOW PORT INFO *** */
>  struct cmd_showport_result {
>  	cmdline_fixed_string_t show;
> @@ -17262,6 +17312,7 @@ cmdline_parse_ctx_t main_ctx[] = {
>  	(cmdline_parse_inst_t *)&cmd_help_long,
>  	(cmdline_parse_inst_t *)&cmd_quit,
>  	(cmdline_parse_inst_t *)&cmd_load_from_file,
> +	(cmdline_parse_inst_t *)&cmd_showdevice,
>  	(cmdline_parse_inst_t *)&cmd_showport,
>  	(cmdline_parse_inst_t *)&cmd_showqueue,
>  	(cmdline_parse_inst_t *)&cmd_showportall, diff --git
> a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> index 0d6fd50ca..4f1009a3a 100644
> --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> @@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on
> the port::
> 
>     testpmd> set port tm hierarchy default (port_id)
> 
> +Device functions
> +----------------
> +
> +Show devices
> +~~~~~~~~~~~~
> +
> +Display any registered devices::
> +
> +   testpmd> show device <device_string>
> +
> +where:
> +
> +* ``device_string``: Device description string, of the format
> +
> +  layer[/layer[/layer]]
> +
> +  where one layer is in the form
> +
> +  layer_key=layer_name[,key1=value1[,...]]
> +
> +  Valid layer keys are ``bus`` and ``class``.
> +  Their respective values is defined by registered ``bus`` and
> + ``class``  drivers.
> +
>  Filter Functions
>  ----------------
> 
> --
> 2.11.0

This patch fails to compile on the latest 18_08 master branch.

There is no update to the internal testpmd documentation about this new command.

Regards,

Bernard.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command
  2018-06-28 10:03     ` Iremonger, Bernard
@ 2018-06-28 10:09       ` Gaëtan Rivet
  2018-06-28 11:28         ` Iremonger, Bernard
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-06-28 10:09 UTC (permalink / raw)
  To: Iremonger, Bernard; +Cc: dev

Hi Bernard,

On Thu, Jun 28, 2018 at 10:03:30AM +0000, Iremonger, Bernard wrote:
> Hi Gaetan,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> > Sent: Tuesday, June 26, 2018 5:56 PM
> > To: dev@dpdk.org
> > Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> > Subject: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device
> > command
> > 
> > A new interactive command is offered:
> > 
> >    show device <device description>
> > 
> > This commands lists all rte_device element matching the device description.
> > e.g.:
> > 
> >    show device bus=pci
> >    show device bus=vdev
> >    show device bus=vdev/class=eth
> >    show device bus=vdev,driver=net_ring/class=eth
> >    show device bus=vdev/class=eth,name=net_ring0
> > 
> > These devices may not be otherwise useful, some buses will spawn devices
> > to keep track of their assets without having a driver to use them.
> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >  app/test-pmd/cmdline.c                      | 51
> > +++++++++++++++++++++++++++++
> >  doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
> >  2 files changed, 75 insertions(+)
> > 
> > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> > 27e2aa8c8..872492b88 100644
> > --- a/app/test-pmd/cmdline.c
> > +++ b/app/test-pmd/cmdline.c
> > @@ -7083,6 +7083,56 @@ cmdline_parse_inst_t cmd_showportall = {
> >  	},
> >  };
> > 
> > +/* *** SHOW DEVICE INFO *** */
> > +struct cmd_showdevice_result {
> > +	cmdline_fixed_string_t show;
> > +	cmdline_fixed_string_t device;
> > +	cmdline_fixed_string_t filter;
> > +};
> > +
> > +static void
> > +cmd_showdevice_dump_device(const struct rte_device *dev) {
> > +	const struct rte_driver *drv = dev->driver;
> > +
> > +	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
> > +		drv ? drv->name : "<nil>");
> > +}
> > +
> > +static void cmd_showdevice_parsed(void *parsed_result,
> > +				__attribute__((unused)) struct cmdline *cl,
> > +				__attribute__((unused)) void *data) {
> > +	struct cmd_showdevice_result *res = parsed_result;
> > +	struct rte_dev_iterator it;
> > +	const struct rte_device *dev;
> > +
> > +	RTE_DEV_FOREACH(dev, res->filter, &it)
> > +		cmd_showdevice_dump_device(dev);
> > +}
> > +
> > +cmdline_parse_token_string_t cmd_showdevice_show =
> > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > +				show, "show");
> > +cmdline_parse_token_string_t cmd_showdevice_device =
> > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > +				device, "device");
> > +cmdline_parse_token_string_t cmd_showdevice_filter =
> > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > +			filter, NULL);
> > +
> > +cmdline_parse_inst_t cmd_showdevice = {
> > +	.f = cmd_showdevice_parsed,
> > +	.data = NULL,
> > +	.help_str = "show device <device string>",
> > +	.tokens = {
> > +		(void *)&cmd_showdevice_show,
> > +		(void *)&cmd_showdevice_device,
> > +		(void *)&cmd_showdevice_filter,
> > +		NULL,
> > +	},
> > +};
> > +
> >  /* *** SHOW PORT INFO *** */
> >  struct cmd_showport_result {
> >  	cmdline_fixed_string_t show;
> > @@ -17262,6 +17312,7 @@ cmdline_parse_ctx_t main_ctx[] = {
> >  	(cmdline_parse_inst_t *)&cmd_help_long,
> >  	(cmdline_parse_inst_t *)&cmd_quit,
> >  	(cmdline_parse_inst_t *)&cmd_load_from_file,
> > +	(cmdline_parse_inst_t *)&cmd_showdevice,
> >  	(cmdline_parse_inst_t *)&cmd_showport,
> >  	(cmdline_parse_inst_t *)&cmd_showqueue,
> >  	(cmdline_parse_inst_t *)&cmd_showportall, diff --git
> > a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > index 0d6fd50ca..4f1009a3a 100644
> > --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > @@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on
> > the port::
> > 
> >     testpmd> set port tm hierarchy default (port_id)
> > 
> > +Device functions
> > +----------------
> > +
> > +Show devices
> > +~~~~~~~~~~~~
> > +
> > +Display any registered devices::
> > +
> > +   testpmd> show device <device_string>
> > +
> > +where:
> > +
> > +* ``device_string``: Device description string, of the format
> > +
> > +  layer[/layer[/layer]]
> > +
> > +  where one layer is in the form
> > +
> > +  layer_key=layer_name[,key1=value1[,...]]
> > +
> > +  Valid layer keys are ``bus`` and ``class``.
> > +  Their respective values is defined by registered ``bus`` and
> > + ``class``  drivers.
> > +
> >  Filter Functions
> >  ----------------
> > 
> > --
> > 2.11.0
> 
> This patch fails to compile on the latest 18_08 master branch.
> 

I had it rebased a few days ago, it was fine. It seems there has been
some movement lately, will rebase again.

> There is no update to the internal testpmd documentation about this new command.
> 

There is some documentation added to
doc/guides/testpmd_app_ug/testpmd_funcs.rst

Are you referring to some other kind of documentation?

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command
  2018-06-28 10:09       ` Gaëtan Rivet
@ 2018-06-28 11:28         ` Iremonger, Bernard
  2018-06-28 11:56           ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Iremonger, Bernard @ 2018-06-28 11:28 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev


Hi Gaetan,

> -----Original Message-----
> From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com]
> Sent: Thursday, June 28, 2018 11:10 AM
> To: Iremonger, Bernard <bernard.iremonger@intel.com>
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device
> command
> 
> Hi Bernard,
> 
> On Thu, Jun 28, 2018 at 10:03:30AM +0000, Iremonger, Bernard wrote:
> > Hi Gaetan,
> >
> > > -----Original Message-----
> > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> > > Sent: Tuesday, June 26, 2018 5:56 PM
> > > To: dev@dpdk.org
> > > Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > Subject: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device
> > > command
> > >
> > > A new interactive command is offered:
> > >
> > >    show device <device description>
> > >
> > > This commands lists all rte_device element matching the device
> description.
> > > e.g.:
> > >
> > >    show device bus=pci
> > >    show device bus=vdev
> > >    show device bus=vdev/class=eth
> > >    show device bus=vdev,driver=net_ring/class=eth
> > >    show device bus=vdev/class=eth,name=net_ring0
> > >
> > > These devices may not be otherwise useful, some buses will spawn
> > > devices to keep track of their assets without having a driver to use them.
> > >
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > ---
> > >  app/test-pmd/cmdline.c                      | 51
> > > +++++++++++++++++++++++++++++
> > >  doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
> > >  2 files changed, 75 insertions(+)
> > >
> > > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> > > 27e2aa8c8..872492b88 100644
> > > --- a/app/test-pmd/cmdline.c
> > > +++ b/app/test-pmd/cmdline.c
> > > @@ -7083,6 +7083,56 @@ cmdline_parse_inst_t cmd_showportall = {
> > >  	},
> > >  };
> > >
> > > +/* *** SHOW DEVICE INFO *** */
> > > +struct cmd_showdevice_result {
> > > +	cmdline_fixed_string_t show;
> > > +	cmdline_fixed_string_t device;
> > > +	cmdline_fixed_string_t filter;
> > > +};
> > > +
> > > +static void
> > > +cmd_showdevice_dump_device(const struct rte_device *dev) {
> > > +	const struct rte_driver *drv = dev->driver;
> > > +
> > > +	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
> > > +		drv ? drv->name : "<nil>");
> > > +}
> > > +
> > > +static void cmd_showdevice_parsed(void *parsed_result,
> > > +				__attribute__((unused)) struct cmdline *cl,
> > > +				__attribute__((unused)) void *data) {
> > > +	struct cmd_showdevice_result *res = parsed_result;
> > > +	struct rte_dev_iterator it;
> > > +	const struct rte_device *dev;
> > > +
> > > +	RTE_DEV_FOREACH(dev, res->filter, &it)
> > > +		cmd_showdevice_dump_device(dev);
> > > +}
> > > +
> > > +cmdline_parse_token_string_t cmd_showdevice_show =
> > > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > > +				show, "show");
> > > +cmdline_parse_token_string_t cmd_showdevice_device =
> > > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > > +				device, "device");
> > > +cmdline_parse_token_string_t cmd_showdevice_filter =
> > > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > > +			filter, NULL);
> > > +
> > > +cmdline_parse_inst_t cmd_showdevice = {
> > > +	.f = cmd_showdevice_parsed,
> > > +	.data = NULL,
> > > +	.help_str = "show device <device string>",
> > > +	.tokens = {
> > > +		(void *)&cmd_showdevice_show,
> > > +		(void *)&cmd_showdevice_device,
> > > +		(void *)&cmd_showdevice_filter,
> > > +		NULL,
> > > +	},
> > > +};
> > > +
> > >  /* *** SHOW PORT INFO *** */
> > >  struct cmd_showport_result {
> > >  	cmdline_fixed_string_t show;
> > > @@ -17262,6 +17312,7 @@ cmdline_parse_ctx_t main_ctx[] = {
> > >  	(cmdline_parse_inst_t *)&cmd_help_long,
> > >  	(cmdline_parse_inst_t *)&cmd_quit,
> > >  	(cmdline_parse_inst_t *)&cmd_load_from_file,
> > > +	(cmdline_parse_inst_t *)&cmd_showdevice,
> > >  	(cmdline_parse_inst_t *)&cmd_showport,
> > >  	(cmdline_parse_inst_t *)&cmd_showqueue,
> > >  	(cmdline_parse_inst_t *)&cmd_showportall, diff --git
> > > a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > index 0d6fd50ca..4f1009a3a 100644
> > > --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > @@ -2628,6 +2628,30 @@ set the traffic management default hierarchy
> > > on the port::
> > >
> > >     testpmd> set port tm hierarchy default (port_id)
> > >
> > > +Device functions
> > > +----------------
> > > +
> > > +Show devices
> > > +~~~~~~~~~~~~
> > > +
> > > +Display any registered devices::
> > > +
> > > +   testpmd> show device <device_string>
> > > +
> > > +where:
> > > +
> > > +* ``device_string``: Device description string, of the format
> > > +
> > > +  layer[/layer[/layer]]
> > > +
> > > +  where one layer is in the form
> > > +
> > > +  layer_key=layer_name[,key1=value1[,...]]
> > > +
> > > +  Valid layer keys are ``bus`` and ``class``.
> > > +  Their respective values is defined by registered ``bus`` and
> > > + ``class``  drivers.
> > > +
> > >  Filter Functions
> > >  ----------------
> > >
> > > --
> > > 2.11.0
> >
> > This patch fails to compile on the latest 18_08 master branch.
> >
> 
> I had it rebased a few days ago, it was fine. It seems there has been some
> movement lately, will rebase again.
> 
> > There is no update to the internal testpmd documentation about this new
> command.
> >
> 
> There is some documentation added to
> doc/guides/testpmd_app_ug/testpmd_funcs.rst
> 
> Are you referring to some other kind of documentation?
> 
> --
> Gaëtan Rivet
> 6WIND

There should be an update to the testpmd "help" command.
See line 122  to 1133 in cmdline .c

Regards,

Bernard

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command
  2018-06-28 11:28         ` Iremonger, Bernard
@ 2018-06-28 11:56           ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-06-28 11:56 UTC (permalink / raw)
  To: Iremonger, Bernard; +Cc: dev

On Thu, Jun 28, 2018 at 11:28:53AM +0000, Iremonger, Bernard wrote:
> 
> Hi Gaetan,
> 
> > -----Original Message-----
> > From: Gaëtan Rivet [mailto:gaetan.rivet@6wind.com]
> > Sent: Thursday, June 28, 2018 11:10 AM
> > To: Iremonger, Bernard <bernard.iremonger@intel.com>
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device
> > command
> > 
> > Hi Bernard,
> > 
> > On Thu, Jun 28, 2018 at 10:03:30AM +0000, Iremonger, Bernard wrote:
> > > Hi Gaetan,
> > >
> > > > -----Original Message-----
> > > > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> > > > Sent: Tuesday, June 26, 2018 5:56 PM
> > > > To: dev@dpdk.org
> > > > Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > Subject: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device
> > > > command
> > > >
> > > > A new interactive command is offered:
> > > >
> > > >    show device <device description>
> > > >
> > > > This commands lists all rte_device element matching the device
> > description.
> > > > e.g.:
> > > >
> > > >    show device bus=pci
> > > >    show device bus=vdev
> > > >    show device bus=vdev/class=eth
> > > >    show device bus=vdev,driver=net_ring/class=eth
> > > >    show device bus=vdev/class=eth,name=net_ring0
> > > >
> > > > These devices may not be otherwise useful, some buses will spawn
> > > > devices to keep track of their assets without having a driver to use them.
> > > >
> > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > ---
> > > >  app/test-pmd/cmdline.c                      | 51
> > > > +++++++++++++++++++++++++++++
> > > >  doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
> > > >  2 files changed, 75 insertions(+)
> > > >
> > > > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> > > > 27e2aa8c8..872492b88 100644
> > > > --- a/app/test-pmd/cmdline.c
> > > > +++ b/app/test-pmd/cmdline.c
> > > > @@ -7083,6 +7083,56 @@ cmdline_parse_inst_t cmd_showportall = {
> > > >  	},
> > > >  };
> > > >
> > > > +/* *** SHOW DEVICE INFO *** */
> > > > +struct cmd_showdevice_result {
> > > > +	cmdline_fixed_string_t show;
> > > > +	cmdline_fixed_string_t device;
> > > > +	cmdline_fixed_string_t filter;
> > > > +};
> > > > +
> > > > +static void
> > > > +cmd_showdevice_dump_device(const struct rte_device *dev) {
> > > > +	const struct rte_driver *drv = dev->driver;
> > > > +
> > > > +	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
> > > > +		drv ? drv->name : "<nil>");
> > > > +}
> > > > +
> > > > +static void cmd_showdevice_parsed(void *parsed_result,
> > > > +				__attribute__((unused)) struct cmdline *cl,
> > > > +				__attribute__((unused)) void *data) {
> > > > +	struct cmd_showdevice_result *res = parsed_result;
> > > > +	struct rte_dev_iterator it;
> > > > +	const struct rte_device *dev;
> > > > +
> > > > +	RTE_DEV_FOREACH(dev, res->filter, &it)
> > > > +		cmd_showdevice_dump_device(dev);
> > > > +}
> > > > +
> > > > +cmdline_parse_token_string_t cmd_showdevice_show =
> > > > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > > > +				show, "show");
> > > > +cmdline_parse_token_string_t cmd_showdevice_device =
> > > > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > > > +				device, "device");
> > > > +cmdline_parse_token_string_t cmd_showdevice_filter =
> > > > +	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
> > > > +			filter, NULL);
> > > > +
> > > > +cmdline_parse_inst_t cmd_showdevice = {
> > > > +	.f = cmd_showdevice_parsed,
> > > > +	.data = NULL,
> > > > +	.help_str = "show device <device string>",
> > > > +	.tokens = {
> > > > +		(void *)&cmd_showdevice_show,
> > > > +		(void *)&cmd_showdevice_device,
> > > > +		(void *)&cmd_showdevice_filter,
> > > > +		NULL,
> > > > +	},
> > > > +};
> > > > +
> > > >  /* *** SHOW PORT INFO *** */
> > > >  struct cmd_showport_result {
> > > >  	cmdline_fixed_string_t show;
> > > > @@ -17262,6 +17312,7 @@ cmdline_parse_ctx_t main_ctx[] = {
> > > >  	(cmdline_parse_inst_t *)&cmd_help_long,
> > > >  	(cmdline_parse_inst_t *)&cmd_quit,
> > > >  	(cmdline_parse_inst_t *)&cmd_load_from_file,
> > > > +	(cmdline_parse_inst_t *)&cmd_showdevice,
> > > >  	(cmdline_parse_inst_t *)&cmd_showport,
> > > >  	(cmdline_parse_inst_t *)&cmd_showqueue,
> > > >  	(cmdline_parse_inst_t *)&cmd_showportall, diff --git
> > > > a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > > b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > > index 0d6fd50ca..4f1009a3a 100644
> > > > --- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > > +++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > > > @@ -2628,6 +2628,30 @@ set the traffic management default hierarchy
> > > > on the port::
> > > >
> > > >     testpmd> set port tm hierarchy default (port_id)
> > > >
> > > > +Device functions
> > > > +----------------
> > > > +
> > > > +Show devices
> > > > +~~~~~~~~~~~~
> > > > +
> > > > +Display any registered devices::
> > > > +
> > > > +   testpmd> show device <device_string>
> > > > +
> > > > +where:
> > > > +
> > > > +* ``device_string``: Device description string, of the format
> > > > +
> > > > +  layer[/layer[/layer]]
> > > > +
> > > > +  where one layer is in the form
> > > > +
> > > > +  layer_key=layer_name[,key1=value1[,...]]
> > > > +
> > > > +  Valid layer keys are ``bus`` and ``class``.
> > > > +  Their respective values is defined by registered ``bus`` and
> > > > + ``class``  drivers.
> > > > +
> > > >  Filter Functions
> > > >  ----------------
> > > >
> > > > --
> > > > 2.11.0
> > >
> > > This patch fails to compile on the latest 18_08 master branch.
> > >
> > 
> > I had it rebased a few days ago, it was fine. It seems there has been some
> > movement lately, will rebase again.
> > 
> > > There is no update to the internal testpmd documentation about this new
> > command.
> > >
> > 
> > There is some documentation added to
> > doc/guides/testpmd_app_ug/testpmd_funcs.rst
> > 
> > Are you referring to some other kind of documentation?
> > 
> > --
> > Gaëtan Rivet
> > 6WIND
> 
> There should be an update to the testpmd "help" command.
> See line 122  to 1133 in cmdline .c
> 
> Regards,
> 
> Bernard
> 

Ah, ok, I will update it.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 00/27] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (22 preceding siblings ...)
  2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
@ 2018-07-03 22:14 ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 01/27] devargs: add non-variadic parsing function Gaetan Rivet
                     ` (26 more replies)
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
  25 siblings, 27 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet, Neil Horman, Keith Wiles, Matan Azrad, Shreyansh Jain

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.

v5:

  * Rebased on master
  * Use strcspn instead of custom function.
  * Introduce private generic rte_eth_dev iterator.
    This could be generalized to other iterators
    (port_next, owner_id-aware, etc).
  * Attempted to support meson.build.
    Got lost in the implicit variables declared
    when inversing dependencies between kvargs and EAL.
    Removed anything related to meson.
  * Postponed genericization of work from
    device query to device declaration.
    Much bigger than anticipated, will let this
    part get in first and iterate over it.

v6:

  * Rebased on master
  * Introduce RTE_PRIORITY_LAST, to explicitly set
    the lowest constructor priority.
  * Fix copyright notice for eth_privage.* files.

v7:

  * Rebased on master
  * Fix rte_kvargs_strcmp return value.
  * Fix layer parsing error
    devstr "bus=pci/onemorelayer" now tells
    that the additional layer is not recognized.

v8:

  * Rebased on master
  * Cleaned kvargs use: introduced
    a new parser function, that simplifies
    using the library for DPDK devargs.
  * Refactored devargs parsing in a single
    function within rte_devargs.
    This function is useful both for rte_dev
    parsing its iterator, and for rte_devargs
    parsing --dev parameters (not yet implemented).
  * A few small bugfixes.

v9:

  * Rebased on master
  * Fixed cyclic dependency kvargs <-> eal
  * Fixed a few checkpatch issues
  * Added dynamic help to testpmd for new "show device" command
  * Added devargs processing stubs to
    primary buses / classes
  * Added new --dev generic device declaration option

Gaetan Rivet (27):
  devargs: add non-variadic parsing function
  kvargs: remove error logs
  kvargs: build before EAL
  kvargs: introduce a more flexible parsing function
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  devargs: add function to parse device layers
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: add private generic device iterator
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command
  bus/pci: pre-process declarative PCI devargs
  bus/vdev: pre-process declarative vdev devargs
  bus/pci: process declarative PCI devargs
  ethdev: process declarative eth devargs
  eal: add generic dev parameter

 app/test-pmd/cmdline.c                      |  54 +++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  24 +++
 drivers/bus/pci/Makefile                    |   3 +-
 drivers/bus/pci/bsd/pci.c                   |   5 +
 drivers/bus/pci/linux/pci.c                 |   5 +
 drivers/bus/pci/pci_common.c                |   4 +
 drivers/bus/pci/pci_params.c                | 143 ++++++++++++++++++
 drivers/bus/pci/private.h                   |  54 +++++++
 drivers/bus/vdev/Makefile                   |   3 +-
 drivers/bus/vdev/vdev.c                     |  20 ++-
 drivers/bus/vdev/vdev_params.c              | 112 ++++++++++++++
 drivers/bus/vdev/vdev_private.h             |  32 ++++
 drivers/net/failsafe/failsafe_args.c        |   2 +-
 drivers/net/failsafe/failsafe_eal.c         |   2 +-
 lib/Makefile                                |   5 +-
 lib/librte_eal/bsdapp/eal/Makefile          |   2 +
 lib/librte_eal/common/Makefile              |   2 +-
 lib/librte_eal/common/eal_common_class.c    |  62 ++++++++
 lib/librte_eal/common/eal_common_dev.c      | 227 +++++++++++++++++++++++++++-
 lib/librte_eal/common/eal_common_devargs.c  | 190 +++++++++++++++++++++--
 lib/librte_eal/common/eal_common_options.c  |  36 ++++-
 lib/librte_eal/common/eal_options.h         |   2 +
 lib/librte_eal/common/eal_private.h         |  27 ++++
 lib/librte_eal/common/include/rte_bus.h     |   1 +
 lib/librte_eal/common/include/rte_class.h   | 127 ++++++++++++++++
 lib/librte_eal/common/include/rte_common.h  |  24 +++
 lib/librte_eal/common/include/rte_dev.h     |  97 ++++++++++++
 lib/librte_eal/common/include/rte_devargs.h |  53 ++++++-
 lib/librte_eal/linuxapp/eal/Makefile        |   2 +
 lib/librte_eal/rte_eal_version.map          |   5 +
 lib/librte_ethdev/Makefile                  |   4 +-
 lib/librte_ethdev/eth_private.c             |  31 ++++
 lib/librte_ethdev/eth_private.h             |  31 ++++
 lib/librte_ethdev/rte_class_eth.c           | 147 ++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.c              |   9 +-
 lib/librte_kvargs/Makefile                  |   2 +-
 lib/librte_kvargs/rte_kvargs.c              |  57 ++++---
 lib/librte_kvargs/rte_kvargs.h              |  58 +++++++
 lib/librte_kvargs/rte_kvargs_version.map    |   8 +
 39 files changed, 1615 insertions(+), 57 deletions(-)
 create mode 100644 drivers/bus/pci/pci_params.c
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 01/27] devargs: add non-variadic parsing function
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 02/27] kvargs: remove error logs Gaetan Rivet
                     ` (25 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose
device strings.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/net/failsafe/failsafe_args.c        |  2 +-
 drivers/net/failsafe/failsafe_eal.c         |  2 +-
 lib/librte_eal/common/eal_common_dev.c      |  4 +--
 lib/librte_eal/common/eal_common_devargs.c  | 42 ++++++++++++++++++++++-------
 lib/librte_eal/common/include/rte_devargs.h | 40 +++++++++++++++++++++++++--
 lib/librte_eal/rte_eal_version.map          |  1 +
 lib/librte_ethdev/rte_ethdev.c              |  2 +-
 7 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/drivers/net/failsafe/failsafe_args.c b/drivers/net/failsafe/failsafe_args.c
index 2c002b164..626883ce2 100644
--- a/drivers/net/failsafe/failsafe_args.c
+++ b/drivers/net/failsafe/failsafe_args.c
@@ -63,7 +63,7 @@ fs_parse_device(struct sub_device *sdev, char *args)
 
 	d = &sdev->devargs;
 	DEBUG("%s", args);
-	ret = rte_devargs_parse(d, "%s", args);
+	ret = rte_devargs_parse(d, args);
 	if (ret) {
 		DEBUG("devargs parsing failed with code %d", ret);
 		return ret;
diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c
index 5672f3961..ce1633f13 100644
--- a/drivers/net/failsafe/failsafe_eal.c
+++ b/drivers/net/failsafe/failsafe_eal.c
@@ -86,7 +86,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			else
 				snprintf(devstr, sizeof(devstr), "%s",
 					 rte_eth_devices[pid].device->name);
-			ret = rte_devargs_parse(da, "%s", devstr);
+			ret = rte_devargs_parse(da, devstr);
 			if (ret) {
 				ERROR("Probed devargs parsing failed with code"
 				      " %d", ret);
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 61cb3b162..ce4b51469 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -138,8 +138,8 @@ int __rte_experimental rte_eal_hotplug_add(const char *busname, const char *devn
 	if (da == NULL)
 		return -ENOMEM;
 
-	ret = rte_devargs_parse(da, "%s:%s,%s",
-				    busname, devname, devargs);
+	ret = rte_devargs_parsef(da, "%s:%s,%s",
+				 busname, devname, devargs);
 	if (ret)
 		goto err_devarg;
 
diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index b0434158b..0a83beb94 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -62,24 +62,18 @@ bus_name_cmp(const struct rte_bus *bus, const void *name)
 	return strncmp(bus->name, name, strlen(bus->name));
 }
 
-int __rte_experimental
-rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev)
 {
 	struct rte_bus *bus = NULL;
-	va_list ap;
-	va_start(ap, format);
-	char dev[vsnprintf(NULL, 0, format, ap) + 1];
 	const char *devname;
 	const size_t maxlen = sizeof(da->name);
 	size_t i;
 
-	va_end(ap);
 	if (da == NULL)
 		return -EINVAL;
 
-	va_start(ap, format);
-	vsnprintf(dev, sizeof(dev), format, ap);
-	va_end(ap);
 	/* Retrieve eventual bus info */
 	do {
 		devname = dev;
@@ -124,6 +118,34 @@ rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
 	return 0;
 }
 
+__rte_experimental
+int
+rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
+{
+	va_list ap;
+	size_t len;
+	char *dev;
+
+	if (da == NULL)
+		return -EINVAL;
+
+	va_start(ap, format);
+	len = vsnprintf(NULL, 0, format, ap);
+	va_end(ap);
+
+	dev = calloc(1, len + 1);
+	if (dev == NULL) {
+		fprintf(stderr, "ERROR: not enough memory to parse device\n");
+		return -ENOMEM;
+	}
+
+	va_start(ap, format);
+	vsnprintf(dev, len, format, ap);
+	va_end(ap);
+
+	return rte_devargs_parse(da, dev);
+}
+
 int __rte_experimental
 rte_devargs_insert(struct rte_devargs *da)
 {
@@ -150,7 +172,7 @@ rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	if (devargs == NULL)
 		goto fail;
 
-	if (rte_devargs_parse(devargs, "%s", dev))
+	if (rte_devargs_parse(devargs, dev))
 		goto fail;
 	devargs->type = devtype;
 	bus = devargs->bus;
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 58fbd90a2..6c3b6326b 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -96,6 +96,42 @@ int rte_eal_parse_devargs_str(const char *devargs_str,
  * in argument. Store which bus will handle the device, its name
  * and the eventual device parameters.
  *
+ * The syntax is:
+ *
+ *     bus:device_identifier,arg1=val1,arg2=val2
+ *
+ * where "bus:" is the bus name followed by any character separator.
+ * The bus name is optional. If no bus name is specified, each bus
+ * will attempt to recognize the device identifier. The first one
+ * to succeed will be used.
+ *
+ * Examples:
+ *
+ *     pci:0000:05.00.0,arg=val
+ *     05.00.0,arg=val
+ *     vdev:net_ring0
+ *
+ * @param da
+ *   The devargs structure holding the device information.
+ *
+ * @param dev
+ *   String describing a device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative errno on error.
+ */
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev);
+
+/**
+ * Parse a device string.
+ *
+ * Verify that a bus is capable of handling the device passed
+ * in argument. Store which bus will handle the device, its name
+ * and the eventual device parameters.
+ *
  * The device string is built with a printf-like syntax.
  *
  * The syntax is:
@@ -124,8 +160,8 @@ int rte_eal_parse_devargs_str(const char *devargs_str,
  */
 __rte_experimental
 int
-rte_devargs_parse(struct rte_devargs *da,
-		  const char *format, ...)
+rte_devargs_parsef(struct rte_devargs *da,
+		   const char *format, ...)
 __attribute__((format(printf, 2, 0)));
 
 /**
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index f7dd0e7bc..1c4db72fa 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -254,6 +254,7 @@ EXPERIMENTAL {
 	rte_devargs_insert;
 	rte_devargs_next;
 	rte_devargs_parse;
+	rte_devargs_parsef;
 	rte_devargs_remove;
 	rte_devargs_type_count;
 	rte_eal_cleanup;
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index a9977df97..cce20d9ae 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -654,7 +654,7 @@ rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
 	}
 
 	/* parse devargs */
-	if (rte_devargs_parse(&da, "%s", devargs))
+	if (rte_devargs_parse(&da, devargs))
 		goto err;
 
 	ret = rte_eal_hotplug_add(da.bus->name, da.name, da.args);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 02/27] kvargs: remove error logs
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 01/27] devargs: add non-variadic parsing function Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 03/27] kvargs: build before EAL Gaetan Rivet
                     ` (24 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Error logs in kvargs parsing should be better handled in components
calling the library.

This library must be as lean as possible.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_kvargs/rte_kvargs.c | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..747f14964 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -6,7 +6,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include <rte_log.h>
 #include <rte_string_fns.h>
 
 #include "rte_kvargs.h"
@@ -28,29 +27,22 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
 	 * to pass to rte_strsplit
 	 */
 	kvlist->str = strdup(params);
-	if (kvlist->str == NULL) {
-		RTE_LOG(ERR, PMD, "Cannot parse arguments: not enough memory\n");
+	if (kvlist->str == NULL)
 		return -1;
-	}
 
 	/* browse each key/value pair and add it in kvlist */
 	str = kvlist->str;
 	while ((str = strtok_r(str, RTE_KVARGS_PAIRS_DELIM, &ctx1)) != NULL) {
 
 		i = kvlist->count;
-		if (i >= RTE_KVARGS_MAX) {
-			RTE_LOG(ERR, PMD, "Cannot parse arguments: list full\n");
+		if (i >= RTE_KVARGS_MAX)
 			return -1;
-		}
 
 		kvlist->pairs[i].key = strtok_r(str, RTE_KVARGS_KV_DELIM, &ctx2);
 		kvlist->pairs[i].value = strtok_r(NULL, RTE_KVARGS_KV_DELIM, &ctx2);
-		if (kvlist->pairs[i].key == NULL || kvlist->pairs[i].value == NULL) {
-			RTE_LOG(ERR, PMD,
-				"Cannot parse arguments: wrong key or value\n"
-				"params=<%s>\n", params);
+		if (kvlist->pairs[i].key == NULL ||
+		    kvlist->pairs[i].value == NULL)
 			return -1;
-		}
 
 		kvlist->count++;
 		str = NULL;
@@ -89,12 +81,8 @@ check_for_valid_keys(struct rte_kvargs *kvlist,
 	for (i = 0; i < kvlist->count; i++) {
 		pair = &kvlist->pairs[i];
 		ret = is_valid_key(valid, pair->key);
-		if (!ret) {
-			RTE_LOG(ERR, PMD,
-				"Error parsing device, invalid key <%s>\n",
-				pair->key);
+		if (!ret)
 			return -1;
-		}
 	}
 	return 0;
 }
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 03/27] kvargs: build before EAL
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 01/27] devargs: add non-variadic parsing function Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 02/27] kvargs: remove error logs Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 04/27] kvargs: introduce a more flexible parsing function Gaetan Rivet
                     ` (23 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile               | 3 +--
 lib/librte_kvargs/Makefile | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index d82462ba2..e8e903c8f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -76,8 +77,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ethdev
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 39d5ac33d..875939547 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -7,7 +7,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 04/27] kvargs: introduce a more flexible parsing function
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (2 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 03/27] kvargs: build before EAL Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 05/27] eal: introduce dtor macros Gaetan Rivet
                     ` (22 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function permits defining additional terminating characters,
ending the parsing to arbitrary delimiters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/rte_kvargs.c           | 25 +++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 30 ++++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 +++++++
 4 files changed, 63 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index e8e903c8f..8a65525cd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-y += librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
+DEPDIRS-librte_kvargs := librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 747f14964..519f77679 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -168,3 +168,28 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+struct rte_kvargs *
+rte_kvargs_parse2(const char *args, const char * const valid_keys[],
+		  const char *valid_ends)
+{
+	struct rte_kvargs *kvlist = NULL;
+	char *copy;
+	size_t len;
+
+	if (valid_ends == NULL)
+		return rte_kvargs_parse(args, valid_keys);
+
+	copy = strdup(args);
+	if (copy == NULL)
+		return NULL;
+
+	len = strcspn(copy, valid_ends);
+	copy[len] = '\0';
+
+	kvlist = rte_kvargs_parse(copy, valid_keys);
+
+	free(copy);
+	return kvlist;
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..98c4ed1bf 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -72,6 +72,36 @@ struct rte_kvargs *rte_kvargs_parse(const char *args,
 		const char *const valid_keys[]);
 
 /**
+ * Allocate a rte_kvargs and store key/value associations from a string.
+ * This version will consider any byte from valid_ends as a possible
+ * terminating character, and will not parse beyond any of their occurrence.
+ *
+ * The function allocates and fills an rte_kvargs structure from a given
+ * string whose format is key1=value1,key2=value2,...
+ *
+ * The structure can be freed with rte_kvargs_free().
+ *
+ * @param args
+ *   The input string containing the key/value associations
+ *
+ * @param valid_keys
+ *   A list of valid keys (table of const char *, the last must be NULL).
+ *   This argument is ignored if NULL
+ *
+ * @param valid_ends
+ *   Acceptable terminating characters.
+ *   If NULL, the behavior is the same as ``rte_kvargs_parse``.
+ *
+ * @return
+ *   - A pointer to an allocated rte_kvargs structure on success
+ *   - NULL on error
+ */
+__rte_experimental
+struct rte_kvargs *rte_kvargs_parse2(const char *args,
+		const char *const valid_keys[],
+		const char *valid_ends);
+
+/**
  * Free a rte_kvargs structure
  *
  * Free a rte_kvargs structure previously allocated with
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..b9fe44b98 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_parse2;
+
+} DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 05/27] eal: introduce dtor macros
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (3 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 04/27] kvargs: introduce a more flexible parsing function Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 06/27] eal: introduce device class abstraction Gaetan Rivet
                     ` (21 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 434adfd45..0dd832728 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -112,6 +112,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 	RTE_INIT_PRIO(func, LAST)
 
 /**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+	RTE_FINI_PRIO(func, LAST)
+
+/**
  * Force a function to be inlined
  */
 #define __rte_always_inline inline __attribute__((always_inline))
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 06/27] eal: introduce device class abstraction
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (4 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 05/27] eal: introduce dtor macros Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 07/27] eal/class: register destructor Gaetan Rivet
                     ` (20 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 7 files changed, 189 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index 3fd33f1e4..b0a1c880a 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -52,6 +52,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 48f870f24..750653093 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..b5e550a34
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 0dd832728..a2e8e6e32 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 #define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 3719ec9d7..babc8617a 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -60,6 +60,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 1c4db72fa..19d36b4c7 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -244,6 +244,8 @@ DPDK_18.05 {
 EXPERIMENTAL {
 	global:
 
+	rte_class_register;
+	rte_class_unregister;
 	rte_ctrl_thread_create;
 	rte_dev_event_callback_register;
 	rte_dev_event_callback_unregister;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 07/27] eal/class: register destructor
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (5 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 06/27] eal: introduce device class abstraction Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 08/27] devargs: add function to parse device layers Gaetan Rivet
                     ` (19 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index b5e550a34..e8176f5e1 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 08/27] devargs: add function to parse device layers
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (6 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 07/27] eal/class: register destructor Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 09/27] eal/dev: add device iterator interface Gaetan Rivet
                     ` (18 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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>
---
 lib/librte_eal/common/eal_common_devargs.c  | 144 ++++++++++++++++++++++++++++
 lib/librte_eal/common/eal_private.h         |  27 ++++++
 lib/librte_eal/common/include/rte_devargs.h |  13 ++-
 3 files changed, 181 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 0a83beb94..5f89e0b6e 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -13,9 +13,13 @@
 #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_kvargs.h>
+#include <rte_errno.h>
 #include <rte_tailq.h>
 #include "eal_private.h"
 
@@ -56,6 +60,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 *da,
+			 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 (da->data != devstr) {
+		da->data = strdup(devstr);
+		if (da->data == NULL) {
+			RTE_LOG(ERR, EAL, "OOM\n");
+			ret = -ENOMEM;
+			goto get_out;
+		}
+		s = da->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_parse2(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. */
+	da->busstr = layers[0].str;
+	da->clsstr = layers[1].str;
+	da->drvstr = layers[2].str;
+	da->bus = bus;
+	da->cls = cls;
+
+	/* If we own the data, clean up a bit
+	 * the several layers string, to ease
+	 * their parsing afterward.
+	 */
+	if (da->data != devstr) {
+		char *s = (void *)(intptr_t)(da->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)
 {
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index bdadc4d50..c4c9283c8 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -258,4 +258,31 @@ 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.
+ *
+ * Note: if the "data" field of da 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 *da,
+			 const char *devstr);
+
 #endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 6c3b6326b..148600258 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -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 *drvstr;
+	};
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< bus-related part of device string. */
+	const char *data; /**< Device string storage. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 09/27] eal/dev: add device iterator interface
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (7 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 08/27] devargs: add function to parse device layers Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 10/27] eal/class: add device iteration Gaetan Rivet
                     ` (17 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 3879ff3ca..120df729f 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -285,6 +285,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 10/27] eal/class: add device iteration
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (8 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 09/27] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 11/27] eal/bus: " Gaetan Rivet
                     ` (16 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index e8176f5e1..9d5b06807 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 11/27] eal/bus: add device iteration
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (9 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 10/27] eal/class: add device iteration Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 12/27] eal/dev: implement device iteration initialization Gaetan Rivet
                     ` (15 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 12/27] eal/dev: implement device iteration initialization
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (10 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 11/27] eal/bus: " Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 13/27] eal/dev: implement device iteration Gaetan Rivet
                     ` (14 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@6wind.com>
---
 lib/Makefile                            |  1 +
 lib/librte_eal/bsdapp/eal/Makefile      |  1 +
 lib/librte_eal/common/eal_common_dev.c  | 55 +++++++++++++++++++++++++++++++++
 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, 83 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 8a65525cd..afa604e20 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index b0a1c880a..67b10ae0d 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 ce4b51469..5b7956d17 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 <rte_spinlock.h>
 #include <rte_malloc.h>
@@ -343,3 +346,55 @@ dev_callback_process(char *device_name, enum rte_dev_event_type event)
 	}
 	rte_spinlock_unlock(&dev_event_lock);
 }
+
+__rte_experimental
+int
+rte_dev_iterator_init(struct rte_dev_iterator *it,
+		      const char *devstr)
+{
+	struct rte_devargs da;
+	struct rte_class *cls = NULL;
+	struct rte_bus *bus = NULL;
+
+	/* Having both busstr and clsstr NULL is illegal,
+	 * marking this iterator as invalid unless
+	 * everything goes well.
+	 */
+	it->busstr = NULL;
+	it->clsstr = NULL;
+
+	da.data = devstr;
+	if (rte_devargs_layers_parse(&da, devstr))
+		goto get_out;
+
+	bus = da.bus;
+	cls = da.cls;
+	/* 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;
+	}
+	it->busstr = da.busstr;
+	it->clsstr = da.clsstr;
+	it->devstr = devstr;
+	it->bus = bus;
+	it->cls = cls;
+	it->device = NULL;
+	it->class_device = NULL;
+get_out:
+	return -rte_errno;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 120df729f..7b7bd83bc 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -332,6 +332,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 babc8617a..885c48110 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 19d36b4c7..ac04120d6 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -251,6 +251,7 @@ EXPERIMENTAL {
 	rte_dev_event_callback_unregister;
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
+	rte_dev_iterator_init;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 13/27] eal/dev: implement device iteration
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (11 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 12/27] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 14/27] kvargs: add generic string matching callback Gaetan Rivet
                     ` (13 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  26 +++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 195 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 5b7956d17..3d486a841 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
 /* spinlock for device callbacks */
 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 get_out:
 	return -rte_errno;
 }
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	size_t end;
+	char *copy;
+
+	end = strcspn(str, ",/");
+	if (str[end] == ',') {
+		copy = strdup(&str[end + 1]);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_copy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_copy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 7b7bd83bc..1553c0970 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -356,6 +356,32 @@ __rte_experimental
 int
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index ac04120d6..4cd5ab3df 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -252,6 +252,7 @@ EXPERIMENTAL {
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 14/27] kvargs: add generic string matching callback
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (12 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 13/27] eal/dev: implement device iteration Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 15/27] bus/pci: implement device iteration and comparison Gaetan Rivet
                     ` (12 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_kvargs/rte_kvargs.c           | 10 ++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  1 +
 3 files changed, 39 insertions(+)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 519f77679..8270d2939 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -193,3 +193,13 @@ rte_kvargs_parse2(const char *args, const char * const valid_keys[],
 	free(copy);
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -abs(strcmp(str, value));
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 98c4ed1bf..ac2999ef3 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -151,6 +153,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index b9fe44b98..6a41a6b65 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -13,5 +13,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_kvargs_parse2;
+	rte_kvargs_strcmp;
 
 } DPDK_2.0;
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 15/27] bus/pci: implement device iteration and comparison
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (13 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 14/27] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 16/27] bus/pci: add device matching field id Gaetan Rivet
                     ` (11 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  3 ++-
 drivers/bus/pci/pci_common.c |  1 +
 drivers/bus/pci/pci_params.c | 53 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/bus/pci/private.h    | 25 +++++++++++++++++++++
 4 files changed, 81 insertions(+), 1 deletion(-)
 create mode 100644 drivers/bus/pci/pci_params.c

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index cf373068a..4de953f8f 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -26,10 +26,11 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
+SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_params.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common_uio.c
 
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 94b0f4143..749b6eee3 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -437,6 +437,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = rte_pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
new file mode 100644
index 000000000..0fde75803
--- /dev/null
+++ b/drivers/bus/pci/pci_params.c
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_bus.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_pci.h>
+
+#include "private.h"
+
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it __rte_unused)
+{
+	rte_bus_find_device_t find_device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	find_device = rte_pci_bus.bus.find_device;
+	dev = find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 8ddd03e16..0e689fa74 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -10,6 +10,8 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 
+extern struct rte_pci_bus rte_pci_bus;
+
 struct rte_pci_driver;
 struct rte_pci_device;
 
@@ -166,4 +168,27 @@ rte_pci_match(const struct rte_pci_driver *pci_drv,
 enum rte_iova_mode
 rte_pci_get_iommu_class(void);
 
+/*
+ * Iterate over internal devices,
+ * matching any device against the provided
+ * string.
+ *
+ * @param start
+ *   Iteration starting point.
+ *
+ * @param str
+ *   Device string to match against.
+ *
+ * @param it
+ *   (unused) iterator structure.
+ *
+ * @return
+ *   A pointer to the next matching device if any.
+ *   NULL otherwise.
+ */
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 16/27] bus/pci: add device matching field id
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (14 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 15/27] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-07-03 22:14   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 17/27] bus/vdev: implement device iteration Gaetan Rivet
                     ` (10 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:14 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_params.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 0fde75803..7630d4845 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -3,6 +3,7 @@
  */
 
 #include <rte_bus.h>
+#include <rte_bus_pci.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
@@ -11,21 +12,45 @@
 #include "private.h"
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
 static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return -abs(rte_pci_addr_cmp(addr1, addr2));
+}
+
+static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 17/27] bus/vdev: implement device iteration
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (15 preceding siblings ...)
  2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 16/27] bus/pci: add device matching field id Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 18/27] bus/vdev: add device matching field driver Gaetan Rivet
                     ` (9 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile       |  3 ++-
 drivers/bus/vdev/vdev.c         | 10 ++++----
 drivers/bus/vdev/vdev_params.c  | 51 +++++++++++++++++++++++++++++++++++++++++
 drivers/bus/vdev/vdev_private.h | 26 +++++++++++++++++++++
 4 files changed, 85 insertions(+), 5 deletions(-)
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index bd0bb8955..1f9cd7ebe 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,8 +19,9 @@ EXPORT_MAP := rte_bus_vdev_version.map
 LIBABIVER := 1
 
 SRCS-y += vdev.c
+SRCS-y += vdev_params.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 6139dd551..e8518833d 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -23,6 +23,7 @@
 
 #include "rte_bus_vdev.h"
 #include "vdev_logs.h"
+#include "vdev_private.h"
 
 #define VDEV_MP_KEY	"bus_vdev_mp"
 
@@ -493,9 +494,9 @@ vdev_probe(void)
 	return ret;
 }
 
-static struct rte_device *
-vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
-		 const void *data)
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
+		     const void *data)
 {
 	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
@@ -532,10 +533,11 @@ vdev_unplug(struct rte_device *dev)
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
-	.find_device = vdev_find_device,
+	.find_device = rte_vdev_find_device,
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = rte_vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
new file mode 100644
index 000000000..842a4684e
--- /dev/null
+++ b/drivers/bus/vdev/vdev_params.c
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_dev.h>
+#include <rte_bus.h>
+#include <rte_kvargs.h>
+#include <rte_errno.h>
+
+#include "vdev_logs.h"
+#include "vdev_private.h"
+
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = rte_vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/vdev/vdev_private.h b/drivers/bus/vdev/vdev_private.h
new file mode 100644
index 000000000..ba6dc48ff
--- /dev/null
+++ b/drivers/bus/vdev/vdev_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _VDEV_PRIVATE_H_
+#define _VDEV_PRIVATE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start,
+		     rte_dev_cmp_t cmp,
+		     const void *data);
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VDEV_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 18/27] bus/vdev: add device matching field driver
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (16 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 17/27] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 19/27] ethdev: add private generic device iterator Gaetan Rivet
                     ` (8 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev_params.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
index 842a4684e..2f55f451f 100644
--- a/drivers/bus/vdev/vdev_params.c
+++ b/drivers/bus/vdev/vdev_params.c
@@ -4,6 +4,7 @@
 
 #include <rte_dev.h>
 #include <rte_bus.h>
+#include <rte_bus_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
 
@@ -11,10 +12,12 @@
 #include "vdev_private.h"
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -23,9 +26,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 19/27] ethdev: add private generic device iterator
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (17 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 18/27] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class Gaetan Rivet
                     ` (7 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This iterator can be customized with a comparison function that will
trigger a stopping condition.

It can be leveraged to write several different iterators that have
similar but non-identical purposes.

It is private to librte_ethdev.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile      |  1 +
 lib/librte_ethdev/eth_private.c | 31 +++++++++++++++++++++++++++++++
 lib/librte_ethdev/eth_private.h | 26 ++++++++++++++++++++++++++
 3 files changed, 58 insertions(+)
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index c2f2f7d82..2fa133fbc 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 9
 
+SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
diff --git a/lib/librte_ethdev/eth_private.c b/lib/librte_ethdev/eth_private.c
new file mode 100644
index 000000000..d565568a0
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include "rte_ethdev.h"
+#include "eth_private.h"
+
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
+		const void *data)
+{
+	struct rte_eth_dev *edev;
+	ptrdiff_t idx;
+
+	/* Avoid Undefined Behaviour */
+	if (start != NULL &&
+	    (start < &rte_eth_devices[0] ||
+	     start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+		return NULL;
+	if (start != NULL)
+		idx = start - &rte_eth_devices[0] + 1;
+	else
+		idx = 0;
+	for (; idx < RTE_MAX_ETHPORTS; idx++) {
+		edev = &rte_eth_devices[idx];
+		if (cmp(edev, data) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
diff --git a/lib/librte_ethdev/eth_private.h b/lib/librte_ethdev/eth_private.h
new file mode 100644
index 000000000..0f5c6d5c4
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_ETH_PRIVATE_H_
+#define _RTE_ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
+		const void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (18 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 19/27] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-04 12:20     ` Andrew Rybchenko
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 21/27] ethdev: add device matching field name Gaetan Rivet
                     ` (6 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile        |  3 +-
 lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 81 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index 2fa133fbc..d4c3a8d06 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
@@ -20,6 +20,7 @@ LIBABIVER := 9
 
 SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
new file mode 100644
index 000000000..32c736d32
--- /dev/null
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "eth_private.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+	struct rte_device *device;
+	struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+	(&(const struct eth_dev_match_arg) { \
+		.device = (d), \
+		.kvlist = (k), \
+	})
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+	      const void *_arg)
+{
+	const struct eth_dev_match_arg *arg = _arg;
+	const struct rte_kvargs *kvlist = arg->kvlist;
+
+	if (edev->state == RTE_ETH_DEV_UNUSED)
+		return -1;
+	if (edev->device != arg->device)
+		return -1;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	edev = eth_find_device(start, eth_dev_match,
+			       eth_dev_match_arg(it->device, kvargs));
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 21/27] ethdev: add device matching field name
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (19 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 22/27] app/testpmd: add show device command Gaetan Rivet
                     ` (5 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
index 32c736d32..d8d8e8845 100644
--- a/lib/librte_ethdev/rte_class_eth.c
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -15,10 +15,12 @@
 #include "eth_private.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -39,6 +41,7 @@ eth_dev_match(const struct rte_eth_dev *edev,
 {
 	const struct eth_dev_match_arg *arg = _arg;
 	const struct rte_kvargs *kvlist = arg->kvlist;
+	struct rte_eth_dev_data *data;
 
 	if (edev->state == RTE_ETH_DEV_UNUSED)
 		return -1;
@@ -47,6 +50,10 @@ eth_dev_match(const struct rte_eth_dev *edev,
 	if (kvlist == NULL)
 		/* Empty string matches everything. */
 		return 0;
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 22/27] app/testpmd: add show device command
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (20 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 21/27] ethdev: add device matching field name Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 23/27] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
                     ` (4 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c                      | 54 +++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 +++++++++++++
 2 files changed, 78 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 27e2aa8c8..3b86bfe48 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -228,6 +228,9 @@ static void cmd_help_long_parsed(void *parsed_result,
                         "show port tm node stats (port_id) (node_id) (clear)\n"
                         "       Display the port TM node stats.\n\n"
 
+			"show device (device_string)\n"
+			"       Display devices matching the device string.\n\n"
+
 		);
 	}
 
@@ -7083,6 +7086,56 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device <device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -17262,6 +17315,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 0d6fd50ca..4f1009a3a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on the port::
 
    testpmd> set port tm hierarchy default (port_id)
 
+Device functions
+----------------
+
+Show devices
+~~~~~~~~~~~~
+
+Display any registered devices::
+
+   testpmd> show device <device_string>
+
+where:
+
+* ``device_string``: Device description string, of the format
+
+  layer[/layer[/layer]]
+
+  where one layer is in the form
+
+  layer_key=layer_name[,key1=value1[,...]]
+
+  Valid layer keys are ``bus`` and ``class``.
+  Their respective values is defined by registered ``bus`` and ``class``
+  drivers.
+
 Filter Functions
 ----------------
 
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 23/27] bus/pci: pre-process declarative PCI devargs
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (21 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 22/27] app/testpmd: add show device command Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 24/27] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
                     ` (3 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The new devargs format does not recognize a particular device name.
Each bus uses its specific format.

Instead of introducing a new bus API, process those devargs privately
for the moment. Prepare them for matching during scan against the
bus devices.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/bsd/pci.c    |  5 ++++
 drivers/bus/pci/linux/pci.c  |  5 ++++
 drivers/bus/pci/pci_params.c | 55 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/bus/pci/private.h    | 16 +++++++++++++
 4 files changed, 81 insertions(+)

diff --git a/drivers/bus/pci/bsd/pci.c b/drivers/bus/pci/bsd/pci.c
index 655b34b7e..046cd11d5 100644
--- a/drivers/bus/pci/bsd/pci.c
+++ b/drivers/bus/pci/bsd/pci.c
@@ -327,6 +327,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 int
 rte_pci_scan(void)
 {
+	struct rte_devargs *devargs;
 	int fd;
 	unsigned dev_count = 0;
 	struct pci_conf matches[16];
@@ -342,6 +343,10 @@ rte_pci_scan(void)
 	if (!rte_eal_has_pci())
 		return 0;
 
+	RTE_EAL_DEVARGS_FOREACH("pci", devargs)
+		if (rte_pci_devargs_prepare(devargs))
+			continue;
+
 	fd = open("/dev/pci", O_RDONLY);
 	if (fd < 0) {
 		RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__);
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 004600f1c..0c20a4337 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -430,6 +430,7 @@ parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
 int
 rte_pci_scan(void)
 {
+	struct rte_devargs *devargs;
 	struct dirent *e;
 	DIR *dir;
 	char dirname[PATH_MAX];
@@ -439,6 +440,10 @@ rte_pci_scan(void)
 	if (!rte_eal_has_pci())
 		return 0;
 
+	RTE_EAL_DEVARGS_FOREACH("pci", devargs)
+		if (rte_pci_devargs_prepare(devargs))
+			continue;
+
 #ifdef VFIO_PRESENT
 	if (!pci_vfio_is_enabled())
 		RTE_LOG(DEBUG, EAL, "VFIO PCI modules not loaded\n");
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 7630d4845..bb62bcb80 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -2,9 +2,12 @@
  * Copyright 2018 Gaëtan Rivet
  */
 
+#include <string.h>
+
 #include <rte_bus.h>
 #include <rte_bus_pci.h>
 #include <rte_dev.h>
+#include <rte_devargs.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
 #include <rte_pci.h>
@@ -76,3 +79,55 @@ rte_pci_dev_iterate(const void *start,
 	rte_kvargs_free(kvargs);
 	return dev;
 }
+
+static int
+pci_addr_kv_parse(const char *key __rte_unused,
+		  const char *value,
+		  void *_da)
+{
+	struct rte_devargs *da = _da;
+	struct rte_pci_addr addr;
+
+	/* Verify address is valid. */
+	if (rte_pci_addr_parse(value, &addr)) {
+		rte_errno = ENODEV;
+		return -1;
+	}
+	/* Write down the address as the devargs name. */
+	rte_pci_device_name(&addr, da->name, sizeof(da->name));
+	return 0;
+}
+
+int
+rte_pci_devargs_prepare(struct rte_devargs *da)
+{
+	struct rte_kvargs *kvargs = NULL;
+	char *args;
+	int ret;
+
+	if (da->busstr == NULL)
+		return 0;
+
+	args = strchr(da->busstr, ',');
+	if (args == NULL)
+		return 0;
+	args++;
+
+	kvargs = rte_kvargs_parse(args, pci_params_keys);
+	if (kvargs == NULL) {
+		RTE_LOG(ERR, EAL, "unable to parse parameter list: %s\n",
+			da->busstr);
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	if (rte_kvargs_process(kvargs, "id",
+			       &pci_addr_kv_parse, da)) {
+		ret = -1;
+		goto free_kvargs;
+	}
+
+free_kvargs:
+	rte_kvargs_free(kvargs);
+	return ret;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 0e689fa74..9beb24c6a 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -191,4 +191,20 @@ rte_pci_dev_iterate(const void *start,
 		    const char *str,
 		    const struct rte_dev_iterator *it);
 
+/*
+ * Prepare a devargs meant for this bus.
+ * This function is only used for a transitory period,
+ * to translate the new devargs format in one
+ * compatible with the old form.
+ *
+ * @param da
+ *   Devargs to process.
+ *
+ * @return
+ *   0 on success.
+ *   <0 on error.
+ */
+int
+rte_pci_devargs_prepare(struct rte_devargs *da);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 24/27] bus/vdev: pre-process declarative vdev devargs
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (22 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 23/27] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 25/27] bus/pci: process declarative PCI devargs Gaetan Rivet
                     ` (2 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The new devargs format does not recognize a particular device name.
Each bus uses its specific format.

Process each devargs privately prior to attempting a bus scan.
Prepare them if they are using the new devargs format.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev.c         | 10 +++++----
 drivers/bus/vdev/vdev_params.c  | 50 +++++++++++++++++++++++++++++++++++++++++
 drivers/bus/vdev/vdev_private.h |  6 +++++
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index e8518833d..f2dace245 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -115,8 +115,8 @@ rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
 	return 0;
 }
 
-static int
-vdev_parse(const char *name, void *addr)
+int
+rte_vdev_parse(const char *name, void *addr)
 {
 	struct rte_vdev_driver **out = addr;
 	struct rte_vdev_driver *driver = NULL;
@@ -148,7 +148,7 @@ vdev_probe_all_drivers(struct rte_vdev_device *dev)
 	VDEV_LOG(DEBUG, "Search driver %s to probe device %s", name,
 		rte_vdev_device_name(dev));
 
-	if (vdev_parse(name, &driver))
+	if (rte_vdev_parse(name, &driver))
 		return -1;
 	dev->device.driver = &driver->driver;
 	ret = driver->probe(dev);
@@ -443,6 +443,8 @@ vdev_scan(void)
 
 	/* for virtual devices we scan the devargs_list populated via cmdline */
 	RTE_EAL_DEVARGS_FOREACH("vdev", devargs) {
+		if (rte_vdev_devargs_prepare(devargs))
+			continue;
 
 		dev = calloc(1, sizeof(*dev));
 		if (!dev)
@@ -536,7 +538,7 @@ static struct rte_bus rte_vdev_bus = {
 	.find_device = rte_vdev_find_device,
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
-	.parse = vdev_parse,
+	.parse = rte_vdev_parse,
 	.dev_iterate = rte_vdev_dev_iterate,
 };
 
diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
index 2f55f451f..7ad11b092 100644
--- a/drivers/bus/vdev/vdev_params.c
+++ b/drivers/bus/vdev/vdev_params.c
@@ -2,11 +2,14 @@
  * Copyright 2018 Gaëtan Rivet
  */
 
+#include <string.h>
+
 #include <rte_dev.h>
 #include <rte_bus.h>
 #include <rte_bus_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
+#include <rte_devargs.h>
 
 #include "vdev_logs.h"
 #include "vdev_private.h"
@@ -60,3 +63,50 @@ rte_vdev_dev_iterate(const void *start,
 	rte_kvargs_free(kvargs);
 	return dev;
 }
+
+static int
+vdev_driver_kv_parse(const char *key __rte_unused,
+		     const char *value,
+		     void *_da)
+{
+	struct rte_devargs *da = _da;
+	struct rte_vdev_driver *driver;
+
+	/* Verify that the driver matches. */
+	if (rte_vdev_parse(value, &driver))
+		return -1;
+
+	/* Copy the driver name as-is. */
+	snprintf(da->name, sizeof(da->name), "%s", value);
+	return 0;
+}
+
+int
+rte_vdev_devargs_prepare(struct rte_devargs *da)
+{
+	struct rte_kvargs *kvargs = NULL;
+	char *args;
+	int ret;
+
+	if (da->busstr == NULL)
+		return 0;
+
+	args = strchr(da->busstr, ',');
+	if (args == NULL)
+		return 0;
+	args++;
+
+	kvargs = rte_kvargs_parse(args, vdev_params_keys);
+	if (kvargs == NULL) {
+		VDEV_LOG(ERR, "unable to parse parameter list: %s\n",
+			 da->busstr);
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	ret = rte_kvargs_process(kvargs, "driver",
+				 vdev_driver_kv_parse, da);
+
+	rte_kvargs_free(kvargs);
+	return ret;
+}
diff --git a/drivers/bus/vdev/vdev_private.h b/drivers/bus/vdev/vdev_private.h
index ba6dc48ff..da57b84dd 100644
--- a/drivers/bus/vdev/vdev_private.h
+++ b/drivers/bus/vdev/vdev_private.h
@@ -19,6 +19,12 @@ rte_vdev_dev_iterate(const void *start,
 		     const char *str,
 		     const struct rte_dev_iterator *it);
 
+int
+rte_vdev_parse(const char *name, void *addr);
+
+int
+rte_vdev_devargs_prepare(struct rte_devargs *da);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 25/27] bus/pci: process declarative PCI devargs
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (23 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 24/27] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 26/27] ethdev: process declarative eth devargs Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 27/27] eal: add generic dev parameter Gaetan Rivet
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Introduce the facility to process future PCI parameters.

Once the matching between PCI devices and devargs has been done, it is
possible to process each devargs. New parameters would have the PCI
device handle to work with when parsing the device (bus specific)
parameters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c |  3 +++
 drivers/bus/pci/pci_params.c | 10 ++++++++++
 drivers/bus/pci/private.h    | 13 +++++++++++++
 3 files changed, 26 insertions(+)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 749b6eee3..e2816eedb 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -251,6 +251,9 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 	if (dev->driver != NULL)
 		return 0;
 
+	if (rte_pci_devargs_process(dev) < 0)
+		return -1;
+
 	FOREACH_DRIVER_ON_PCIBUS(dr) {
 		rc = rte_pci_probe_one_driver(dr, dev);
 		if (rc < 0)
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index bb62bcb80..7dceef89b 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -131,3 +131,13 @@ rte_pci_devargs_prepare(struct rte_devargs *da)
 	rte_kvargs_free(kvargs);
 	return ret;
 }
+
+int
+rte_pci_devargs_process(struct rte_pci_device *pdev)
+{
+	/* For the moment, no PCI param
+	 * needs to be processed.
+	 */
+	(void) pdev;
+	return 0;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 9beb24c6a..06dc85e85 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -207,4 +207,17 @@ rte_pci_dev_iterate(const void *start,
 int
 rte_pci_devargs_prepare(struct rte_devargs *da);
 
+/*
+ * Process the device devargs, if any.
+ *
+ * @param pdev
+ *   PCI device
+ *
+ * @return
+ *   0 on success.
+ *   <0 on error.
+ */
+int
+rte_pci_devargs_process(struct rte_pci_device *pdev);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 26/27] ethdev: process declarative eth devargs
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (24 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 25/27] bus/pci: process declarative PCI devargs Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 27/27] eal: add generic dev parameter Gaetan Rivet
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Process the class-specific arguments in a devargs.
This processing takes the form of setting the proper eth_dev fields when
relevant.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/eth_private.h   |  5 ++++
 lib/librte_ethdev/rte_class_eth.c | 61 +++++++++++++++++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.c    |  7 +++++
 3 files changed, 73 insertions(+)

diff --git a/lib/librte_ethdev/eth_private.h b/lib/librte_ethdev/eth_private.h
index 0f5c6d5c4..c0c065165 100644
--- a/lib/librte_ethdev/eth_private.h
+++ b/lib/librte_ethdev/eth_private.h
@@ -19,6 +19,11 @@ struct rte_eth_dev *
 eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
 		const void *data);
 
+/* Generic rte_eth_dev parameters processor. */
+int
+rte_eth_dev_args_parse(struct rte_eth_dev *eth_dev,
+		       struct rte_devargs *da);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
index d8d8e8845..f02b6fd6a 100644
--- a/lib/librte_ethdev/rte_class_eth.c
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -35,6 +35,19 @@ struct eth_dev_match_arg {
 		.kvlist = (k), \
 	})
 
+typedef int (*eth_dev_set_t)(struct rte_eth_dev *edev, const char *value);
+
+static enum eth_params
+ethdev_param_id(const char *key)
+{
+	int i;
+
+	for (i = 0; i < RTE_ETH_PARAMS_MAX; i++)
+		if (strcmp(key, eth_params_keys[i]) == 0)
+			return i;
+	return RTE_ETH_PARAMS_MAX;
+}
+
 static int
 eth_dev_match(const struct rte_eth_dev *edev,
 	      const void *_arg)
@@ -79,6 +92,54 @@ eth_dev_iterate(const void *start,
 	return edev;
 }
 
+static int
+eth_dev_set_name(struct rte_eth_dev *edev,
+		 const char *value)
+{
+	snprintf(edev->data->name,
+		 sizeof(edev->data->name),
+		 "%s", value);
+	return 0;
+}
+
+static int
+ethdev_args_process(const char *key,
+		    const char *value,
+		    void *_edev)
+{
+	static eth_dev_set_t eth_dev_set[] = {
+		[RTE_ETH_PARAMS_NAME] = eth_dev_set_name,
+		[RTE_ETH_PARAMS_MAX] = NULL,
+	};
+	struct rte_eth_dev *edev = _edev;
+	int param;
+
+	param = ethdev_param_id(key);
+	if (eth_dev_set[param])
+		return eth_dev_set[param](edev, value);
+	return 0;
+}
+
+int
+rte_eth_dev_args_parse(struct rte_eth_dev *edev,
+		       struct rte_devargs *da)
+{
+	struct rte_kvargs *kvargs = NULL;
+
+	if (da == NULL || da->clsstr == NULL)
+		return 0;
+
+	kvargs = rte_kvargs_parse2(da->clsstr, eth_params_keys, "/");
+	if (kvargs == NULL) {
+		RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+		return -EINVAL;
+	}
+	if (rte_kvargs_process(kvargs, NULL, ethdev_args_process, edev))
+		return -1;
+	rte_kvargs_free(kvargs);
+	return 0;
+}
+
 struct rte_class rte_class_eth = {
 	.dev_iterate = eth_dev_iterate,
 };
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index cce20d9ae..4583509dd 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -41,6 +41,7 @@
 #include "rte_ethdev.h"
 #include "rte_ethdev_driver.h"
 #include "ethdev_profile.h"
+#include "eth_private.h"
 
 static int ethdev_logtype;
 
@@ -3594,6 +3595,12 @@ rte_eth_dev_create(struct rte_device *device, const char *name,
 		}
 	}
 
+	retval = rte_eth_dev_args_parse(ethdev, device->devargs);
+	if (retval) {
+		RTE_LOG(ERR, EAL, "ethdev parsing failed");
+		goto probe_failed;
+	}
+
 	retval = ethdev_init(ethdev, init_params);
 	if (retval) {
 		RTE_LOG(ERR, EAL, "ethdev initialisation failed");
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v9 27/27] eal: add generic dev parameter
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
                     ` (25 preceding siblings ...)
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 26/27] ethdev: process declarative eth devargs Gaetan Rivet
@ 2018-07-03 22:15   ` Gaetan Rivet
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-03 22:15 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Add the --dev parameter to the EAL.
This new parameter takes a generic device declaration as argument.

It uses the new devargs parsing API.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_devargs.c |  4 ++++
 lib/librte_eal/common/eal_common_options.c | 36 +++++++++++++++++++++++++-----
 lib/librte_eal/common/eal_options.h        |  2 ++
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 5f89e0b6e..bc3ba9fe0 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -218,6 +218,10 @@ rte_devargs_parse(struct rte_devargs *da, const char *dev)
 	if (da == NULL)
 		return -EINVAL;
 
+	if (strncmp(dev, "bus=", 4) == 0 ||
+	    strncmp(dev, "class=", 6) == 0)
+		return rte_devargs_layers_parse(da, dev);
+
 	/* Retrieve eventual bus info */
 	do {
 		devname = dev;
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index ecebb2923..89d608180 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -54,6 +54,7 @@ const struct option
 eal_long_options[] = {
 	{OPT_BASE_VIRTADDR,     1, NULL, OPT_BASE_VIRTADDR_NUM    },
 	{OPT_CREATE_UIO_DEV,    0, NULL, OPT_CREATE_UIO_DEV_NUM   },
+	{OPT_DEV,               1, NULL, OPT_DEV_NUM              },
 	{OPT_FILE_PREFIX,       1, NULL, OPT_FILE_PREFIX_NUM      },
 	{OPT_HELP,              0, NULL, OPT_HELP_NUM             },
 	{OPT_HUGE_DIR,          1, NULL, OPT_HUGE_DIR_NUM         },
@@ -109,6 +110,7 @@ TAILQ_HEAD(device_option_list, device_option);
 struct device_option {
 	TAILQ_ENTRY(device_option) next;
 
+	int new;
 	enum rte_devtype type;
 	char arg[];
 };
@@ -121,7 +123,8 @@ static int mem_parsed;
 static int core_parsed;
 
 static int
-eal_option_device_add(enum rte_devtype type, const char *optarg)
+eal_option_device_add(enum rte_devtype type, const char *optarg,
+		      int new)
 {
 	struct device_option *devopt;
 	size_t optlen;
@@ -135,6 +138,7 @@ eal_option_device_add(enum rte_devtype type, const char *optarg)
 	}
 
 	devopt->type = type;
+	devopt->new = new;
 	ret = snprintf(devopt->arg, optlen, "%s", optarg);
 	if (ret < 0) {
 		RTE_LOG(ERR, EAL, "Unable to copy device option\n");
@@ -154,7 +158,22 @@ eal_option_device_parse(void)
 
 	TAILQ_FOREACH_SAFE(devopt, &devopt_list, next, tmp) {
 		if (ret == 0) {
-			ret = rte_devargs_add(devopt->type, devopt->arg);
+			if (devopt->new) {
+				struct rte_devargs *da;
+
+				da = calloc(1, sizeof(*da));
+				ret = rte_devargs_parse(da, devopt->arg);
+				if (ret) {
+					free(da);
+				} else {
+					ret = rte_devargs_insert(da);
+					if (ret)
+						free(da);
+				}
+			} else {
+				ret = rte_devargs_add(devopt->type,
+						      devopt->arg);
+			}
 			if (ret)
 				RTE_LOG(ERR, EAL, "Unable to parse device '%s'\n",
 					devopt->arg);
@@ -1038,7 +1057,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		if (w_used)
 			goto bw_used;
 		if (eal_option_device_add(RTE_DEVTYPE_BLACKLISTED_PCI,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		b_used = 1;
@@ -1048,7 +1067,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		if (b_used)
 			goto bw_used;
 		if (eal_option_device_add(RTE_DEVTYPE_WHITELISTED_PCI,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		w_used = 1;
@@ -1177,9 +1196,16 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_DEV_NUM:
+		if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
+				optarg, 1) < 0) {
+			return -1;
+		}
+		break;
+
 	case OPT_VDEV_NUM:
 		if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		break;
diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h
index 211ae06ae..b1851864f 100644
--- a/lib/librte_eal/common/eal_options.h
+++ b/lib/librte_eal/common/eal_options.h
@@ -21,6 +21,8 @@ enum {
 	OPT_BASE_VIRTADDR_NUM,
 #define OPT_CREATE_UIO_DEV    "create-uio-dev"
 	OPT_CREATE_UIO_DEV_NUM,
+#define OPT_DEV               "dev"
+	OPT_DEV_NUM,
 #define OPT_FILE_PREFIX       "file-prefix"
 	OPT_FILE_PREFIX_NUM,
 #define OPT_HUGE_DIR          "huge-dir"
-- 
2.11.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class
  2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-07-04 12:20     ` Andrew Rybchenko
  2018-07-05  9:36       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Andrew Rybchenko @ 2018-07-04 12:20 UTC (permalink / raw)
  To: Gaetan Rivet, dev

On 07/04/2018 01:15 AM, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>   lib/librte_ethdev/Makefile        |  3 +-
>   lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++++++++++
>   2 files changed, 81 insertions(+), 1 deletion(-)
>   create mode 100644 lib/librte_ethdev/rte_class_eth.c
>
> diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
> index 2fa133fbc..d4c3a8d06 100644
> --- a/lib/librte_ethdev/Makefile
> +++ b/lib/librte_ethdev/Makefile
> @@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
>   CFLAGS += -O3
>   CFLAGS += $(WERROR_FLAGS)
>   LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
> -LDLIBS += -lrte_mbuf
> +LDLIBS += -lrte_mbuf -lrte_kvargs
>   
>   EXPORT_MAP := rte_ethdev_version.map
>   
> @@ -20,6 +20,7 @@ LIBABIVER := 9
>   
>   SRCS-y += eth_private.c
>   SRCS-y += rte_ethdev.c
> +SRCS-y += rte_class_eth.c
>   SRCS-y += rte_flow.c
>   SRCS-y += rte_tm.c
>   SRCS-y += rte_mtr.c

meson.build files should be updated as well.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class
  2018-07-04 12:20     ` Andrew Rybchenko
@ 2018-07-05  9:36       ` Gaëtan Rivet
  2018-07-05 11:13         ` Bruce Richardson
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-07-05  9:36 UTC (permalink / raw)
  To: Andrew Rybchenko; +Cc: dev

Hi Andrew,

On Wed, Jul 04, 2018 at 03:20:17PM +0300, Andrew Rybchenko wrote:
> On 07/04/2018 01:15 AM, Gaetan Rivet wrote:
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >   lib/librte_ethdev/Makefile        |  3 +-
> >   lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++++++++++
> >   2 files changed, 81 insertions(+), 1 deletion(-)
> >   create mode 100644 lib/librte_ethdev/rte_class_eth.c
> > 
> > diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
> > index 2fa133fbc..d4c3a8d06 100644
> > --- a/lib/librte_ethdev/Makefile
> > +++ b/lib/librte_ethdev/Makefile
> > @@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
> >   CFLAGS += -O3
> >   CFLAGS += $(WERROR_FLAGS)
> >   LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
> > -LDLIBS += -lrte_mbuf
> > +LDLIBS += -lrte_mbuf -lrte_kvargs
> >   EXPORT_MAP := rte_ethdev_version.map
> > @@ -20,6 +20,7 @@ LIBABIVER := 9
> >   SRCS-y += eth_private.c
> >   SRCS-y += rte_ethdev.c
> > +SRCS-y += rte_class_eth.c
> >   SRCS-y += rte_flow.c
> >   SRCS-y += rte_tm.c
> >   SRCS-y += rte_mtr.c
> 
> meson.build files should be updated as well.

The meson version required by DPDK is not available in my distribution.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class
  2018-07-05  9:36       ` Gaëtan Rivet
@ 2018-07-05 11:13         ` Bruce Richardson
  2018-07-05 11:54           ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Bruce Richardson @ 2018-07-05 11:13 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: Andrew Rybchenko, dev

On Thu, Jul 05, 2018 at 11:36:38AM +0200, Gaëtan Rivet wrote:
> Hi Andrew,
> 
> On Wed, Jul 04, 2018 at 03:20:17PM +0300, Andrew Rybchenko wrote:
> > On 07/04/2018 01:15 AM, Gaetan Rivet wrote:
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > ---
> > >   lib/librte_ethdev/Makefile        |  3 +-
> > >   lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++++++++++
> > >   2 files changed, 81 insertions(+), 1 deletion(-)
> > >   create mode 100644 lib/librte_ethdev/rte_class_eth.c
> > > 
> > > diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
> > > index 2fa133fbc..d4c3a8d06 100644
> > > --- a/lib/librte_ethdev/Makefile
> > > +++ b/lib/librte_ethdev/Makefile
> > > @@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
> > >   CFLAGS += -O3
> > >   CFLAGS += $(WERROR_FLAGS)
> > >   LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
> > > -LDLIBS += -lrte_mbuf
> > > +LDLIBS += -lrte_mbuf -lrte_kvargs
> > >   EXPORT_MAP := rte_ethdev_version.map
> > > @@ -20,6 +20,7 @@ LIBABIVER := 9
> > >   SRCS-y += eth_private.c
> > >   SRCS-y += rte_ethdev.c
> > > +SRCS-y += rte_class_eth.c
> > >   SRCS-y += rte_flow.c
> > >   SRCS-y += rte_tm.c
> > >   SRCS-y += rte_mtr.c
> > 
> > meson.build files should be updated as well.
> 
> The meson version required by DPDK is not available in my distribution.
> 
"pip3 install meson" works in just about all distros. I'd recommend using
meson from pip generally, since it tends to be very up to date. The latest
versions configure DPDK a lot faster than the older ones!

/Bruce

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 00/27] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (23 preceding siblings ...)
  2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
@ 2018-07-05 11:48 ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function Gaetan Rivet
                     ` (26 more replies)
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
  25 siblings, 27 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev
  Cc: Gaetan Rivet, Neil Horman, Keith Wiles, Matan Azrad,
	Shreyansh Jain, Bruce Richardson, Andrew Rybchenko

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.

v5:

  * Rebased on master
  * Use strcspn instead of custom function.
  * Introduce private generic rte_eth_dev iterator.
    This could be generalized to other iterators
    (port_next, owner_id-aware, etc).
  * Attempted to support meson.build.
    Got lost in the implicit variables declared
    when inversing dependencies between kvargs and EAL.
    Removed anything related to meson.
  * Postponed genericization of work from
    device query to device declaration.
    Much bigger than anticipated, will let this
    part get in first and iterate over it.

v6:

  * Rebased on master
  * Introduce RTE_PRIORITY_LAST, to explicitly set
    the lowest constructor priority.
  * Fix copyright notice for eth_privage.* files.

v7:

  * Rebased on master
  * Fix rte_kvargs_strcmp return value.
  * Fix layer parsing error
    devstr "bus=pci/onemorelayer" now tells
    that the additional layer is not recognized.

v8:

  * Rebased on master
  * Cleaned kvargs use: introduced
    a new parser function, that simplifies
    using the library for DPDK devargs.
  * Refactored devargs parsing in a single
    function within rte_devargs.
    This function is useful both for rte_dev
    parsing its iterator, and for rte_devargs
    parsing --dev parameters (not yet implemented).
  * A few small bugfixes.

v9:

  * Rebased on master
  * Fixed cyclic dependency kvargs <-> eal
  * Fixed a few checkpatch issues
  * Added dynamic help to testpmd for new "show device" command
  * Added devargs processing stubs to
    primary buses / classes
  * Added new --dev generic device declaration option

v10:

  * Support meson build

Gaetan Rivet (27):
  devargs: add non-variadic parsing function
  kvargs: remove error logs
  kvargs: build before EAL
  kvargs: introduce a more flexible parsing function
  eal: introduce dtor macros
  eal: introduce device class abstraction
  eal/class: register destructor
  devargs: add function to parse device layers
  eal/dev: add device iterator interface
  eal/class: add device iteration
  eal/bus: add device iteration
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: add private generic device iterator
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command
  bus/pci: pre-process declarative PCI devargs
  bus/vdev: pre-process declarative vdev devargs
  bus/pci: process declarative PCI devargs
  ethdev: process declarative eth devargs
  eal: add generic dev parameter

 app/test-pmd/cmdline.c                      |  54 +++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  24 +++
 drivers/bus/pci/Makefile                    |   3 +-
 drivers/bus/pci/bsd/pci.c                   |   5 +
 drivers/bus/pci/linux/pci.c                 |   5 +
 drivers/bus/pci/meson.build                 |   6 +-
 drivers/bus/pci/pci_common.c                |   6 +-
 drivers/bus/pci/pci_params.c                | 139 ++++++++++++
 drivers/bus/pci/private.h                   |  54 +++++
 drivers/bus/vdev/Makefile                   |   3 +-
 drivers/bus/vdev/meson.build                |   5 +-
 drivers/bus/vdev/vdev.c                     |  20 +-
 drivers/bus/vdev/vdev_params.c              | 112 ++++++++++
 drivers/bus/vdev/vdev_private.h             |  32 +++
 drivers/net/failsafe/failsafe_args.c        |   2 +-
 drivers/net/failsafe/failsafe_eal.c         |   2 +-
 lib/Makefile                                |   5 +-
 lib/librte_eal/bsdapp/eal/Makefile          |   2 +
 lib/librte_eal/common/Makefile              |   2 +-
 lib/librte_eal/common/eal_common_class.c    |  62 ++++++
 lib/librte_eal/common/eal_common_dev.c      | 227 +++++++++++++++++++-
 lib/librte_eal/common/eal_common_devargs.c  | 190 +++++++++++++++-
 lib/librte_eal/common/eal_common_options.c  |  36 +++-
 lib/librte_eal/common/eal_options.h         |   2 +
 lib/librte_eal/common/eal_private.h         |  27 +++
 lib/librte_eal/common/include/rte_bus.h     |   1 +
 lib/librte_eal/common/include/rte_class.h   | 127 +++++++++++
 lib/librte_eal/common/include/rte_common.h  |  24 +++
 lib/librte_eal/common/include/rte_dev.h     |  97 +++++++++
 lib/librte_eal/common/include/rte_devargs.h |  53 ++++-
 lib/librte_eal/common/meson.build           |   2 +
 lib/librte_eal/linuxapp/eal/Makefile        |   2 +
 lib/librte_eal/meson.build                  |   1 +
 lib/librte_eal/rte_eal_version.map          |   5 +
 lib/librte_ethdev/Makefile                  |   4 +-
 lib/librte_ethdev/eth_private.c             |  31 +++
 lib/librte_ethdev/eth_private.h             |  31 +++
 lib/librte_ethdev/meson.build               |   4 +-
 lib/librte_ethdev/rte_class_eth.c           | 147 +++++++++++++
 lib/librte_ethdev/rte_ethdev.c              |   9 +-
 lib/librte_kvargs/Makefile                  |   2 +-
 lib/librte_kvargs/meson.build               |   5 +
 lib/librte_kvargs/rte_kvargs.c              |  57 +++--
 lib/librte_kvargs/rte_kvargs.h              |  58 +++++
 lib/librte_kvargs/rte_kvargs_version.map    |   8 +
 lib/meson.build                             |   8 +-
 46 files changed, 1637 insertions(+), 64 deletions(-)
 create mode 100644 drivers/bus/pci/pci_params.c
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 14:44     ` Thomas Monjalon
  2018-07-11 11:46     ` Shreyansh Jain
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 02/27] kvargs: remove error logs Gaetan Rivet
                     ` (25 subsequent siblings)
  26 siblings, 2 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose
device strings.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/net/failsafe/failsafe_args.c        |  2 +-
 drivers/net/failsafe/failsafe_eal.c         |  2 +-
 lib/librte_eal/common/eal_common_dev.c      |  4 +-
 lib/librte_eal/common/eal_common_devargs.c  | 42 ++++++++++++++++-----
 lib/librte_eal/common/include/rte_devargs.h | 40 +++++++++++++++++++-
 lib/librte_eal/rte_eal_version.map          |  1 +
 lib/librte_ethdev/rte_ethdev.c              |  2 +-
 7 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/drivers/net/failsafe/failsafe_args.c b/drivers/net/failsafe/failsafe_args.c
index 2c002b164..626883ce2 100644
--- a/drivers/net/failsafe/failsafe_args.c
+++ b/drivers/net/failsafe/failsafe_args.c
@@ -63,7 +63,7 @@ fs_parse_device(struct sub_device *sdev, char *args)
 
 	d = &sdev->devargs;
 	DEBUG("%s", args);
-	ret = rte_devargs_parse(d, "%s", args);
+	ret = rte_devargs_parse(d, args);
 	if (ret) {
 		DEBUG("devargs parsing failed with code %d", ret);
 		return ret;
diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c
index 5672f3961..ce1633f13 100644
--- a/drivers/net/failsafe/failsafe_eal.c
+++ b/drivers/net/failsafe/failsafe_eal.c
@@ -86,7 +86,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			else
 				snprintf(devstr, sizeof(devstr), "%s",
 					 rte_eth_devices[pid].device->name);
-			ret = rte_devargs_parse(da, "%s", devstr);
+			ret = rte_devargs_parse(da, devstr);
 			if (ret) {
 				ERROR("Probed devargs parsing failed with code"
 				      " %d", ret);
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 61cb3b162..ce4b51469 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -138,8 +138,8 @@ int __rte_experimental rte_eal_hotplug_add(const char *busname, const char *devn
 	if (da == NULL)
 		return -ENOMEM;
 
-	ret = rte_devargs_parse(da, "%s:%s,%s",
-				    busname, devname, devargs);
+	ret = rte_devargs_parsef(da, "%s:%s,%s",
+				 busname, devname, devargs);
 	if (ret)
 		goto err_devarg;
 
diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index b0434158b..0a83beb94 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -62,24 +62,18 @@ bus_name_cmp(const struct rte_bus *bus, const void *name)
 	return strncmp(bus->name, name, strlen(bus->name));
 }
 
-int __rte_experimental
-rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev)
 {
 	struct rte_bus *bus = NULL;
-	va_list ap;
-	va_start(ap, format);
-	char dev[vsnprintf(NULL, 0, format, ap) + 1];
 	const char *devname;
 	const size_t maxlen = sizeof(da->name);
 	size_t i;
 
-	va_end(ap);
 	if (da == NULL)
 		return -EINVAL;
 
-	va_start(ap, format);
-	vsnprintf(dev, sizeof(dev), format, ap);
-	va_end(ap);
 	/* Retrieve eventual bus info */
 	do {
 		devname = dev;
@@ -124,6 +118,34 @@ rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
 	return 0;
 }
 
+__rte_experimental
+int
+rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
+{
+	va_list ap;
+	size_t len;
+	char *dev;
+
+	if (da == NULL)
+		return -EINVAL;
+
+	va_start(ap, format);
+	len = vsnprintf(NULL, 0, format, ap);
+	va_end(ap);
+
+	dev = calloc(1, len + 1);
+	if (dev == NULL) {
+		fprintf(stderr, "ERROR: not enough memory to parse device\n");
+		return -ENOMEM;
+	}
+
+	va_start(ap, format);
+	vsnprintf(dev, len, format, ap);
+	va_end(ap);
+
+	return rte_devargs_parse(da, dev);
+}
+
 int __rte_experimental
 rte_devargs_insert(struct rte_devargs *da)
 {
@@ -150,7 +172,7 @@ rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	if (devargs == NULL)
 		goto fail;
 
-	if (rte_devargs_parse(devargs, "%s", dev))
+	if (rte_devargs_parse(devargs, dev))
 		goto fail;
 	devargs->type = devtype;
 	bus = devargs->bus;
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 58fbd90a2..6c3b6326b 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -89,6 +89,42 @@ __rte_deprecated
 int rte_eal_parse_devargs_str(const char *devargs_str,
 				char **drvname, char **drvargs);
 
+/**
+ * Parse a device string.
+ *
+ * Verify that a bus is capable of handling the device passed
+ * in argument. Store which bus will handle the device, its name
+ * and the eventual device parameters.
+ *
+ * The syntax is:
+ *
+ *     bus:device_identifier,arg1=val1,arg2=val2
+ *
+ * where "bus:" is the bus name followed by any character separator.
+ * The bus name is optional. If no bus name is specified, each bus
+ * will attempt to recognize the device identifier. The first one
+ * to succeed will be used.
+ *
+ * Examples:
+ *
+ *     pci:0000:05.00.0,arg=val
+ *     05.00.0,arg=val
+ *     vdev:net_ring0
+ *
+ * @param da
+ *   The devargs structure holding the device information.
+ *
+ * @param dev
+ *   String describing a device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative errno on error.
+ */
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev);
+
 /**
  * Parse a device string.
  *
@@ -124,8 +160,8 @@ int rte_eal_parse_devargs_str(const char *devargs_str,
  */
 __rte_experimental
 int
-rte_devargs_parse(struct rte_devargs *da,
-		  const char *format, ...)
+rte_devargs_parsef(struct rte_devargs *da,
+		   const char *format, ...)
 __attribute__((format(printf, 2, 0)));
 
 /**
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index f7dd0e7bc..1c4db72fa 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -254,6 +254,7 @@ EXPERIMENTAL {
 	rte_devargs_insert;
 	rte_devargs_next;
 	rte_devargs_parse;
+	rte_devargs_parsef;
 	rte_devargs_remove;
 	rte_devargs_type_count;
 	rte_eal_cleanup;
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index a9977df97..cce20d9ae 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -654,7 +654,7 @@ rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
 	}
 
 	/* parse devargs */
-	if (rte_devargs_parse(&da, "%s", devargs))
+	if (rte_devargs_parse(&da, devargs))
 		goto err;
 
 	ret = rte_eal_hotplug_add(da.bus->name, da.name, da.args);
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 02/27] kvargs: remove error logs
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 21:51     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 03/27] kvargs: build before EAL Gaetan Rivet
                     ` (24 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Error logs in kvargs parsing should be better handled in components
calling the library.

This library must be as lean as possible.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_kvargs/rte_kvargs.c | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..747f14964 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -6,7 +6,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include <rte_log.h>
 #include <rte_string_fns.h>
 
 #include "rte_kvargs.h"
@@ -28,29 +27,22 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
 	 * to pass to rte_strsplit
 	 */
 	kvlist->str = strdup(params);
-	if (kvlist->str == NULL) {
-		RTE_LOG(ERR, PMD, "Cannot parse arguments: not enough memory\n");
+	if (kvlist->str == NULL)
 		return -1;
-	}
 
 	/* browse each key/value pair and add it in kvlist */
 	str = kvlist->str;
 	while ((str = strtok_r(str, RTE_KVARGS_PAIRS_DELIM, &ctx1)) != NULL) {
 
 		i = kvlist->count;
-		if (i >= RTE_KVARGS_MAX) {
-			RTE_LOG(ERR, PMD, "Cannot parse arguments: list full\n");
+		if (i >= RTE_KVARGS_MAX)
 			return -1;
-		}
 
 		kvlist->pairs[i].key = strtok_r(str, RTE_KVARGS_KV_DELIM, &ctx2);
 		kvlist->pairs[i].value = strtok_r(NULL, RTE_KVARGS_KV_DELIM, &ctx2);
-		if (kvlist->pairs[i].key == NULL || kvlist->pairs[i].value == NULL) {
-			RTE_LOG(ERR, PMD,
-				"Cannot parse arguments: wrong key or value\n"
-				"params=<%s>\n", params);
+		if (kvlist->pairs[i].key == NULL ||
+		    kvlist->pairs[i].value == NULL)
 			return -1;
-		}
 
 		kvlist->count++;
 		str = NULL;
@@ -89,12 +81,8 @@ check_for_valid_keys(struct rte_kvargs *kvlist,
 	for (i = 0; i < kvlist->count; i++) {
 		pair = &kvlist->pairs[i];
 		ret = is_valid_key(valid, pair->key);
-		if (!ret) {
-			RTE_LOG(ERR, PMD,
-				"Error parsing device, invalid key <%s>\n",
-				pair->key);
+		if (!ret)
 			return -1;
-		}
 	}
 	return 0;
 }
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 03/27] kvargs: build before EAL
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 02/27] kvargs: remove error logs Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 21:50     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 04/27] kvargs: introduce a more flexible parsing function Gaetan Rivet
                     ` (23 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                  | 3 +--
 lib/librte_eal/meson.build    | 1 +
 lib/librte_kvargs/Makefile    | 2 +-
 lib/librte_kvargs/meson.build | 3 +++
 lib/meson.build               | 8 ++++++--
 5 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index d82462ba2..e8e903c8f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -76,8 +77,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ethdev
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/meson.build b/lib/librte_eal/meson.build
index 4aa63e3d0..259bb4464 100644
--- a/lib/librte_eal/meson.build
+++ b/lib/librte_eal/meson.build
@@ -24,6 +24,7 @@ endif
 version = 7  # the version of the EAL API
 allow_experimental_apis = true
 deps += 'compat'
+deps += 'kvargs'
 cflags += '-D_GNU_SOURCE'
 sources = common_sources + env_sources
 objs = common_objs + env_objs
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 39d5ac33d..875939547 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -7,7 +7,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
diff --git a/lib/librte_kvargs/meson.build b/lib/librte_kvargs/meson.build
index 0c5b9cb20..0a81e8da7 100644
--- a/lib/librte_kvargs/meson.build
+++ b/lib/librte_kvargs/meson.build
@@ -1,6 +1,9 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
+includes = [global_inc]
+includes += include_directories('../../../lib/librte_eal/common/include')
+
 version = 1
 sources = files('rte_kvargs.c')
 headers = files('rte_kvargs.h')
diff --git a/lib/meson.build b/lib/meson.build
index 9d11571f9..5f7eb310e 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -9,7 +9,8 @@
 # given as a dep, no need to mention ring. This is especially true for the
 # core libs which are widely reused, so their deps are kept to a minimum.
 libraries = [ 'compat', # just a header, used for versioning
-	'eal', 'ring', 'mempool', 'mbuf', 'net', 'kvargs', 'ethdev', 'pci', # core
+	'kvargs',
+	'eal', 'ring', 'mempool', 'mbuf', 'net', 'ethdev', 'pci', # core
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
 	'timer',   # eventdev depends on this
@@ -41,9 +42,12 @@ foreach l:libraries
 	# external package/library requirements
 	ext_deps = []
 	deps = ['eal']   # eal is standard dependency except for itself
-	if l == 'eal'
+	if l == 'kvargs'
 		deps = []
 	endif
+	if l == 'eal'
+		deps = ['kvargs']
+	endif
 
 	dir_name = 'librte_' + l
 	subdir(dir_name)
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 04/27] kvargs: introduce a more flexible parsing function
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (2 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 03/27] kvargs: build before EAL Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 22:00     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros Gaetan Rivet
                     ` (22 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function permits defining additional terminating characters,
ending the parsing to arbitrary delimiters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/meson.build            |  2 ++
 lib/librte_kvargs/rte_kvargs.c           | 25 ++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 30 ++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 ++++++
 5 files changed, 65 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index e8e903c8f..8a65525cd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-y += librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
+DEPDIRS-librte_kvargs := librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
diff --git a/lib/librte_kvargs/meson.build b/lib/librte_kvargs/meson.build
index 0a81e8da7..a1c724961 100644
--- a/lib/librte_kvargs/meson.build
+++ b/lib/librte_kvargs/meson.build
@@ -7,3 +7,5 @@ includes += include_directories('../../../lib/librte_eal/common/include')
 version = 1
 sources = files('rte_kvargs.c')
 headers = files('rte_kvargs.h')
+
+deps += 'compat'
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 747f14964..519f77679 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -168,3 +168,28 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+struct rte_kvargs *
+rte_kvargs_parse2(const char *args, const char * const valid_keys[],
+		  const char *valid_ends)
+{
+	struct rte_kvargs *kvlist = NULL;
+	char *copy;
+	size_t len;
+
+	if (valid_ends == NULL)
+		return rte_kvargs_parse(args, valid_keys);
+
+	copy = strdup(args);
+	if (copy == NULL)
+		return NULL;
+
+	len = strcspn(copy, valid_ends);
+	copy[len] = '\0';
+
+	kvlist = rte_kvargs_parse(copy, valid_keys);
+
+	free(copy);
+	return kvlist;
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..98c4ed1bf 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -71,6 +71,36 @@ struct rte_kvargs {
 struct rte_kvargs *rte_kvargs_parse(const char *args,
 		const char *const valid_keys[]);
 
+/**
+ * Allocate a rte_kvargs and store key/value associations from a string.
+ * This version will consider any byte from valid_ends as a possible
+ * terminating character, and will not parse beyond any of their occurrence.
+ *
+ * The function allocates and fills an rte_kvargs structure from a given
+ * string whose format is key1=value1,key2=value2,...
+ *
+ * The structure can be freed with rte_kvargs_free().
+ *
+ * @param args
+ *   The input string containing the key/value associations
+ *
+ * @param valid_keys
+ *   A list of valid keys (table of const char *, the last must be NULL).
+ *   This argument is ignored if NULL
+ *
+ * @param valid_ends
+ *   Acceptable terminating characters.
+ *   If NULL, the behavior is the same as ``rte_kvargs_parse``.
+ *
+ * @return
+ *   - A pointer to an allocated rte_kvargs structure on success
+ *   - NULL on error
+ */
+__rte_experimental
+struct rte_kvargs *rte_kvargs_parse2(const char *args,
+		const char *const valid_keys[],
+		const char *valid_ends);
+
 /**
  * Free a rte_kvargs structure
  *
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..b9fe44b98 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_parse2;
+
+} DPDK_2.0;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (3 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 04/27] kvargs: introduce a more flexible parsing function Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-06  4:17     ` Shreyansh Jain
  2018-07-10 11:40     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 06/27] eal: introduce device class abstraction Gaetan Rivet
                     ` (21 subsequent siblings)
  26 siblings, 2 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 434adfd45..0dd832728 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -111,6 +111,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 #define RTE_INIT(func) \
 	RTE_INIT_PRIO(func, LAST)
 
+/**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+	RTE_FINI_PRIO(func, LAST)
+
 /**
  * Force a function to be inlined
  */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 06/27] eal: introduce device class abstraction
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (4 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-11  8:10     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 07/27] eal/class: register destructor Gaetan Rivet
                     ` (20 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 +++++++++++
 lib/librte_eal/common/include/rte_class.h  | 121 +++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/common/meson.build          |   2 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 8 files changed, 191 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index 3fd33f1e4..b0a1c880a 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -52,6 +52,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 48f870f24..750653093 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..b5e550a34
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file exposes API and interfaces of device classes.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \
+static void classinitfn_ ##nm(void) \
+{\
+	(cls).name = RTE_STR(nm);\
+	rte_class_register(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 0dd832728..a2e8e6e32 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 #define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 8a3dcfee0..3009cd0a2 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -8,6 +8,7 @@ common_objs = []
 common_sources = files(
 	'eal_common_bus.c',
 	'eal_common_cpuflags.c',
+	'eal_common_class.c',
 	'eal_common_devargs.c',
 	'eal_common_dev.c',
 	'eal_common_errno.c',
@@ -46,6 +47,7 @@ common_headers = files(
 	'include/rte_branch_prediction.h',
 	'include/rte_bus.h',
 	'include/rte_bitmap.h',
+	'include/rte_class.h',
 	'include/rte_common.h',
 	'include/rte_debug.h',
 	'include/rte_devargs.h',
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 3719ec9d7..babc8617a 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -60,6 +60,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 1c4db72fa..19d36b4c7 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -244,6 +244,8 @@ DPDK_18.05 {
 EXPERIMENTAL {
 	global:
 
+	rte_class_register;
+	rte_class_unregister;
 	rte_ctrl_thread_create;
 	rte_dev_event_callback_register;
 	rte_dev_event_callback_unregister;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 07/27] eal/class: register destructor
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (5 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 06/27] eal: introduce device class abstraction Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-11  8:12     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers Gaetan Rivet
                     ` (19 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index b5e550a34..e8176f5e1 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \
 {\
 	(cls).name = RTE_STR(nm);\
 	rte_class_register(&cls); \
+} \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
+static void classfinifn_ ##nm(void) \
+{ \
+	rte_class_unregister(&cls); \
 }
 
 #ifdef __cplusplus
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (6 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 07/27] eal/class: register destructor Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-11  8:19     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 09/27] eal/dev: add device iterator interface Gaetan Rivet
                     ` (18 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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>
---
 lib/librte_eal/common/eal_common_devargs.c  | 144 ++++++++++++++++++++
 lib/librte_eal/common/eal_private.h         |  27 ++++
 lib/librte_eal/common/include/rte_devargs.h |  13 +-
 3 files changed, 181 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 0a83beb94..5f89e0b6e 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -13,9 +13,13 @@
 #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_kvargs.h>
+#include <rte_errno.h>
 #include <rte_tailq.h>
 #include "eal_private.h"
 
@@ -56,6 +60,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 *da,
+			 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 (da->data != devstr) {
+		da->data = strdup(devstr);
+		if (da->data == NULL) {
+			RTE_LOG(ERR, EAL, "OOM\n");
+			ret = -ENOMEM;
+			goto get_out;
+		}
+		s = da->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_parse2(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. */
+	da->busstr = layers[0].str;
+	da->clsstr = layers[1].str;
+	da->drvstr = layers[2].str;
+	da->bus = bus;
+	da->cls = cls;
+
+	/* If we own the data, clean up a bit
+	 * the several layers string, to ease
+	 * their parsing afterward.
+	 */
+	if (da->data != devstr) {
+		char *s = (void *)(intptr_t)(da->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)
 {
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index bdadc4d50..c4c9283c8 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -258,4 +258,31 @@ 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.
+ *
+ * Note: if the "data" field of da 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 *da,
+			 const char *devstr);
+
 #endif /* _EAL_PRIVATE_H_ */
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 6c3b6326b..148600258 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -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 *drvstr;
+	};
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< bus-related part of device string. */
+	const char *data; /**< Device string storage. */
 };
 
 /**
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 09/27] eal/dev: add device iterator interface
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (7 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 10/27] eal/class: add device iteration Gaetan Rivet
                     ` (17 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++
 1 file changed, 47 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 3879ff3ca..120df729f 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -285,6 +285,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *devstr; /**< device string. */
+	const char *busstr; /**< bus-related part of device string. */
+	const char *clsstr; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 10/27] eal/class: add device iteration
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (8 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 09/27] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-11  9:47     ` Thomas Monjalon
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 11/27] eal/bus: " Gaetan Rivet
                     ` (16 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index e8176f5e1..9d5b06807 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 11/27] eal/bus: add device iteration
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (9 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 10/27] eal/class: add device iteration Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 12/27] eal/dev: implement device iteration initialization Gaetan Rivet
                     ` (15 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 12/27] eal/dev: implement device iteration initialization
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (10 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 11/27] eal/bus: " Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 13/27] eal/dev: implement device iteration Gaetan Rivet
                     ` (14 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@6wind.com>
---
 lib/Makefile                            |  1 +
 lib/librte_eal/bsdapp/eal/Makefile      |  1 +
 lib/librte_eal/common/eal_common_dev.c  | 55 +++++++++++++++++++++++++
 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, 83 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 8a65525cd..afa604e20 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index b0a1c880a..67b10ae0d 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 ce4b51469..5b7956d17 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 <rte_spinlock.h>
 #include <rte_malloc.h>
@@ -343,3 +346,55 @@ dev_callback_process(char *device_name, enum rte_dev_event_type event)
 	}
 	rte_spinlock_unlock(&dev_event_lock);
 }
+
+__rte_experimental
+int
+rte_dev_iterator_init(struct rte_dev_iterator *it,
+		      const char *devstr)
+{
+	struct rte_devargs da;
+	struct rte_class *cls = NULL;
+	struct rte_bus *bus = NULL;
+
+	/* Having both busstr and clsstr NULL is illegal,
+	 * marking this iterator as invalid unless
+	 * everything goes well.
+	 */
+	it->busstr = NULL;
+	it->clsstr = NULL;
+
+	da.data = devstr;
+	if (rte_devargs_layers_parse(&da, devstr))
+		goto get_out;
+
+	bus = da.bus;
+	cls = da.cls;
+	/* 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;
+	}
+	it->busstr = da.busstr;
+	it->clsstr = da.clsstr;
+	it->devstr = devstr;
+	it->bus = bus;
+	it->cls = cls;
+	it->device = NULL;
+	it->class_device = NULL;
+get_out:
+	return -rte_errno;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 120df729f..7b7bd83bc 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -332,6 +332,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 babc8617a..885c48110 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 19d36b4c7..ac04120d6 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -251,6 +251,7 @@ EXPERIMENTAL {
 	rte_dev_event_callback_unregister;
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
+	rte_dev_iterator_init;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 13/27] eal/dev: implement device iteration
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (11 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 12/27] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 14/27] kvargs: add generic string matching callback Gaetan Rivet
                     ` (13 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  26 ++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 195 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 5b7956d17..3d486a841 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
 /* spinlock for device callbacks */
 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *busstr;
+	const char *clsstr;
+};
+
+#define CTX(it, busstr, clsstr) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.busstr = busstr, \
+		.clsstr = clsstr, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->busstr)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->clsstr)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 get_out:
 	return -rte_errno;
 }
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	size_t end;
+	char *copy;
+
+	end = strcspn(str, ",/");
+	if (str[end] == ',') {
+		copy = strdup(&str[end + 1]);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *clsstr = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	clsstr = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->clsstr != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->clsstr != NULL && cls != it->cls)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, clsstr, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *busstr = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	busstr = BUSCTX(ctx);
+	dev = it->device;
+	/* it->busstr != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->busstr != NULL && bus != it->bus)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->clsstr == NULL) {
+		dev = bus->dev_iterate(dev, busstr, it);
+		goto end;
+	}
+	/* clsstr != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, busstr, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *busstr = NULL;
+	char *clsstr = NULL;
+
+	rte_errno = 0;
+	if (it->busstr == NULL && it->clsstr == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->busstr != NULL) {
+		busstr = dev_str_sane_copy(it->busstr);
+		if (busstr == NULL)
+			goto out;
+	}
+	if (it->clsstr != NULL) {
+		clsstr = dev_str_sane_copy(it->clsstr);
+		if (clsstr == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, busstr, clsstr)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->busstr != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(busstr);
+	free(clsstr);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 7b7bd83bc..1553c0970 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -356,6 +356,32 @@ __rte_experimental
 int
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index ac04120d6..4cd5ab3df 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -252,6 +252,7 @@ EXPERIMENTAL {
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 14/27] kvargs: add generic string matching callback
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (12 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 13/27] eal/dev: implement device iteration Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 15/27] bus/pci: implement device iteration and comparison Gaetan Rivet
                     ` (12 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_kvargs/rte_kvargs.c           | 10 +++++++++
 lib/librte_kvargs/rte_kvargs.h           | 28 ++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  1 +
 3 files changed, 39 insertions(+)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 519f77679..8270d2939 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -193,3 +193,13 @@ rte_kvargs_parse2(const char *args, const char * const valid_keys[],
 	free(copy);
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -abs(strcmp(str, value));
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 98c4ed1bf..ac2999ef3 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -151,6 +153,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index b9fe44b98..6a41a6b65 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -13,5 +13,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_kvargs_parse2;
+	rte_kvargs_strcmp;
 
 } DPDK_2.0;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 15/27] bus/pci: implement device iteration and comparison
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (13 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 14/27] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 16/27] bus/pci: add device matching field id Gaetan Rivet
                     ` (11 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  3 +-
 drivers/bus/pci/meson.build  |  6 +++-
 drivers/bus/pci/pci_common.c |  3 +-
 drivers/bus/pci/pci_params.c | 53 ++++++++++++++++++++++++++++++++++++
 drivers/bus/pci/private.h    | 25 +++++++++++++++++
 5 files changed, 86 insertions(+), 4 deletions(-)
 create mode 100644 drivers/bus/pci/pci_params.c

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index cf373068a..4de953f8f 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -26,10 +26,11 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
+SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_params.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common_uio.c
 
diff --git a/drivers/bus/pci/meson.build b/drivers/bus/pci/meson.build
index 72939e598..23d6a5fec 100644
--- a/drivers/bus/pci/meson.build
+++ b/drivers/bus/pci/meson.build
@@ -3,7 +3,9 @@
 
 deps += ['pci']
 install_headers('rte_bus_pci.h')
-sources = files('pci_common.c', 'pci_common_uio.c')
+sources = files('pci_common.c',
+	'pci_common_uio.c',
+	'pci_params.c')
 if host_machine.system() == 'linux'
 	sources += files('linux/pci.c',
 			'linux/pci_uio.c',
@@ -17,3 +19,5 @@ endif
 
 # memseg walk is not part of stable API yet
 allow_experimental_apis = true
+
+deps += ['kvargs']
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 94b0f4143..5b7854490 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -29,8 +29,6 @@
 
 static void rte_pci_remove_device(struct rte_pci_device *pci_device);
 
-extern struct rte_pci_bus rte_pci_bus;
-
 #define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
 
 const char *rte_pci_get_sysfs_path(void)
@@ -437,6 +435,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = rte_pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
new file mode 100644
index 000000000..0fde75803
--- /dev/null
+++ b/drivers/bus/pci/pci_params.c
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_bus.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_pci.h>
+
+#include "private.h"
+
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it __rte_unused)
+{
+	rte_bus_find_device_t find_device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	find_device = rte_pci_bus.bus.find_device;
+	dev = find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 8ddd03e16..0e689fa74 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -10,6 +10,8 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 
+extern struct rte_pci_bus rte_pci_bus;
+
 struct rte_pci_driver;
 struct rte_pci_device;
 
@@ -166,4 +168,27 @@ rte_pci_match(const struct rte_pci_driver *pci_drv,
 enum rte_iova_mode
 rte_pci_get_iommu_class(void);
 
+/*
+ * Iterate over internal devices,
+ * matching any device against the provided
+ * string.
+ *
+ * @param start
+ *   Iteration starting point.
+ *
+ * @param str
+ *   Device string to match against.
+ *
+ * @param it
+ *   (unused) iterator structure.
+ *
+ * @return
+ *   A pointer to the next matching device if any.
+ *   NULL otherwise.
+ */
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 16/27] bus/pci: add device matching field id
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (14 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 15/27] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 17/27] bus/vdev: implement device iteration Gaetan Rivet
                     ` (10 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_params.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 0fde75803..7630d4845 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -3,6 +3,7 @@
  */
 
 #include <rte_bus.h>
+#include <rte_bus_pci.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
@@ -11,21 +12,45 @@
 #include "private.h"
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
+static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return -abs(rte_pci_addr_cmp(addr1, addr2));
+}
+
 static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 17/27] bus/vdev: implement device iteration
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (15 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 16/27] bus/pci: add device matching field id Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 18/27] bus/vdev: add device matching field driver Gaetan Rivet
                     ` (9 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile       |  3 +-
 drivers/bus/vdev/meson.build    |  5 +++-
 drivers/bus/vdev/vdev.c         | 10 ++++---
 drivers/bus/vdev/vdev_params.c  | 51 +++++++++++++++++++++++++++++++++
 drivers/bus/vdev/vdev_private.h | 26 +++++++++++++++++
 5 files changed, 89 insertions(+), 6 deletions(-)
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index bd0bb8955..1f9cd7ebe 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,8 +19,9 @@ EXPORT_MAP := rte_bus_vdev_version.map
 LIBABIVER := 1
 
 SRCS-y += vdev.c
+SRCS-y += vdev_params.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/meson.build b/drivers/bus/vdev/meson.build
index 2ee648b49..12605e5c7 100644
--- a/drivers/bus/vdev/meson.build
+++ b/drivers/bus/vdev/meson.build
@@ -1,7 +1,10 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-sources = files('vdev.c')
+sources = files('vdev.c',
+	'vdev_params.c')
 install_headers('rte_bus_vdev.h')
 
 allow_experimental_apis = true
+
+deps += ['kvargs']
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 6139dd551..e8518833d 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -23,6 +23,7 @@
 
 #include "rte_bus_vdev.h"
 #include "vdev_logs.h"
+#include "vdev_private.h"
 
 #define VDEV_MP_KEY	"bus_vdev_mp"
 
@@ -493,9 +494,9 @@ vdev_probe(void)
 	return ret;
 }
 
-static struct rte_device *
-vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
-		 const void *data)
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
+		     const void *data)
 {
 	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
@@ -532,10 +533,11 @@ vdev_unplug(struct rte_device *dev)
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
-	.find_device = vdev_find_device,
+	.find_device = rte_vdev_find_device,
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = rte_vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
new file mode 100644
index 000000000..842a4684e
--- /dev/null
+++ b/drivers/bus/vdev/vdev_params.c
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_dev.h>
+#include <rte_bus.h>
+#include <rte_kvargs.h>
+#include <rte_errno.h>
+
+#include "vdev_logs.h"
+#include "vdev_private.h"
+
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = rte_vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/vdev/vdev_private.h b/drivers/bus/vdev/vdev_private.h
new file mode 100644
index 000000000..ba6dc48ff
--- /dev/null
+++ b/drivers/bus/vdev/vdev_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _VDEV_PRIVATE_H_
+#define _VDEV_PRIVATE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start,
+		     rte_dev_cmp_t cmp,
+		     const void *data);
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VDEV_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 18/27] bus/vdev: add device matching field driver
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (16 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 17/27] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 19/27] ethdev: add private generic device iterator Gaetan Rivet
                     ` (8 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev_params.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
index 842a4684e..2f55f451f 100644
--- a/drivers/bus/vdev/vdev_params.c
+++ b/drivers/bus/vdev/vdev_params.c
@@ -4,6 +4,7 @@
 
 #include <rte_dev.h>
 #include <rte_bus.h>
+#include <rte_bus_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
 
@@ -11,10 +12,12 @@
 #include "vdev_private.h"
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -23,9 +26,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 19/27] ethdev: add private generic device iterator
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (17 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 18/27] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 20/27] ethdev: register ether layer as a class Gaetan Rivet
                     ` (7 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This iterator can be customized with a comparison function that will
trigger a stopping condition.

It can be leveraged to write several different iterators that have
similar but non-identical purposes.

It is private to librte_ethdev.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile      |  1 +
 lib/librte_ethdev/eth_private.c | 31 +++++++++++++++++++++++++++++++
 lib/librte_ethdev/eth_private.h | 26 ++++++++++++++++++++++++++
 lib/librte_ethdev/meson.build   |  3 ++-
 4 files changed, 60 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index c2f2f7d82..2fa133fbc 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 9
 
+SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
diff --git a/lib/librte_ethdev/eth_private.c b/lib/librte_ethdev/eth_private.c
new file mode 100644
index 000000000..d565568a0
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include "rte_ethdev.h"
+#include "eth_private.h"
+
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
+		const void *data)
+{
+	struct rte_eth_dev *edev;
+	ptrdiff_t idx;
+
+	/* Avoid Undefined Behaviour */
+	if (start != NULL &&
+	    (start < &rte_eth_devices[0] ||
+	     start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+		return NULL;
+	if (start != NULL)
+		idx = start - &rte_eth_devices[0] + 1;
+	else
+		idx = 0;
+	for (; idx < RTE_MAX_ETHPORTS; idx++) {
+		edev = &rte_eth_devices[idx];
+		if (cmp(edev, data) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
diff --git a/lib/librte_ethdev/eth_private.h b/lib/librte_ethdev/eth_private.h
new file mode 100644
index 000000000..0f5c6d5c4
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_ETH_PRIVATE_H_
+#define _RTE_ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
+		const void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_PRIVATE_H_ */
diff --git a/lib/librte_ethdev/meson.build b/lib/librte_ethdev/meson.build
index aed5d2265..a0c001847 100644
--- a/lib/librte_ethdev/meson.build
+++ b/lib/librte_ethdev/meson.build
@@ -4,7 +4,8 @@
 name = 'ethdev'
 version = 9
 allow_experimental_apis = true
-sources = files('ethdev_profile.c',
+sources = files('eth_private.c',
+	'ethdev_profile.c',
 	'rte_ethdev.c',
 	'rte_flow.c',
 	'rte_mtr.c',
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 20/27] ethdev: register ether layer as a class
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (18 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 19/27] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 21/27] ethdev: add device matching field name Gaetan Rivet
                     ` (6 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile        |  3 +-
 lib/librte_ethdev/meson.build     |  1 +
 lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index 2fa133fbc..d4c3a8d06 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
@@ -20,6 +20,7 @@ LIBABIVER := 9
 
 SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ethdev/meson.build b/lib/librte_ethdev/meson.build
index a0c001847..f9538770b 100644
--- a/lib/librte_ethdev/meson.build
+++ b/lib/librte_ethdev/meson.build
@@ -6,6 +6,7 @@ version = 9
 allow_experimental_apis = true
 sources = files('eth_private.c',
 	'ethdev_profile.c',
+	'rte_class_eth.c',
 	'rte_ethdev.c',
 	'rte_flow.c',
 	'rte_mtr.c',
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
new file mode 100644
index 000000000..32c736d32
--- /dev/null
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "eth_private.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+	struct rte_device *device;
+	struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+	(&(const struct eth_dev_match_arg) { \
+		.device = (d), \
+		.kvlist = (k), \
+	})
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+	      const void *_arg)
+{
+	const struct eth_dev_match_arg *arg = _arg;
+	const struct rte_kvargs *kvlist = arg->kvlist;
+
+	if (edev->state == RTE_ETH_DEV_UNUSED)
+		return -1;
+	if (edev->device != arg->device)
+		return -1;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	edev = eth_find_device(start, eth_dev_match,
+			       eth_dev_match_arg(it->device, kvargs));
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 21/27] ethdev: add device matching field name
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (19 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 20/27] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 22/27] app/testpmd: add show device command Gaetan Rivet
                     ` (5 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
index 32c736d32..d8d8e8845 100644
--- a/lib/librte_ethdev/rte_class_eth.c
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -15,10 +15,12 @@
 #include "eth_private.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -39,6 +41,7 @@ eth_dev_match(const struct rte_eth_dev *edev,
 {
 	const struct eth_dev_match_arg *arg = _arg;
 	const struct rte_kvargs *kvlist = arg->kvlist;
+	struct rte_eth_dev_data *data;
 
 	if (edev->state == RTE_ETH_DEV_UNUSED)
 		return -1;
@@ -47,6 +50,10 @@ eth_dev_match(const struct rte_eth_dev *edev,
 	if (kvlist == NULL)
 		/* Empty string matches everything. */
 		return 0;
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 22/27] app/testpmd: add show device command
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (20 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 21/27] ethdev: add device matching field name Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-10 14:45     ` Iremonger, Bernard
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 23/27] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
                     ` (4 subsequent siblings)
  26 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 app/test-pmd/cmdline.c                      | 54 +++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 +++++++++
 2 files changed, 78 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 27e2aa8c8..3b86bfe48 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -228,6 +228,9 @@ static void cmd_help_long_parsed(void *parsed_result,
                         "show port tm node stats (port_id) (node_id) (clear)\n"
                         "       Display the port TM node stats.\n\n"
 
+			"show device (device_string)\n"
+			"       Display devices matching the device string.\n\n"
+
 		);
 	}
 
@@ -7083,6 +7086,56 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device <device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -17262,6 +17315,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 0d6fd50ca..4f1009a3a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on the port::
 
    testpmd> set port tm hierarchy default (port_id)
 
+Device functions
+----------------
+
+Show devices
+~~~~~~~~~~~~
+
+Display any registered devices::
+
+   testpmd> show device <device_string>
+
+where:
+
+* ``device_string``: Device description string, of the format
+
+  layer[/layer[/layer]]
+
+  where one layer is in the form
+
+  layer_key=layer_name[,key1=value1[,...]]
+
+  Valid layer keys are ``bus`` and ``class``.
+  Their respective values is defined by registered ``bus`` and ``class``
+  drivers.
+
 Filter Functions
 ----------------
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 23/27] bus/pci: pre-process declarative PCI devargs
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (21 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 22/27] app/testpmd: add show device command Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 24/27] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
                     ` (3 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The new devargs format does not recognize a particular device name.
Each bus uses its specific format.

Instead of introducing a new bus API, process those devargs privately
for the moment. Prepare them for matching during scan against the
bus devices.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/bsd/pci.c    |  5 ++++
 drivers/bus/pci/linux/pci.c  |  5 ++++
 drivers/bus/pci/pci_params.c | 51 ++++++++++++++++++++++++++++++++++++
 drivers/bus/pci/private.h    | 16 +++++++++++
 4 files changed, 77 insertions(+)

diff --git a/drivers/bus/pci/bsd/pci.c b/drivers/bus/pci/bsd/pci.c
index 655b34b7e..046cd11d5 100644
--- a/drivers/bus/pci/bsd/pci.c
+++ b/drivers/bus/pci/bsd/pci.c
@@ -327,6 +327,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 int
 rte_pci_scan(void)
 {
+	struct rte_devargs *devargs;
 	int fd;
 	unsigned dev_count = 0;
 	struct pci_conf matches[16];
@@ -342,6 +343,10 @@ rte_pci_scan(void)
 	if (!rte_eal_has_pci())
 		return 0;
 
+	RTE_EAL_DEVARGS_FOREACH("pci", devargs)
+		if (rte_pci_devargs_prepare(devargs))
+			continue;
+
 	fd = open("/dev/pci", O_RDONLY);
 	if (fd < 0) {
 		RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__);
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 004600f1c..0c20a4337 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -430,6 +430,7 @@ parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
 int
 rte_pci_scan(void)
 {
+	struct rte_devargs *devargs;
 	struct dirent *e;
 	DIR *dir;
 	char dirname[PATH_MAX];
@@ -439,6 +440,10 @@ rte_pci_scan(void)
 	if (!rte_eal_has_pci())
 		return 0;
 
+	RTE_EAL_DEVARGS_FOREACH("pci", devargs)
+		if (rte_pci_devargs_prepare(devargs))
+			continue;
+
 #ifdef VFIO_PRESENT
 	if (!pci_vfio_is_enabled())
 		RTE_LOG(DEBUG, EAL, "VFIO PCI modules not loaded\n");
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 7630d4845..56bb653fc 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -2,9 +2,12 @@
  * Copyright 2018 Gaëtan Rivet
  */
 
+#include <string.h>
+
 #include <rte_bus.h>
 #include <rte_bus_pci.h>
 #include <rte_dev.h>
+#include <rte_devargs.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
 #include <rte_pci.h>
@@ -76,3 +79,51 @@ rte_pci_dev_iterate(const void *start,
 	rte_kvargs_free(kvargs);
 	return dev;
 }
+
+static int
+pci_addr_kv_parse(const char *key __rte_unused,
+		  const char *value,
+		  void *_da)
+{
+	struct rte_devargs *da = _da;
+	struct rte_pci_addr addr;
+
+	/* Verify address is valid. */
+	if (rte_pci_addr_parse(value, &addr)) {
+		rte_errno = ENODEV;
+		return -1;
+	}
+	/* Write down the address as the devargs name. */
+	rte_pci_device_name(&addr, da->name, sizeof(da->name));
+	return 0;
+}
+
+int
+rte_pci_devargs_prepare(struct rte_devargs *da)
+{
+	struct rte_kvargs *kvargs = NULL;
+	char *args;
+	int ret;
+
+	if (da->busstr == NULL)
+		return 0;
+
+	args = strchr(da->busstr, ',');
+	if (args == NULL)
+		return 0;
+	args++;
+
+	kvargs = rte_kvargs_parse(args, pci_params_keys);
+	if (kvargs == NULL) {
+		RTE_LOG(ERR, EAL, "unable to parse parameter list: %s\n",
+			da->busstr);
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	ret = rte_kvargs_process(kvargs, "id",
+				 &pci_addr_kv_parse, da);
+
+	rte_kvargs_free(kvargs);
+	return ret;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 0e689fa74..9beb24c6a 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -191,4 +191,20 @@ rte_pci_dev_iterate(const void *start,
 		    const char *str,
 		    const struct rte_dev_iterator *it);
 
+/*
+ * Prepare a devargs meant for this bus.
+ * This function is only used for a transitory period,
+ * to translate the new devargs format in one
+ * compatible with the old form.
+ *
+ * @param da
+ *   Devargs to process.
+ *
+ * @return
+ *   0 on success.
+ *   <0 on error.
+ */
+int
+rte_pci_devargs_prepare(struct rte_devargs *da);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 24/27] bus/vdev: pre-process declarative vdev devargs
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (22 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 23/27] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 25/27] bus/pci: process declarative PCI devargs Gaetan Rivet
                     ` (2 subsequent siblings)
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The new devargs format does not recognize a particular device name.
Each bus uses its specific format.

Process each devargs privately prior to attempting a bus scan.
Prepare them if they are using the new devargs format.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev.c         | 10 ++++---
 drivers/bus/vdev/vdev_params.c  | 50 +++++++++++++++++++++++++++++++++
 drivers/bus/vdev/vdev_private.h |  6 ++++
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index e8518833d..f2dace245 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -115,8 +115,8 @@ rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
 	return 0;
 }
 
-static int
-vdev_parse(const char *name, void *addr)
+int
+rte_vdev_parse(const char *name, void *addr)
 {
 	struct rte_vdev_driver **out = addr;
 	struct rte_vdev_driver *driver = NULL;
@@ -148,7 +148,7 @@ vdev_probe_all_drivers(struct rte_vdev_device *dev)
 	VDEV_LOG(DEBUG, "Search driver %s to probe device %s", name,
 		rte_vdev_device_name(dev));
 
-	if (vdev_parse(name, &driver))
+	if (rte_vdev_parse(name, &driver))
 		return -1;
 	dev->device.driver = &driver->driver;
 	ret = driver->probe(dev);
@@ -443,6 +443,8 @@ vdev_scan(void)
 
 	/* for virtual devices we scan the devargs_list populated via cmdline */
 	RTE_EAL_DEVARGS_FOREACH("vdev", devargs) {
+		if (rte_vdev_devargs_prepare(devargs))
+			continue;
 
 		dev = calloc(1, sizeof(*dev));
 		if (!dev)
@@ -536,7 +538,7 @@ static struct rte_bus rte_vdev_bus = {
 	.find_device = rte_vdev_find_device,
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
-	.parse = vdev_parse,
+	.parse = rte_vdev_parse,
 	.dev_iterate = rte_vdev_dev_iterate,
 };
 
diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
index 2f55f451f..7ad11b092 100644
--- a/drivers/bus/vdev/vdev_params.c
+++ b/drivers/bus/vdev/vdev_params.c
@@ -2,11 +2,14 @@
  * Copyright 2018 Gaëtan Rivet
  */
 
+#include <string.h>
+
 #include <rte_dev.h>
 #include <rte_bus.h>
 #include <rte_bus_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
+#include <rte_devargs.h>
 
 #include "vdev_logs.h"
 #include "vdev_private.h"
@@ -60,3 +63,50 @@ rte_vdev_dev_iterate(const void *start,
 	rte_kvargs_free(kvargs);
 	return dev;
 }
+
+static int
+vdev_driver_kv_parse(const char *key __rte_unused,
+		     const char *value,
+		     void *_da)
+{
+	struct rte_devargs *da = _da;
+	struct rte_vdev_driver *driver;
+
+	/* Verify that the driver matches. */
+	if (rte_vdev_parse(value, &driver))
+		return -1;
+
+	/* Copy the driver name as-is. */
+	snprintf(da->name, sizeof(da->name), "%s", value);
+	return 0;
+}
+
+int
+rte_vdev_devargs_prepare(struct rte_devargs *da)
+{
+	struct rte_kvargs *kvargs = NULL;
+	char *args;
+	int ret;
+
+	if (da->busstr == NULL)
+		return 0;
+
+	args = strchr(da->busstr, ',');
+	if (args == NULL)
+		return 0;
+	args++;
+
+	kvargs = rte_kvargs_parse(args, vdev_params_keys);
+	if (kvargs == NULL) {
+		VDEV_LOG(ERR, "unable to parse parameter list: %s\n",
+			 da->busstr);
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	ret = rte_kvargs_process(kvargs, "driver",
+				 vdev_driver_kv_parse, da);
+
+	rte_kvargs_free(kvargs);
+	return ret;
+}
diff --git a/drivers/bus/vdev/vdev_private.h b/drivers/bus/vdev/vdev_private.h
index ba6dc48ff..da57b84dd 100644
--- a/drivers/bus/vdev/vdev_private.h
+++ b/drivers/bus/vdev/vdev_private.h
@@ -19,6 +19,12 @@ rte_vdev_dev_iterate(const void *start,
 		     const char *str,
 		     const struct rte_dev_iterator *it);
 
+int
+rte_vdev_parse(const char *name, void *addr);
+
+int
+rte_vdev_devargs_prepare(struct rte_devargs *da);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 25/27] bus/pci: process declarative PCI devargs
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (23 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 24/27] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 26/27] ethdev: process declarative eth devargs Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 27/27] eal: add generic dev parameter Gaetan Rivet
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Introduce the facility to process future PCI parameters.

Once the matching between PCI devices and devargs has been done, it is
possible to process each devargs. New parameters would have the PCI
device handle to work with when parsing the device (bus specific)
parameters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c |  3 +++
 drivers/bus/pci/pci_params.c | 10 ++++++++++
 drivers/bus/pci/private.h    | 13 +++++++++++++
 3 files changed, 26 insertions(+)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 5b7854490..15a3cf3ae 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -249,6 +249,9 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 	if (dev->driver != NULL)
 		return 0;
 
+	if (rte_pci_devargs_process(dev) < 0)
+		return -1;
+
 	FOREACH_DRIVER_ON_PCIBUS(dr) {
 		rc = rte_pci_probe_one_driver(dr, dev);
 		if (rc < 0)
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 56bb653fc..effa73606 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -127,3 +127,13 @@ rte_pci_devargs_prepare(struct rte_devargs *da)
 	rte_kvargs_free(kvargs);
 	return ret;
 }
+
+int
+rte_pci_devargs_process(struct rte_pci_device *pdev)
+{
+	/* For the moment, no PCI param
+	 * needs to be processed.
+	 */
+	(void) pdev;
+	return 0;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 9beb24c6a..06dc85e85 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -207,4 +207,17 @@ rte_pci_dev_iterate(const void *start,
 int
 rte_pci_devargs_prepare(struct rte_devargs *da);
 
+/*
+ * Process the device devargs, if any.
+ *
+ * @param pdev
+ *   PCI device
+ *
+ * @return
+ *   0 on success.
+ *   <0 on error.
+ */
+int
+rte_pci_devargs_process(struct rte_pci_device *pdev);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 26/27] ethdev: process declarative eth devargs
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (24 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 25/27] bus/pci: process declarative PCI devargs Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 27/27] eal: add generic dev parameter Gaetan Rivet
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Process the class-specific arguments in a devargs.
This processing takes the form of setting the proper eth_dev fields when
relevant.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/eth_private.h   |  5 +++
 lib/librte_ethdev/rte_class_eth.c | 61 +++++++++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.c    |  7 ++++
 3 files changed, 73 insertions(+)

diff --git a/lib/librte_ethdev/eth_private.h b/lib/librte_ethdev/eth_private.h
index 0f5c6d5c4..c0c065165 100644
--- a/lib/librte_ethdev/eth_private.h
+++ b/lib/librte_ethdev/eth_private.h
@@ -19,6 +19,11 @@ struct rte_eth_dev *
 eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
 		const void *data);
 
+/* Generic rte_eth_dev parameters processor. */
+int
+rte_eth_dev_args_parse(struct rte_eth_dev *eth_dev,
+		       struct rte_devargs *da);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
index d8d8e8845..f02b6fd6a 100644
--- a/lib/librte_ethdev/rte_class_eth.c
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -35,6 +35,19 @@ struct eth_dev_match_arg {
 		.kvlist = (k), \
 	})
 
+typedef int (*eth_dev_set_t)(struct rte_eth_dev *edev, const char *value);
+
+static enum eth_params
+ethdev_param_id(const char *key)
+{
+	int i;
+
+	for (i = 0; i < RTE_ETH_PARAMS_MAX; i++)
+		if (strcmp(key, eth_params_keys[i]) == 0)
+			return i;
+	return RTE_ETH_PARAMS_MAX;
+}
+
 static int
 eth_dev_match(const struct rte_eth_dev *edev,
 	      const void *_arg)
@@ -79,6 +92,54 @@ eth_dev_iterate(const void *start,
 	return edev;
 }
 
+static int
+eth_dev_set_name(struct rte_eth_dev *edev,
+		 const char *value)
+{
+	snprintf(edev->data->name,
+		 sizeof(edev->data->name),
+		 "%s", value);
+	return 0;
+}
+
+static int
+ethdev_args_process(const char *key,
+		    const char *value,
+		    void *_edev)
+{
+	static eth_dev_set_t eth_dev_set[] = {
+		[RTE_ETH_PARAMS_NAME] = eth_dev_set_name,
+		[RTE_ETH_PARAMS_MAX] = NULL,
+	};
+	struct rte_eth_dev *edev = _edev;
+	int param;
+
+	param = ethdev_param_id(key);
+	if (eth_dev_set[param])
+		return eth_dev_set[param](edev, value);
+	return 0;
+}
+
+int
+rte_eth_dev_args_parse(struct rte_eth_dev *edev,
+		       struct rte_devargs *da)
+{
+	struct rte_kvargs *kvargs = NULL;
+
+	if (da == NULL || da->clsstr == NULL)
+		return 0;
+
+	kvargs = rte_kvargs_parse2(da->clsstr, eth_params_keys, "/");
+	if (kvargs == NULL) {
+		RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+		return -EINVAL;
+	}
+	if (rte_kvargs_process(kvargs, NULL, ethdev_args_process, edev))
+		return -1;
+	rte_kvargs_free(kvargs);
+	return 0;
+}
+
 struct rte_class rte_class_eth = {
 	.dev_iterate = eth_dev_iterate,
 };
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index cce20d9ae..4583509dd 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -41,6 +41,7 @@
 #include "rte_ethdev.h"
 #include "rte_ethdev_driver.h"
 #include "ethdev_profile.h"
+#include "eth_private.h"
 
 static int ethdev_logtype;
 
@@ -3594,6 +3595,12 @@ rte_eth_dev_create(struct rte_device *device, const char *name,
 		}
 	}
 
+	retval = rte_eth_dev_args_parse(ethdev, device->devargs);
+	if (retval) {
+		RTE_LOG(ERR, EAL, "ethdev parsing failed");
+		goto probe_failed;
+	}
+
 	retval = ethdev_init(ethdev, init_params);
 	if (retval) {
 		RTE_LOG(ERR, EAL, "ethdev initialisation failed");
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v10 27/27] eal: add generic dev parameter
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
                     ` (25 preceding siblings ...)
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 26/27] ethdev: process declarative eth devargs Gaetan Rivet
@ 2018-07-05 11:48   ` Gaetan Rivet
  26 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-05 11:48 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Add the --dev parameter to the EAL.
This new parameter takes a generic device declaration as argument.

It uses the new devargs parsing API.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_devargs.c |  4 +++
 lib/librte_eal/common/eal_common_options.c | 36 +++++++++++++++++++---
 lib/librte_eal/common/eal_options.h        |  2 ++
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 5f89e0b6e..bc3ba9fe0 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -218,6 +218,10 @@ rte_devargs_parse(struct rte_devargs *da, const char *dev)
 	if (da == NULL)
 		return -EINVAL;
 
+	if (strncmp(dev, "bus=", 4) == 0 ||
+	    strncmp(dev, "class=", 6) == 0)
+		return rte_devargs_layers_parse(da, dev);
+
 	/* Retrieve eventual bus info */
 	do {
 		devname = dev;
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index ecebb2923..89d608180 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -54,6 +54,7 @@ const struct option
 eal_long_options[] = {
 	{OPT_BASE_VIRTADDR,     1, NULL, OPT_BASE_VIRTADDR_NUM    },
 	{OPT_CREATE_UIO_DEV,    0, NULL, OPT_CREATE_UIO_DEV_NUM   },
+	{OPT_DEV,               1, NULL, OPT_DEV_NUM              },
 	{OPT_FILE_PREFIX,       1, NULL, OPT_FILE_PREFIX_NUM      },
 	{OPT_HELP,              0, NULL, OPT_HELP_NUM             },
 	{OPT_HUGE_DIR,          1, NULL, OPT_HUGE_DIR_NUM         },
@@ -109,6 +110,7 @@ TAILQ_HEAD(device_option_list, device_option);
 struct device_option {
 	TAILQ_ENTRY(device_option) next;
 
+	int new;
 	enum rte_devtype type;
 	char arg[];
 };
@@ -121,7 +123,8 @@ static int mem_parsed;
 static int core_parsed;
 
 static int
-eal_option_device_add(enum rte_devtype type, const char *optarg)
+eal_option_device_add(enum rte_devtype type, const char *optarg,
+		      int new)
 {
 	struct device_option *devopt;
 	size_t optlen;
@@ -135,6 +138,7 @@ eal_option_device_add(enum rte_devtype type, const char *optarg)
 	}
 
 	devopt->type = type;
+	devopt->new = new;
 	ret = snprintf(devopt->arg, optlen, "%s", optarg);
 	if (ret < 0) {
 		RTE_LOG(ERR, EAL, "Unable to copy device option\n");
@@ -154,7 +158,22 @@ eal_option_device_parse(void)
 
 	TAILQ_FOREACH_SAFE(devopt, &devopt_list, next, tmp) {
 		if (ret == 0) {
-			ret = rte_devargs_add(devopt->type, devopt->arg);
+			if (devopt->new) {
+				struct rte_devargs *da;
+
+				da = calloc(1, sizeof(*da));
+				ret = rte_devargs_parse(da, devopt->arg);
+				if (ret) {
+					free(da);
+				} else {
+					ret = rte_devargs_insert(da);
+					if (ret)
+						free(da);
+				}
+			} else {
+				ret = rte_devargs_add(devopt->type,
+						      devopt->arg);
+			}
 			if (ret)
 				RTE_LOG(ERR, EAL, "Unable to parse device '%s'\n",
 					devopt->arg);
@@ -1038,7 +1057,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		if (w_used)
 			goto bw_used;
 		if (eal_option_device_add(RTE_DEVTYPE_BLACKLISTED_PCI,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		b_used = 1;
@@ -1048,7 +1067,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		if (b_used)
 			goto bw_used;
 		if (eal_option_device_add(RTE_DEVTYPE_WHITELISTED_PCI,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		w_used = 1;
@@ -1177,9 +1196,16 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_DEV_NUM:
+		if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
+				optarg, 1) < 0) {
+			return -1;
+		}
+		break;
+
 	case OPT_VDEV_NUM:
 		if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		break;
diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h
index 211ae06ae..b1851864f 100644
--- a/lib/librte_eal/common/eal_options.h
+++ b/lib/librte_eal/common/eal_options.h
@@ -21,6 +21,8 @@ enum {
 	OPT_BASE_VIRTADDR_NUM,
 #define OPT_CREATE_UIO_DEV    "create-uio-dev"
 	OPT_CREATE_UIO_DEV_NUM,
+#define OPT_DEV               "dev"
+	OPT_DEV_NUM,
 #define OPT_FILE_PREFIX       "file-prefix"
 	OPT_FILE_PREFIX_NUM,
 #define OPT_HUGE_DIR          "huge-dir"
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class
  2018-07-05 11:13         ` Bruce Richardson
@ 2018-07-05 11:54           ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-07-05 11:54 UTC (permalink / raw)
  To: Bruce Richardson; +Cc: Andrew Rybchenko, dev

On Thu, Jul 05, 2018 at 12:13:56PM +0100, Bruce Richardson wrote:
> On Thu, Jul 05, 2018 at 11:36:38AM +0200, Gaëtan Rivet wrote:
> > Hi Andrew,
> > 
> > On Wed, Jul 04, 2018 at 03:20:17PM +0300, Andrew Rybchenko wrote:
> > > On 07/04/2018 01:15 AM, Gaetan Rivet wrote:
> > > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > > > ---
> > > >   lib/librte_ethdev/Makefile        |  3 +-
> > > >   lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++++++++++
> > > >   2 files changed, 81 insertions(+), 1 deletion(-)
> > > >   create mode 100644 lib/librte_ethdev/rte_class_eth.c
> > > > 
> > > > diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
> > > > index 2fa133fbc..d4c3a8d06 100644
> > > > --- a/lib/librte_ethdev/Makefile
> > > > +++ b/lib/librte_ethdev/Makefile
> > > > @@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
> > > >   CFLAGS += -O3
> > > >   CFLAGS += $(WERROR_FLAGS)
> > > >   LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
> > > > -LDLIBS += -lrte_mbuf
> > > > +LDLIBS += -lrte_mbuf -lrte_kvargs
> > > >   EXPORT_MAP := rte_ethdev_version.map
> > > > @@ -20,6 +20,7 @@ LIBABIVER := 9
> > > >   SRCS-y += eth_private.c
> > > >   SRCS-y += rte_ethdev.c
> > > > +SRCS-y += rte_class_eth.c
> > > >   SRCS-y += rte_flow.c
> > > >   SRCS-y += rte_tm.c
> > > >   SRCS-y += rte_mtr.c
> > > 
> > > meson.build files should be updated as well.
> > 
> > The meson version required by DPDK is not available in my distribution.
> > 
> "pip3 install meson" works in just about all distros. I'd recommend using
> meson from pip generally, since it tends to be very up to date. The latest
> versions configure DPDK a lot faster than the older ones!
> 
> /Bruce

Thanks,

The v10 now supports meson.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function Gaetan Rivet
@ 2018-07-05 14:44     ` Thomas Monjalon
  2018-07-11 11:46     ` Shreyansh Jain
  1 sibling, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-05 14:44 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

05/07/2018 13:48, Gaetan Rivet:
> rte_devargs_parse becomes non-variadic,
> rte_devargs_parsef becomes the variadic version, to be used to compose
> device strings.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

Acked-by: Thomas Monjalon <thomas@monjalon.net>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 03/27] kvargs: build before EAL
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 03/27] kvargs: build before EAL Gaetan Rivet
@ 2018-07-05 21:50     ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-05 21:50 UTC (permalink / raw)
  To: gaetan.rivet; +Cc: dev

05/07/2018 13:48, Gaetan Rivet:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

You should add a commit log to explain the intent:
kvargs will be used in EAL for devargs parsing.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 02/27] kvargs: remove error logs
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 02/27] kvargs: remove error logs Gaetan Rivet
@ 2018-07-05 21:51     ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-05 21:51 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev, olivier.matz

05/07/2018 13:48, Gaetan Rivet:
> Error logs in kvargs parsing should be better handled in components
> calling the library.
> 
> This library must be as lean as possible.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

Acked-by: Thomas Monjalon <thomas@monjalon.net>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 04/27] kvargs: introduce a more flexible parsing function
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 04/27] kvargs: introduce a more flexible parsing function Gaetan Rivet
@ 2018-07-05 22:00     ` Thomas Monjalon
  2018-07-11 11:55       ` Shreyansh Jain
  0 siblings, 1 reply; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-05 22:00 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev, olivier.matz

05/07/2018 13:48, Gaetan Rivet:
> This function permits defining additional terminating characters,
> ending the parsing to arbitrary delimiters.
[...]
> +__rte_experimental
> +struct rte_kvargs *rte_kvargs_parse2(const char *args,
> +		const char *const valid_keys[],
> +		const char *valid_ends);

The name is not ideal but I don't have a better idea.

Acked-by: Thomas Monjalon <thomas@monjalon.net>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros Gaetan Rivet
@ 2018-07-06  4:17     ` Shreyansh Jain
  2018-07-10 11:40     ` Thomas Monjalon
  1 sibling, 0 replies; 364+ messages in thread
From: Shreyansh Jain @ 2018-07-06  4:17 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Thursday 05 July 2018 05:18 PM, Gaetan Rivet wrote:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>   lib/librte_eal/common/include/rte_common.h | 23 ++++++++++++++++++++++
>   1 file changed, 23 insertions(+)
> 
> diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
> index 434adfd45..0dd832728 100644
> --- a/lib/librte_eal/common/include/rte_common.h
> +++ b/lib/librte_eal/common/include/rte_common.h
> @@ -111,6 +111,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
>   #define RTE_INIT(func) \
>   	RTE_INIT_PRIO(func, LAST)
>   

Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros Gaetan Rivet
  2018-07-06  4:17     ` Shreyansh Jain
@ 2018-07-10 11:40     ` Thomas Monjalon
  2018-07-10 12:56       ` Gaëtan Rivet
  1 sibling, 1 reply; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-10 11:40 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev, shreyansh.jain

05/07/2018 13:48, Gaetan Rivet:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

Please justify why you need destructors, by providing a commit log.

> --- a/lib/librte_eal/common/include/rte_common.h
> +++ b/lib/librte_eal/common/include/rte_common.h
> @@ -111,6 +111,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
>  #define RTE_INIT(func) \
>  	RTE_INIT_PRIO(func, LAST)
>  
> +/**
> + * Run after main() with low priority.
> + *
> + * @param func
> + *   Destructor function name.
> + * @param prio
> + *   Priority number must be above 100.
> + *   Lowest number is the last to run.
> + */
> +#define RTE_FINI_PRIO(func, prio) \
> +static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)

I don't like the name of this macro.
What about RTE_CLEAN_PRIO?

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros
  2018-07-10 11:40     ` Thomas Monjalon
@ 2018-07-10 12:56       ` Gaëtan Rivet
  2018-07-10 13:06         ` Thomas Monjalon
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-07-10 12:56 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev, shreyansh.jain

Hi Thomas,

On Tue, Jul 10, 2018 at 01:40:01PM +0200, Thomas Monjalon wrote:
> 05/07/2018 13:48, Gaetan Rivet:
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> 
> Please justify why you need destructors, by providing a commit log.
> 
> > --- a/lib/librte_eal/common/include/rte_common.h
> > +++ b/lib/librte_eal/common/include/rte_common.h
> > @@ -111,6 +111,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> >  #define RTE_INIT(func) \
> >  	RTE_INIT_PRIO(func, LAST)
> >  
> > +/**
> > + * Run after main() with low priority.
> > + *
> > + * @param func
> > + *   Destructor function name.
> > + * @param prio
> > + *   Priority number must be above 100.
> > + *   Lowest number is the last to run.
> > + */
> > +#define RTE_FINI_PRIO(func, prio) \
> > +static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
> 
> I don't like the name of this macro.
> What about RTE_CLEAN_PRIO?
> 
> 

FINI is symmetrical to INIT in referencing the related ELF section.

RTE_CLEAN presumes that the intended purpose of the function will be to
cleanup resources. As far as we are concerned, this code could send a
signal, dump config info or format / (which would be a pretty advanced
cleanup, granted).

Sometimes, it could be used to release resources, presumably.

I'm not a fan of FINI either, but I appreciate the symmetry.
It's pretty neutral about what it does, as its meaning is literally
"The following function will be part of the .fini section".

Alternatives:

   FINALIZE
   UNINIT

But they have the same issue as RTE_CLEAN, IMO.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros
  2018-07-10 12:56       ` Gaëtan Rivet
@ 2018-07-10 13:06         ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-10 13:06 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev, shreyansh.jain

10/07/2018 14:56, Gaëtan Rivet:
> Hi Thomas,
> 
> On Tue, Jul 10, 2018 at 01:40:01PM +0200, Thomas Monjalon wrote:
> > 05/07/2018 13:48, Gaetan Rivet:
> > > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > 
> > Please justify why you need destructors, by providing a commit log.
> > 
> > > --- a/lib/librte_eal/common/include/rte_common.h
> > > +++ b/lib/librte_eal/common/include/rte_common.h
> > > @@ -111,6 +111,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
> > >  #define RTE_INIT(func) \
> > >  	RTE_INIT_PRIO(func, LAST)
> > >  
> > > +/**
> > > + * Run after main() with low priority.
> > > + *
> > > + * @param func
> > > + *   Destructor function name.
> > > + * @param prio
> > > + *   Priority number must be above 100.
> > > + *   Lowest number is the last to run.
> > > + */
> > > +#define RTE_FINI_PRIO(func, prio) \
> > > +static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
> > 
> > I don't like the name of this macro.
> > What about RTE_CLEAN_PRIO?
> > 
> > 
> 
> FINI is symmetrical to INIT in referencing the related ELF section.
> 
> RTE_CLEAN presumes that the intended purpose of the function will be to
> cleanup resources. As far as we are concerned, this code could send a
> signal, dump config info or format / (which would be a pretty advanced
> cleanup, granted).
> 
> Sometimes, it could be used to release resources, presumably.
> 
> I'm not a fan of FINI either, but I appreciate the symmetry.
> It's pretty neutral about what it does, as its meaning is literally
> "The following function will be part of the .fini section".
> 
> Alternatives:
> 
>    FINALIZE
>    UNINIT
> 
> But they have the same issue as RTE_CLEAN, IMO.

OK, you convinced me. And I remember now that you already convinced
me earlier with the same argument :)

Acked-by: Thomas Monjalon <thomas@monjalon.net>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 22/27] app/testpmd: add show device command
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 22/27] app/testpmd: add show device command Gaetan Rivet
@ 2018-07-10 14:45     ` Iremonger, Bernard
  0 siblings, 0 replies; 364+ messages in thread
From: Iremonger, Bernard @ 2018-07-10 14:45 UTC (permalink / raw)
  To: Gaetan Rivet, dev

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Gaetan Rivet
> Sent: Thursday, July 5, 2018 12:48 PM
> To: dev@dpdk.org
> Cc: Gaetan Rivet <gaetan.rivet@6wind.com>
> Subject: [dpdk-dev] [PATCH v10 22/27] app/testpmd: add show device
> command
> 
> A new interactive command is offered:
> 
>    show device <device description>
> 
> This commands lists all rte_device element matching the device description.
> e.g.:
> 
>    show device bus=pci
>    show device bus=vdev
>    show device bus=vdev/class=eth
>    show device bus=vdev,driver=net_ring/class=eth
>    show device bus=vdev/class=eth,name=net_ring0
> 
> These devices may not be otherwise useful, some buses will spawn devices
> to keep track of their assets without having a driver to use them.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

Acked-by: Bernard Iremonger <bernard.iremonger@intel.com>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 06/27] eal: introduce device class abstraction
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 06/27] eal: introduce device class abstraction Gaetan Rivet
@ 2018-07-11  8:10     ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-11  8:10 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

05/07/2018 13:48, Gaetan Rivet:
> +/**
> + * @file
> + *
> + * DPDK device class interface.
> + *
> + * This file exposes API and interfaces of device classes.

What is the difference between "API" and "interfaces"?
I think you need to explain what is a device class.
You can mention examples ethdev and cryptodev.

> +#define RTE_REGISTER_CLASS(nm, cls) \
> +RTE_INIT_PRIO(classinitfn_ ##nm, CLASS); \

If you remove the ; you can avoid next line.
See this patch which removes such useless line:
	https://patches.dpdk.org/patch/41228/

> +static void classinitfn_ ##nm(void) \
> +{\
> +	(cls).name = RTE_STR(nm);\

Better to insert a space before \

> +	rte_class_register(&cls); \
> +}

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 07/27] eal/class: register destructor
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 07/27] eal/class: register destructor Gaetan Rivet
@ 2018-07-11  8:12     ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-11  8:12 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

05/07/2018 13:48, Gaetan Rivet:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>

If there is no specific comment, this patch can be squashed.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers Gaetan Rivet
@ 2018-07-11  8:19     ` Thomas Monjalon
  2018-07-11  8:41       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-11  8:19 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

05/07/2018 13:48, Gaetan Rivet:
> +/**
> + * @internal
> + * Parse a device string and store its information in an
> + * rte_devargs structure.

Please, explain what is a layer.

> + *
> + * Note: if the "data" field of da points to devstr,

Better to use "devargs" as variable name, instead of "da".

> + * 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 *da,
> +			 const char *devstr);
> +
>  #endif /* _EAL_PRIVATE_H_ */
> diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
> index 6c3b6326b..148600258 100644
> --- a/lib/librte_eal/common/include/rte_devargs.h
> +++ b/lib/librte_eal/common/include/rte_devargs.h
> @@ -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 *drvstr;
> +	};
> +	struct rte_bus *bus; /**< bus handle. */
> +	struct rte_class *cls; /**< class handle. */

"class" is more readable than "cls"

> +	const char *busstr; /**< bus-related part of device string. */

bus_str ?

> +	const char *clsstr; /**< bus-related part of device string. */

class_str ?
+ there is a typo in the comment (copy/pasted "bus")

> +	const char *data; /**< Device string storage. */
>  };

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers
  2018-07-11  8:19     ` Thomas Monjalon
@ 2018-07-11  8:41       ` Gaëtan Rivet
  2018-07-11  9:30         ` Thomas Monjalon
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-07-11  8:41 UTC (permalink / raw)
  To: Thomas Monjalon; +Cc: dev

Hi Thomas,

On Wed, Jul 11, 2018 at 10:19:07AM +0200, Thomas Monjalon wrote:
> 05/07/2018 13:48, Gaetan Rivet:
> > +/**
> > + * @internal
> > + * Parse a device string and store its information in an
> > + * rte_devargs structure.
> 
> Please, explain what is a layer.
> 
> > + *
> > + * Note: if the "data" field of da points to devstr,
> 
> Better to use "devargs" as variable name, instead of "da".
> 
> > + * 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 *da,
> > +			 const char *devstr);
> > +
> >  #endif /* _EAL_PRIVATE_H_ */
> > diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
> > index 6c3b6326b..148600258 100644
> > --- a/lib/librte_eal/common/include/rte_devargs.h
> > +++ b/lib/librte_eal/common/include/rte_devargs.h
> > @@ -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 *drvstr;
> > +	};
> > +	struct rte_bus *bus; /**< bus handle. */
> > +	struct rte_class *cls; /**< class handle. */
> 
> "class" is more readable than "cls"
> 

I was thinking that maybe this could be a problem when trying to build
with C++. The EAL headers in DPDK are meant to be included in C++ apps,
I think ``class`` would be an issue then.

If I'm mistaken, then sure, class is a better name.

> > +	const char *busstr; /**< bus-related part of device string. */
> 
> bus_str ?
> 
> > +	const char *clsstr; /**< bus-related part of device string. */
> 
> class_str ?
> + there is a typo in the comment (copy/pasted "bus")
> 
> > +	const char *data; /**< Device string storage. */
> >  };
> 
> 
> 

Otherwise, ok with the rest of the comments, will fix (as well as the
previous emails). Thanks for reading.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers
  2018-07-11  8:41       ` Gaëtan Rivet
@ 2018-07-11  9:30         ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-11  9:30 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev

11/07/2018 10:41, Gaëtan Rivet:
> > > +	struct rte_bus *bus; /**< bus handle. */
> > > +	struct rte_class *cls; /**< class handle. */
> > 
> > "class" is more readable than "cls"
> > 
> 
> I was thinking that maybe this could be a problem when trying to build
> with C++. The EAL headers in DPDK are meant to be included in C++ apps,
> I think ``class`` would be an issue then.

Yes, right.

So only options are "cls" or "devclass".
Up to you.

> If I'm mistaken, then sure, class is a better name.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 10/27] eal/class: add device iteration
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 10/27] eal/class: add device iteration Gaetan Rivet
@ 2018-07-11  9:47     ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-11  9:47 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

05/07/2018 13:48, Gaetan Rivet:
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>  lib/librte_eal/common/include/rte_class.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
> index e8176f5e1..9d5b06807 100644
> --- a/lib/librte_eal/common/include/rte_class.h
> +++ b/lib/librte_eal/common/include/rte_class.h
> @@ -30,6 +30,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
>  struct rte_class {
>  	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
>  	const char *name; /**< Name of the class */
> +	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
>  };

Patches 10 and 11 can be squashed in 9.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function
  2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function Gaetan Rivet
  2018-07-05 14:44     ` Thomas Monjalon
@ 2018-07-11 11:46     ` Shreyansh Jain
  2018-07-11 12:01       ` Gaëtan Rivet
  1 sibling, 1 reply; 364+ messages in thread
From: Shreyansh Jain @ 2018-07-11 11:46 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Thursday 05 July 2018 05:18 PM, Gaetan Rivet wrote:
> rte_devargs_parse becomes non-variadic,
> rte_devargs_parsef becomes the variadic version, to be used to compose
> device strings.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>   drivers/net/failsafe/failsafe_args.c        |  2 +-
>   drivers/net/failsafe/failsafe_eal.c         |  2 +-
>   lib/librte_eal/common/eal_common_dev.c      |  4 +-
>   lib/librte_eal/common/eal_common_devargs.c  | 42 ++++++++++++++++-----
>   lib/librte_eal/common/include/rte_devargs.h | 40 +++++++++++++++++++-
>   lib/librte_eal/rte_eal_version.map          |  1 +
>   lib/librte_ethdev/rte_ethdev.c              |  2 +-
>   7 files changed, 76 insertions(+), 17 deletions(-)
> 

[...]

> +__rte_experimental
> +int
> +rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
> +{
> +	va_list ap;
> +	size_t len;
> +	char *dev;
> +
> +	if (da == NULL)
> +		return -EINVAL;
> +
> +	va_start(ap, format);
> +	len = vsnprintf(NULL, 0, format, ap);
> +	va_end(ap);
> +
> +	dev = calloc(1, len + 1);
> +	if (dev == NULL) {
> +		fprintf(stderr, "ERROR: not enough memory to parse device\n");

Should RTE_LOG be used here?

> +		return -ENOMEM;
> +	}
> +
> +	va_start(ap, format);
> +	vsnprintf(dev, len, format, ap);
> +	va_end(ap);
> +
> +	return rte_devargs_parse(da, dev);
> +}
> +
>   int __rte_experimental
>   rte_devargs_insert(struct rte_devargs *da)
>   {

[...]

Except the comment above:

Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 04/27] kvargs: introduce a more flexible parsing function
  2018-07-05 22:00     ` Thomas Monjalon
@ 2018-07-11 11:55       ` Shreyansh Jain
  0 siblings, 0 replies; 364+ messages in thread
From: Shreyansh Jain @ 2018-07-11 11:55 UTC (permalink / raw)
  To: Thomas Monjalon, Gaetan Rivet; +Cc: dev, olivier.matz

On Friday 06 July 2018 03:30 AM, Thomas Monjalon wrote:
> 05/07/2018 13:48, Gaetan Rivet:
>> This function permits defining additional terminating characters,
>> ending the parsing to arbitrary delimiters.
> [...]
>> +__rte_experimental
>> +struct rte_kvargs *rte_kvargs_parse2(const char *args,
>> +		const char *const valid_keys[],
>> +		const char *valid_ends);
> 
> The name is not ideal but I don't have a better idea.
> 
Does 'rte_kvargs_parse_delim()' seem any better?
Or, a more obvious one 'rte_kvargs_parse_with_delim()'.

[...]

As I am already late in commenting on this, I am OK changing this later 
as well (using the 'experimental' blanket) when a better suggestion 
comes along. So, from me as well:

Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function
  2018-07-11 11:46     ` Shreyansh Jain
@ 2018-07-11 12:01       ` Gaëtan Rivet
  0 siblings, 0 replies; 364+ messages in thread
From: Gaëtan Rivet @ 2018-07-11 12:01 UTC (permalink / raw)
  To: Shreyansh Jain; +Cc: dev

On Wed, Jul 11, 2018 at 05:16:15PM +0530, Shreyansh Jain wrote:
> On Thursday 05 July 2018 05:18 PM, Gaetan Rivet wrote:
> > rte_devargs_parse becomes non-variadic,
> > rte_devargs_parsef becomes the variadic version, to be used to compose
> > device strings.
> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >   drivers/net/failsafe/failsafe_args.c        |  2 +-
> >   drivers/net/failsafe/failsafe_eal.c         |  2 +-
> >   lib/librte_eal/common/eal_common_dev.c      |  4 +-
> >   lib/librte_eal/common/eal_common_devargs.c  | 42 ++++++++++++++++-----
> >   lib/librte_eal/common/include/rte_devargs.h | 40 +++++++++++++++++++-
> >   lib/librte_eal/rte_eal_version.map          |  1 +
> >   lib/librte_ethdev/rte_ethdev.c              |  2 +-
> >   7 files changed, 76 insertions(+), 17 deletions(-)
> > 
> 
> [...]
> 
> > +__rte_experimental
> > +int
> > +rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
> > +{
> > +	va_list ap;
> > +	size_t len;
> > +	char *dev;
> > +
> > +	if (da == NULL)
> > +		return -EINVAL;
> > +
> > +	va_start(ap, format);
> > +	len = vsnprintf(NULL, 0, format, ap);
> > +	va_end(ap);
> > +
> > +	dev = calloc(1, len + 1);
> > +	if (dev == NULL) {
> > +		fprintf(stderr, "ERROR: not enough memory to parse device\n");
> 
> Should RTE_LOG be used here?
> 

Yes, actually, I think the whole rte_devargs should be changed to
RTE_LOG.

> > +		return -ENOMEM;
> > +	}
> > +
> > +	va_start(ap, format);
> > +	vsnprintf(dev, len, format, ap);
> > +	va_end(ap);
> > +
> > +	return rte_devargs_parse(da, dev);
> > +}
> > +
> >   int __rte_experimental
> >   rte_devargs_insert(struct rte_devargs *da)
> >   {
> 
> [...]
> 
> Except the comment above:
> 
> Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 00/25] Device querying
  2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
                   ` (24 preceding siblings ...)
  2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
@ 2018-07-11 21:44 ` Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 01/25] devargs: use rte-log functions Gaetan Rivet
                     ` (25 more replies)
  25 siblings, 26 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev
  Cc: Gaetan Rivet, Neil Horman, Shreyansh Jain, Bruce Richardson,
	Andrew Rybchenko

This patchset introduces a new EAL API for querying devices,
filtered by arbitrary properties.

The following elements are introduced to this end:

 * A new object, "rte_class", is used to describe
   the device class abstraction layer (eth, crypto, ...).

 * Both rte_bus and rte_class now offer a way to
   list their devices and filter the result
   using locally defined properties.

 * The rte_dev API now has an rte_dev_iterator, which
   is the way for the user to define the device filter
   and iterate upon the resulting set.

As an example, the "eth" device class is implemented.

Additionally, the device filters for

  + rte_bus_pci
  + rte_bus_vdev
  + rte_class_eth

are implemented and can be used with some
properties each, to show how to extend those.

Some example of filters:

  "bus=pci/class=eth"
  "bus=pci"
  "class=eth"
  "class=eth,name=net_ring0"
  "bus=pci,id=00:00.0"
  "bus=vdev,driver=net_ring"

---

v2:

  * Reworked the dev_iterate callback to simplify
    its implementation.

    Now dev_iterate implementation do not need to learn
    about the intricacies of the rte_dev_iterator.
    The rte_dev_iterator is managed purely by the
    rte_dev_iterator_next function. Buses and classes then
    do not have to care about settings things right.

    Additionally, dev_iterate implementations do not
    have to sanitize their dev string anymore, they
    are prepared by the rte_dev layer prior, which also
    reduces the number of dynamic allocations.

v3:

  * Introduced central constructor priority list.
  * Removed lightweight kvarg parsing utility,
    using librte_kvargs instead.
  * Reversed dependencies of librte_kvargs and
    librte_eal.
  * Fixed a few bugs.
  * @Bruce: I have noted the request for meson support.
    I will install it and attempt it once the bulk of the work is done.

v4:

  * Fixed a few bugs, added relevant acks,
    fixed some typos.
  * Made each matching functions actually check for a proper
    list of accepted properties.
  * rte_kvargs now includes rte_eal directly and keeps rte_log.
  * added generic string comparison function to rte_kvargs,
    as some kind of comparison should probably be shared by many layers.

v5:

  * Rebased on master
  * Use strcspn instead of custom function.
  * Introduce private generic rte_eth_dev iterator.
    This could be generalized to other iterators
    (port_next, owner_id-aware, etc).
  * Attempted to support meson.build.
    Got lost in the implicit variables declared
    when inversing dependencies between kvargs and EAL.
    Removed anything related to meson.
  * Postponed genericization of work from
    device query to device declaration.
    Much bigger than anticipated, will let this
    part get in first and iterate over it.

v6:

  * Rebased on master
  * Introduce RTE_PRIORITY_LAST, to explicitly set
    the lowest constructor priority.
  * Fix copyright notice for eth_privage.* files.

v7:

  * Rebased on master
  * Fix rte_kvargs_strcmp return value.
  * Fix layer parsing error
    devstr "bus=pci/onemorelayer" now tells
    that the additional layer is not recognized.

v8:

  * Rebased on master
  * Cleaned kvargs use: introduced
    a new parser function, that simplifies
    using the library for DPDK devargs.
  * Refactored devargs parsing in a single
    function within rte_devargs.
    This function is useful both for rte_dev
    parsing its iterator, and for rte_devargs
    parsing --dev parameters (not yet implemented).
  * A few small bugfixes.

v9:

  * Rebased on master
  * Fixed cyclic dependency kvargs <-> eal
  * Fixed a few checkpatch issues
  * Added dynamic help to testpmd for new "show device" command
  * Added devargs processing stubs to
    primary buses / classes
  * Added new --dev generic device declaration option

v10:

  * Support meson build

v11:

  * Some cleanup, rewriting of comments
    and commit logs.
  * New fields in devargs and dev_it renamed.

Gaetan Rivet (25):
  devargs: use rte-log functions
  devargs: add non-variadic parsing function
  kvargs: remove error logs
  kvargs: build before EAL
  kvargs: introduce a more flexible parsing function
  eal: introduce dtor macros
  eal: introduce device class abstraction
  devargs: add function to parse device layers
  eal/dev: add device iterator interface
  eal/dev: implement device iteration initialization
  eal/dev: implement device iteration
  kvargs: add generic string matching callback
  bus/pci: implement device iteration and comparison
  bus/pci: add device matching field id
  bus/vdev: implement device iteration
  bus/vdev: add device matching field driver
  ethdev: add private generic device iterator
  ethdev: register ether layer as a class
  ethdev: add device matching field name
  app/testpmd: add show device command
  bus/pci: pre-process declarative PCI devargs
  bus/vdev: pre-process declarative vdev devargs
  bus/pci: process declarative PCI devargs
  ethdev: process declarative eth devargs
  eal: add generic dev parameter

 app/test-pmd/cmdline.c                      |  54 +++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst |  24 +++
 drivers/bus/pci/Makefile                    |   3 +-
 drivers/bus/pci/bsd/pci.c                   |   5 +
 drivers/bus/pci/linux/pci.c                 |   5 +
 drivers/bus/pci/meson.build                 |   6 +-
 drivers/bus/pci/pci_common.c                |   6 +-
 drivers/bus/pci/pci_params.c                | 139 ++++++++++++
 drivers/bus/pci/private.h                   |  54 +++++
 drivers/bus/vdev/Makefile                   |   3 +-
 drivers/bus/vdev/meson.build                |   5 +-
 drivers/bus/vdev/vdev.c                     |  20 +-
 drivers/bus/vdev/vdev_params.c              | 112 ++++++++++
 drivers/bus/vdev/vdev_private.h             |  32 +++
 drivers/net/failsafe/failsafe_args.c        |   2 +-
 drivers/net/failsafe/failsafe_eal.c         |   2 +-
 lib/Makefile                                |   5 +-
 lib/librte_eal/bsdapp/eal/Makefile          |   2 +
 lib/librte_eal/common/Makefile              |   2 +-
 lib/librte_eal/common/eal_common_class.c    |  62 ++++++
 lib/librte_eal/common/eal_common_dev.c      | 227 +++++++++++++++++++-
 lib/librte_eal/common/eal_common_devargs.c  | 197 +++++++++++++++--
 lib/librte_eal/common/eal_common_options.c  |  36 +++-
 lib/librte_eal/common/eal_options.h         |   2 +
 lib/librte_eal/common/eal_private.h         |  34 +++
 lib/librte_eal/common/include/rte_bus.h     |   1 +
 lib/librte_eal/common/include/rte_class.h   | 132 ++++++++++++
 lib/librte_eal/common/include/rte_common.h  |  24 +++
 lib/librte_eal/common/include/rte_dev.h     |  97 +++++++++
 lib/librte_eal/common/include/rte_devargs.h |  53 ++++-
 lib/librte_eal/common/meson.build           |   2 +
 lib/librte_eal/linuxapp/eal/Makefile        |   2 +
 lib/librte_eal/meson.build                  |   1 +
 lib/librte_eal/rte_eal_version.map          |   5 +
 lib/librte_ethdev/Makefile                  |   4 +-
 lib/librte_ethdev/eth_private.c             |  31 +++
 lib/librte_ethdev/eth_private.h             |  31 +++
 lib/librte_ethdev/meson.build               |   4 +-
 lib/librte_ethdev/rte_class_eth.c           | 148 +++++++++++++
 lib/librte_ethdev/rte_ethdev.c              |   9 +-
 lib/librte_kvargs/Makefile                  |   2 +-
 lib/librte_kvargs/meson.build               |   5 +
 lib/librte_kvargs/rte_kvargs.c              |  57 +++--
 lib/librte_kvargs/rte_kvargs.h              |  58 +++++
 lib/librte_kvargs/rte_kvargs_version.map    |   8 +
 lib/meson.build                             |   8 +-
 46 files changed, 1654 insertions(+), 67 deletions(-)
 create mode 100644 drivers/bus/pci/pci_params.c
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 01/25] devargs: use rte-log functions
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 02/25] devargs: add non-variadic parsing function Gaetan Rivet
                     ` (24 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the standard EAL logging functions in rte_devargs.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_devargs.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index b0434158b..894749e40 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -16,6 +16,7 @@
 #include <rte_compat.h>
 #include <rte_dev.h>
 #include <rte_devargs.h>
+#include <rte_log.h>
 #include <rte_tailq.h>
 #include "eal_private.h"
 
@@ -96,7 +97,7 @@ rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
 		da->name[i] = devname[i];
 		i++;
 		if (i == maxlen) {
-			fprintf(stderr, "WARNING: Parsing \"%s\": device name should be shorter than %zu\n",
+			RTE_LOG(WARNING, EAL, "Parsing \"%s\": device name should be shorter than %zu\n",
 				dev, maxlen);
 			da->name[i - 1] = '\0';
 			return -EINVAL;
@@ -106,7 +107,7 @@ rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
 	if (bus == NULL) {
 		bus = rte_bus_find_by_device_name(da->name);
 		if (bus == NULL) {
-			fprintf(stderr, "ERROR: failed to parse device \"%s\"\n",
+			RTE_LOG(ERR, EAL, "failed to parse device \"%s\"\n",
 				da->name);
 			return -EFAULT;
 		}
@@ -118,7 +119,7 @@ rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
 	else
 		da->args = strdup("");
 	if (da->args == NULL) {
-		fprintf(stderr, "ERROR: not enough memory to parse arguments\n");
+		RTE_LOG(ERR, EAL, "not enough memory to parse arguments\n");
 		return -ENOMEM;
 	}
 	return 0;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 02/25] devargs: add non-variadic parsing function
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 01/25] devargs: use rte-log functions Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 03/25] kvargs: remove error logs Gaetan Rivet
                     ` (23 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose
device strings.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
---
 drivers/net/failsafe/failsafe_args.c        |  2 +-
 drivers/net/failsafe/failsafe_eal.c         |  2 +-
 lib/librte_eal/common/eal_common_dev.c      |  4 +-
 lib/librte_eal/common/eal_common_devargs.c  | 42 ++++++++++++++++-----
 lib/librte_eal/common/include/rte_devargs.h | 40 +++++++++++++++++++-
 lib/librte_eal/rte_eal_version.map          |  1 +
 lib/librte_ethdev/rte_ethdev.c              |  2 +-
 7 files changed, 76 insertions(+), 17 deletions(-)

diff --git a/drivers/net/failsafe/failsafe_args.c b/drivers/net/failsafe/failsafe_args.c
index 2c002b164..626883ce2 100644
--- a/drivers/net/failsafe/failsafe_args.c
+++ b/drivers/net/failsafe/failsafe_args.c
@@ -63,7 +63,7 @@ fs_parse_device(struct sub_device *sdev, char *args)
 
 	d = &sdev->devargs;
 	DEBUG("%s", args);
-	ret = rte_devargs_parse(d, "%s", args);
+	ret = rte_devargs_parse(d, args);
 	if (ret) {
 		DEBUG("devargs parsing failed with code %d", ret);
 		return ret;
diff --git a/drivers/net/failsafe/failsafe_eal.c b/drivers/net/failsafe/failsafe_eal.c
index 5672f3961..ce1633f13 100644
--- a/drivers/net/failsafe/failsafe_eal.c
+++ b/drivers/net/failsafe/failsafe_eal.c
@@ -86,7 +86,7 @@ fs_bus_init(struct rte_eth_dev *dev)
 			else
 				snprintf(devstr, sizeof(devstr), "%s",
 					 rte_eth_devices[pid].device->name);
-			ret = rte_devargs_parse(da, "%s", devstr);
+			ret = rte_devargs_parse(da, devstr);
 			if (ret) {
 				ERROR("Probed devargs parsing failed with code"
 				      " %d", ret);
diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 61cb3b162..ce4b51469 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -138,8 +138,8 @@ int __rte_experimental rte_eal_hotplug_add(const char *busname, const char *devn
 	if (da == NULL)
 		return -ENOMEM;
 
-	ret = rte_devargs_parse(da, "%s:%s,%s",
-				    busname, devname, devargs);
+	ret = rte_devargs_parsef(da, "%s:%s,%s",
+				 busname, devname, devargs);
 	if (ret)
 		goto err_devarg;
 
diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index 894749e40..f84f3d2cf 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -63,24 +63,18 @@ bus_name_cmp(const struct rte_bus *bus, const void *name)
 	return strncmp(bus->name, name, strlen(bus->name));
 }
 
-int __rte_experimental
-rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev)
 {
 	struct rte_bus *bus = NULL;
-	va_list ap;
-	va_start(ap, format);
-	char dev[vsnprintf(NULL, 0, format, ap) + 1];
 	const char *devname;
 	const size_t maxlen = sizeof(da->name);
 	size_t i;
 
-	va_end(ap);
 	if (da == NULL)
 		return -EINVAL;
 
-	va_start(ap, format);
-	vsnprintf(dev, sizeof(dev), format, ap);
-	va_end(ap);
 	/* Retrieve eventual bus info */
 	do {
 		devname = dev;
@@ -125,6 +119,34 @@ rte_devargs_parse(struct rte_devargs *da, const char *format, ...)
 	return 0;
 }
 
+__rte_experimental
+int
+rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
+{
+	va_list ap;
+	size_t len;
+	char *dev;
+
+	if (da == NULL)
+		return -EINVAL;
+
+	va_start(ap, format);
+	len = vsnprintf(NULL, 0, format, ap);
+	va_end(ap);
+
+	dev = calloc(1, len + 1);
+	if (dev == NULL) {
+		RTE_LOG(ERR, EAL, "not enough memory to parse device\n");
+		return -ENOMEM;
+	}
+
+	va_start(ap, format);
+	vsnprintf(dev, len, format, ap);
+	va_end(ap);
+
+	return rte_devargs_parse(da, dev);
+}
+
 int __rte_experimental
 rte_devargs_insert(struct rte_devargs *da)
 {
@@ -151,7 +173,7 @@ rte_devargs_add(enum rte_devtype devtype, const char *devargs_str)
 	if (devargs == NULL)
 		goto fail;
 
-	if (rte_devargs_parse(devargs, "%s", dev))
+	if (rte_devargs_parse(devargs, dev))
 		goto fail;
 	devargs->type = devtype;
 	bus = devargs->bus;
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 58fbd90a2..6c3b6326b 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -89,6 +89,42 @@ __rte_deprecated
 int rte_eal_parse_devargs_str(const char *devargs_str,
 				char **drvname, char **drvargs);
 
+/**
+ * Parse a device string.
+ *
+ * Verify that a bus is capable of handling the device passed
+ * in argument. Store which bus will handle the device, its name
+ * and the eventual device parameters.
+ *
+ * The syntax is:
+ *
+ *     bus:device_identifier,arg1=val1,arg2=val2
+ *
+ * where "bus:" is the bus name followed by any character separator.
+ * The bus name is optional. If no bus name is specified, each bus
+ * will attempt to recognize the device identifier. The first one
+ * to succeed will be used.
+ *
+ * Examples:
+ *
+ *     pci:0000:05.00.0,arg=val
+ *     05.00.0,arg=val
+ *     vdev:net_ring0
+ *
+ * @param da
+ *   The devargs structure holding the device information.
+ *
+ * @param dev
+ *   String describing a device.
+ *
+ * @return
+ *   - 0 on success.
+ *   - Negative errno on error.
+ */
+__rte_experimental
+int
+rte_devargs_parse(struct rte_devargs *da, const char *dev);
+
 /**
  * Parse a device string.
  *
@@ -124,8 +160,8 @@ int rte_eal_parse_devargs_str(const char *devargs_str,
  */
 __rte_experimental
 int
-rte_devargs_parse(struct rte_devargs *da,
-		  const char *format, ...)
+rte_devargs_parsef(struct rte_devargs *da,
+		   const char *format, ...)
 __attribute__((format(printf, 2, 0)));
 
 /**
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index f7dd0e7bc..1c4db72fa 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -254,6 +254,7 @@ EXPERIMENTAL {
 	rte_devargs_insert;
 	rte_devargs_next;
 	rte_devargs_parse;
+	rte_devargs_parsef;
 	rte_devargs_remove;
 	rte_devargs_type_count;
 	rte_eal_cleanup;
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index 16b8258a7..98e089e58 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -658,7 +658,7 @@ rte_eth_dev_attach(const char *devargs, uint16_t *port_id)
 	}
 
 	/* parse devargs */
-	if (rte_devargs_parse(&da, "%s", devargs))
+	if (rte_devargs_parse(&da, devargs))
 		goto err;
 
 	ret = rte_eal_hotplug_add(da.bus->name, da.name, da.args);
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 03/25] kvargs: remove error logs
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 01/25] devargs: use rte-log functions Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 02/25] devargs: add non-variadic parsing function Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 04/25] kvargs: build before EAL Gaetan Rivet
                     ` (22 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Error logs in kvargs parsing should be better handled in components
calling the library.

This library must be as lean as possible.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
---
 lib/librte_kvargs/rte_kvargs.c | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index d92a5f9dc..747f14964 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -6,7 +6,6 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include <rte_log.h>
 #include <rte_string_fns.h>
 
 #include "rte_kvargs.h"
@@ -28,29 +27,22 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)
 	 * to pass to rte_strsplit
 	 */
 	kvlist->str = strdup(params);
-	if (kvlist->str == NULL) {
-		RTE_LOG(ERR, PMD, "Cannot parse arguments: not enough memory\n");
+	if (kvlist->str == NULL)
 		return -1;
-	}
 
 	/* browse each key/value pair and add it in kvlist */
 	str = kvlist->str;
 	while ((str = strtok_r(str, RTE_KVARGS_PAIRS_DELIM, &ctx1)) != NULL) {
 
 		i = kvlist->count;
-		if (i >= RTE_KVARGS_MAX) {
-			RTE_LOG(ERR, PMD, "Cannot parse arguments: list full\n");
+		if (i >= RTE_KVARGS_MAX)
 			return -1;
-		}
 
 		kvlist->pairs[i].key = strtok_r(str, RTE_KVARGS_KV_DELIM, &ctx2);
 		kvlist->pairs[i].value = strtok_r(NULL, RTE_KVARGS_KV_DELIM, &ctx2);
-		if (kvlist->pairs[i].key == NULL || kvlist->pairs[i].value == NULL) {
-			RTE_LOG(ERR, PMD,
-				"Cannot parse arguments: wrong key or value\n"
-				"params=<%s>\n", params);
+		if (kvlist->pairs[i].key == NULL ||
+		    kvlist->pairs[i].value == NULL)
 			return -1;
-		}
 
 		kvlist->count++;
 		str = NULL;
@@ -89,12 +81,8 @@ check_for_valid_keys(struct rte_kvargs *kvlist,
 	for (i = 0; i < kvlist->count; i++) {
 		pair = &kvlist->pairs[i];
 		ret = is_valid_key(valid, pair->key);
-		if (!ret) {
-			RTE_LOG(ERR, PMD,
-				"Error parsing device, invalid key <%s>\n",
-				pair->key);
+		if (!ret)
 			return -1;
-		}
 	}
 	return 0;
 }
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 04/25] kvargs: build before EAL
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (2 preceding siblings ...)
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 03/25] kvargs: remove error logs Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 05/25] kvargs: introduce a more flexible parsing function Gaetan Rivet
                     ` (21 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This library will be used by the EAL to parse parameters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/Makefile                  | 3 +--
 lib/librte_eal/meson.build    | 1 +
 lib/librte_kvargs/Makefile    | 2 +-
 lib/librte_kvargs/meson.build | 3 +++
 lib/meson.build               | 8 ++++++--
 5 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/lib/Makefile b/lib/Makefile
index d82462ba2..e8e903c8f 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -4,6 +4,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
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
@@ -76,8 +77,6 @@ DEPDIRS-librte_flow_classify :=  librte_net librte_table librte_acl
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched
 DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net
 DEPDIRS-librte_sched += librte_timer
-DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
-DEPDIRS-librte_kvargs := librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor
 DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ethdev
 DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
diff --git a/lib/librte_eal/meson.build b/lib/librte_eal/meson.build
index 4aa63e3d0..259bb4464 100644
--- a/lib/librte_eal/meson.build
+++ b/lib/librte_eal/meson.build
@@ -24,6 +24,7 @@ endif
 version = 7  # the version of the EAL API
 allow_experimental_apis = true
 deps += 'compat'
+deps += 'kvargs'
 cflags += '-D_GNU_SOURCE'
 sources = common_sources + env_sources
 objs = common_objs + env_objs
diff --git a/lib/librte_kvargs/Makefile b/lib/librte_kvargs/Makefile
index 39d5ac33d..875939547 100644
--- a/lib/librte_kvargs/Makefile
+++ b/lib/librte_kvargs/Makefile
@@ -7,7 +7,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 LIB = librte_kvargs.a
 
 CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
-LDLIBS += -lrte_eal
+CFLAGS += -I$(RTE_SDK)/lib/librte_eal/common/include
 
 EXPORT_MAP := rte_kvargs_version.map
 
diff --git a/lib/librte_kvargs/meson.build b/lib/librte_kvargs/meson.build
index 0c5b9cb20..0a81e8da7 100644
--- a/lib/librte_kvargs/meson.build
+++ b/lib/librte_kvargs/meson.build
@@ -1,6 +1,9 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
+includes = [global_inc]
+includes += include_directories('../../../lib/librte_eal/common/include')
+
 version = 1
 sources = files('rte_kvargs.c')
 headers = files('rte_kvargs.h')
diff --git a/lib/meson.build b/lib/meson.build
index 9d11571f9..5f7eb310e 100644
--- a/lib/meson.build
+++ b/lib/meson.build
@@ -9,7 +9,8 @@
 # given as a dep, no need to mention ring. This is especially true for the
 # core libs which are widely reused, so their deps are kept to a minimum.
 libraries = [ 'compat', # just a header, used for versioning
-	'eal', 'ring', 'mempool', 'mbuf', 'net', 'kvargs', 'ethdev', 'pci', # core
+	'kvargs',
+	'eal', 'ring', 'mempool', 'mbuf', 'net', 'ethdev', 'pci', # core
 	'metrics', # bitrate/latency stats depends on this
 	'hash',    # efd depends on this
 	'timer',   # eventdev depends on this
@@ -41,9 +42,12 @@ foreach l:libraries
 	# external package/library requirements
 	ext_deps = []
 	deps = ['eal']   # eal is standard dependency except for itself
-	if l == 'eal'
+	if l == 'kvargs'
 		deps = []
 	endif
+	if l == 'eal'
+		deps = ['kvargs']
+	endif
 
 	dir_name = 'librte_' + l
 	subdir(dir_name)
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 05/25] kvargs: introduce a more flexible parsing function
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (3 preceding siblings ...)
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 04/25] kvargs: build before EAL Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 06/25] eal: introduce dtor macros Gaetan Rivet
                     ` (20 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function permits defining additional terminating characters,
ending the parsing to arbitrary delimiters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Thomas Monjalon <thomas@monjalon.net>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
 lib/Makefile                             |  1 +
 lib/librte_kvargs/meson.build            |  2 ++
 lib/librte_kvargs/rte_kvargs.c           | 25 ++++++++++++++++++
 lib/librte_kvargs/rte_kvargs.h           | 32 ++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  7 ++++++
 5 files changed, 67 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index e8e903c8f..8a65525cd 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -5,6 +5,7 @@ include $(RTE_SDK)/mk/rte.vars.mk
 
 DIRS-y += librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs
+DEPDIRS-librte_kvargs := librte_compat
 DIRS-$(CONFIG_RTE_LIBRTE_EAL) += librte_eal
 DIRS-$(CONFIG_RTE_LIBRTE_PCI) += librte_pci
 DEPDIRS-librte_pci := librte_eal
diff --git a/lib/librte_kvargs/meson.build b/lib/librte_kvargs/meson.build
index 0a81e8da7..a1c724961 100644
--- a/lib/librte_kvargs/meson.build
+++ b/lib/librte_kvargs/meson.build
@@ -7,3 +7,5 @@ includes += include_directories('../../../lib/librte_eal/common/include')
 version = 1
 sources = files('rte_kvargs.c')
 headers = files('rte_kvargs.h')
+
+deps += 'compat'
diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 747f14964..52262fe54 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -168,3 +168,28 @@ rte_kvargs_parse(const char *args, const char * const valid_keys[])
 
 	return kvlist;
 }
+
+__rte_experimental
+struct rte_kvargs *
+rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
+		       const char *valid_ends)
+{
+	struct rte_kvargs *kvlist = NULL;
+	char *copy;
+	size_t len;
+
+	if (valid_ends == NULL)
+		return rte_kvargs_parse(args, valid_keys);
+
+	copy = strdup(args);
+	if (copy == NULL)
+		return NULL;
+
+	len = strcspn(copy, valid_ends);
+	copy[len] = '\0';
+
+	kvlist = rte_kvargs_parse(copy, valid_keys);
+
+	free(copy);
+	return kvlist;
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 51b8120b8..7f32fd1f6 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -25,6 +25,8 @@
 extern "C" {
 #endif
 
+#include <rte_compat.h>
+
 /** Maximum number of key/value associations */
 #define RTE_KVARGS_MAX 32
 
@@ -71,6 +73,36 @@ struct rte_kvargs {
 struct rte_kvargs *rte_kvargs_parse(const char *args,
 		const char *const valid_keys[]);
 
+/**
+ * Allocate a rte_kvargs and store key/value associations from a string.
+ * This version will consider any byte from valid_ends as a possible
+ * terminating character, and will not parse beyond any of their occurrence.
+ *
+ * The function allocates and fills an rte_kvargs structure from a given
+ * string whose format is key1=value1,key2=value2,...
+ *
+ * The structure can be freed with rte_kvargs_free().
+ *
+ * @param args
+ *   The input string containing the key/value associations
+ *
+ * @param valid_keys
+ *   A list of valid keys (table of const char *, the last must be NULL).
+ *   This argument is ignored if NULL
+ *
+ * @param valid_ends
+ *   Acceptable terminating characters.
+ *   If NULL, the behavior is the same as ``rte_kvargs_parse``.
+ *
+ * @return
+ *   - A pointer to an allocated rte_kvargs structure on success
+ *   - NULL on error
+ */
+__rte_experimental
+struct rte_kvargs *rte_kvargs_parse_delim(const char *args,
+		const char *const valid_keys[],
+		const char *valid_ends);
+
 /**
  * Free a rte_kvargs structure
  *
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index 2030ec46c..afce125a9 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_parse_delim;
+
+} DPDK_2.0;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 06/25] eal: introduce dtor macros
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (4 preceding siblings ...)
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 05/25] kvargs: introduce a more flexible parsing function Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction Gaetan Rivet
                     ` (19 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This macro adds symbols to the .fini section using the global
RTE priorities, to ensure consistency.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>
---
 lib/librte_eal/common/include/rte_common.h | 23 ++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 434adfd45..0dd832728 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -111,6 +111,29 @@ static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)
 #define RTE_INIT(func) \
 	RTE_INIT_PRIO(func, LAST)
 
+/**
+ * Run after main() with low priority.
+ *
+ * @param func
+ *   Destructor function name.
+ * @param prio
+ *   Priority number must be above 100.
+ *   Lowest number is the last to run.
+ */
+#define RTE_FINI_PRIO(func, prio) \
+static void __attribute__((destructor(RTE_PRIO(prio)), used)) func(void)
+
+/**
+ * Run after main() with high priority.
+ *
+ * The destructor will be run *before* prioritized destructors.
+ *
+ * @param func
+ *   Destructor function name.
+ */
+#define RTE_FINI(func) \
+	RTE_FINI_PRIO(func, LAST)
+
 /**
  * Force a function to be inlined
  */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (5 preceding siblings ...)
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 06/25] eal: introduce dtor macros Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-12  6:49     ` Shreyansh Jain
  2018-07-14  6:37     ` Thomas Monjalon
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers Gaetan Rivet
                     ` (18 subsequent siblings)
  25 siblings, 2 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This abstraction exists since the infancy of DPDK.
It needs to be fleshed out however, to allow a generic
description of devices properties and capabilities.

A device class is the northbound interface of the device, intended
for applications to know what it can be used for.

It is conceptually just above buses.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/bsdapp/eal/Makefile         |   1 +
 lib/librte_eal/common/Makefile             |   2 +-
 lib/librte_eal/common/eal_common_class.c   |  62 ++++++++++
 lib/librte_eal/common/include/rte_class.h  | 131 +++++++++++++++++++++
 lib/librte_eal/common/include/rte_common.h |   1 +
 lib/librte_eal/common/meson.build          |   2 +
 lib/librte_eal/linuxapp/eal/Makefile       |   1 +
 lib/librte_eal/rte_eal_version.map         |   2 +
 8 files changed, 201 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_eal/common/eal_common_class.c
 create mode 100644 lib/librte_eal/common/include/rte_class.h

diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index 3fd33f1e4..b0a1c880a 100644
--- a/lib/librte_eal/bsdapp/eal/Makefile
+++ b/lib/librte_eal/bsdapp/eal/Makefile
@@ -52,6 +52,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += eal_common_options.c
diff --git a/lib/librte_eal/common/Makefile b/lib/librte_eal/common/Makefile
index 48f870f24..750653093 100644
--- a/lib/librte_eal/common/Makefile
+++ b/lib/librte_eal/common/Makefile
@@ -11,7 +11,7 @@ INC += rte_per_lcore.h rte_random.h
 INC += rte_tailq.h rte_interrupts.h rte_alarm.h
 INC += rte_string_fns.h rte_version.h
 INC += rte_eal_memconfig.h rte_malloc_heap.h
-INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h
+INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h
 INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
 INC += rte_malloc.h rte_keepalive.h rte_time.h
 INC += rte_service.h rte_service_component.h
diff --git a/lib/librte_eal/common/eal_common_class.c b/lib/librte_eal/common/eal_common_class.c
new file mode 100644
index 000000000..aed4dd8fb
--- /dev/null
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/queue.h>
+
+#include <rte_class.h>
+#include <rte_debug.h>
+
+struct rte_class_list rte_class_list =
+	TAILQ_HEAD_INITIALIZER(rte_class_list);
+
+__rte_experimental void
+rte_class_register(struct rte_class *class)
+{
+	RTE_VERIFY(class);
+	RTE_VERIFY(class->name && strlen(class->name));
+
+	TAILQ_INSERT_TAIL(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Registered [%s] device class.\n", class->name);
+}
+
+__rte_experimental void
+rte_class_unregister(struct rte_class *class)
+{
+	TAILQ_REMOVE(&rte_class_list, class, next);
+	RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
+}
+
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data)
+{
+	struct rte_class *cls;
+
+	if (start != NULL)
+		cls = TAILQ_NEXT(start, next);
+	else
+		cls = TAILQ_FIRST(&rte_class_list);
+	while (cls != NULL) {
+		if (cmp(cls, data) == 0)
+			break;
+		cls = TAILQ_NEXT(cls, next);
+	}
+	return cls;
+}
+
+static int
+cmp_class_name(const struct rte_class *class, const void *_name)
+{
+	const char *name = _name;
+
+	return strcmp(class->name, name);
+}
+
+struct rte_class *
+rte_class_find_by_name(const char *name)
+{
+	return rte_class_find(NULL, cmp_class_name, (const void *)name);
+}
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
new file mode 100644
index 000000000..a79f3152e
--- /dev/null
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -0,0 +1,131 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_CLASS_H_
+#define _RTE_CLASS_H_
+
+/**
+ * @file
+ *
+ * DPDK device class interface.
+ *
+ * This file describes the interface of the device class
+ * abstraction layer.
+ *
+ * A device class defines the type of function a device
+ * will be used for e.g.: Ethernet adapter (eth),
+ * cryptographic coprocessor (crypto), etc.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/queue.h>
+
+#include <rte_dev.h>
+
+/** Double linked list of classes */
+TAILQ_HEAD(rte_class_list, rte_class);
+
+/**
+ * A structure describing a generic device class.
+ */
+struct rte_class {
+	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
+	const char *name; /**< Name of the class */
+};
+
+/**
+ * Class comparison function.
+ *
+ * @param cls
+ *	Class under test.
+ *
+ * @param data
+ *	Data to compare against.
+ *
+ * @return
+ *	0 if the class matches the data.
+ *	!0 if the class does not match.
+ *	<0 if ordering is possible and the class is lower than the data.
+ *	>0 if ordering is possible and the class is greater than the data.
+ */
+typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
+
+/**
+ * Class iterator to find a particular class.
+ *
+ * This function compares each registered class to find one that matches
+ * the data passed as parameter.
+ *
+ * If the comparison function returns zero this function will stop iterating
+ * over any more classes. To continue a search the class of a previous search
+ * can be passed via the start parameter.
+ *
+ * @param start
+ *	Starting point for the iteration.
+ *
+ * @param cmp
+ *	Comparison function.
+ *
+ * @param data
+ *	 Data to pass to comparison function.
+ *
+ * @return
+ *	 A pointer to a rte_class structure or NULL in case no class matches
+ */
+struct rte_class *
+rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
+	       const void *data);
+
+/**
+ * Find the registered class for a given name.
+ */
+struct rte_class *
+rte_class_find_by_name(const char *name);
+
+/**
+ * Register a Class handle.
+ *
+ * @param
+ *   A pointer to a rte_class structure describing the class
+ *   to be registered.
+ */
+__rte_experimental
+void rte_class_register(struct rte_class *cls);
+
+/**
+ * Unregister a Class handle.
+ *
+ * @param class
+ *   A pointer to a rte_class structure describing the class
+ *   to be unregistered.
+ */
+__rte_experimental
+void rte_class_unregister(struct rte_class *cls);
+
+/**
+ * Helper for Class registration.
+ * The constructor has lower priority than Bus constructors.
+ * The constructor has higher priority than PMD constructors.
+ */
+#define RTE_REGISTER_CLASS(nm, cls) \
+RTE_INIT_PRIO(classinitfn_ ##nm, CLASS) \
+{\
+	(cls).name = RTE_STR(nm); \
+	rte_class_register(&cls); \
+}
+
+#define RTE_UNREGISTER_CLASS(nm, cls) \
+RTE_FINI_PRIO(classfinifn_ ##nm, CLASS) \
+{ \
+	rte_class_unregister(&cls); \
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_CLASS_H_ */
diff --git a/lib/librte_eal/common/include/rte_common.h b/lib/librte_eal/common/include/rte_common.h
index 0dd832728..a2e8e6e32 100644
--- a/lib/librte_eal/common/include/rte_common.h
+++ b/lib/librte_eal/common/include/rte_common.h
@@ -83,6 +83,7 @@ typedef uint16_t unaligned_uint16_t;
 
 #define RTE_PRIORITY_LOG 101
 #define RTE_PRIORITY_BUS 110
+#define RTE_PRIORITY_CLASS 120
 #define RTE_PRIORITY_LAST 65535
 
 #define RTE_PRIO(prio) \
diff --git a/lib/librte_eal/common/meson.build b/lib/librte_eal/common/meson.build
index 8a3dcfee0..3009cd0a2 100644
--- a/lib/librte_eal/common/meson.build
+++ b/lib/librte_eal/common/meson.build
@@ -8,6 +8,7 @@ common_objs = []
 common_sources = files(
 	'eal_common_bus.c',
 	'eal_common_cpuflags.c',
+	'eal_common_class.c',
 	'eal_common_devargs.c',
 	'eal_common_dev.c',
 	'eal_common_errno.c',
@@ -46,6 +47,7 @@ common_headers = files(
 	'include/rte_branch_prediction.h',
 	'include/rte_bus.h',
 	'include/rte_bitmap.h',
+	'include/rte_class.h',
 	'include/rte_common.h',
 	'include/rte_debug.h',
 	'include/rte_devargs.h',
diff --git a/lib/librte_eal/linuxapp/eal/Makefile b/lib/librte_eal/linuxapp/eal/Makefile
index 3719ec9d7..babc8617a 100644
--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -60,6 +60,7 @@ SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hypervisor.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_string_fns.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_hexdump.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_devargs.c
+SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_class.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_bus.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_dev.c
 SRCS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += eal_common_options.c
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index 1c4db72fa..19d36b4c7 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -244,6 +244,8 @@ DPDK_18.05 {
 EXPERIMENTAL {
 	global:
 
+	rte_class_register;
+	rte_class_unregister;
 	rte_ctrl_thread_create;
 	rte_dev_event_callback_register;
 	rte_dev_event_callback_unregister;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (6 preceding siblings ...)
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-12  9:48     ` Shreyansh Jain
  2018-07-14 10:30     ` Thomas Monjalon
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 09/25] eal/dev: add device iterator interface Gaetan Rivet
                     ` (17 subsequent siblings)
  25 siblings, 2 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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>
---
 lib/librte_eal/common/eal_common_devargs.c  | 144 ++++++++++++++++++++
 lib/librte_eal/common/eal_private.h         |  34 +++++
 lib/librte_eal/common/include/rte_devargs.h |  13 +-
 3 files changed, 188 insertions(+), 3 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index f84f3d2cf..a22a2002e 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -13,9 +13,13 @@
 #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)
 {
diff --git a/lib/librte_eal/common/eal_private.h b/lib/librte_eal/common/eal_private.h
index bdadc4d50..722957428 100644
--- a/lib/librte_eal/common/eal_private.h
+++ b/lib/librte_eal/common/eal_private.h
@@ -258,4 +258,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_ */
diff --git a/lib/librte_eal/common/include/rte_devargs.h b/lib/librte_eal/common/include/rte_devargs.h
index 6c3b6326b..097a4ce7b 100644
--- a/lib/librte_eal/common/include/rte_devargs.h
+++ b/lib/librte_eal/common/include/rte_devargs.h
@@ -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. */
 };
 
 /**
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 09/25] eal/dev: add device iterator interface
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (7 preceding siblings ...)
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers Gaetan Rivet
@ 2018-07-11 21:44   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 10/25] eal/dev: implement device iteration initialization Gaetan Rivet
                     ` (16 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:44 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A device iterator allows iterating over a set of devices.
This set is defined by the two descriptions offered,

  * rte_bus
  * rte_class

Only one description can be provided, or both. It is not allowed to
provide no description at all.

Each layer of abstraction then performs a filter based on the
description provided. This filtering allows iterating on their internal
set of devices, stopping when a match is valid and returning the current
iteration context.

This context allows starting the next iteration from the same point and
going forward.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/include/rte_bus.h   |  1 +
 lib/librte_eal/common/include/rte_class.h |  1 +
 lib/librte_eal/common/include/rte_dev.h   | 47 +++++++++++++++++++++++
 3 files changed, 49 insertions(+)

diff --git a/lib/librte_eal/common/include/rte_bus.h b/lib/librte_eal/common/include/rte_bus.h
index eb9eded4e..747baf140 100644
--- a/lib/librte_eal/common/include/rte_bus.h
+++ b/lib/librte_eal/common/include/rte_bus.h
@@ -211,6 +211,7 @@ struct rte_bus {
 	rte_bus_parse_t parse;       /**< Parse a device name */
 	struct rte_bus_conf conf;    /**< Bus configuration */
 	rte_bus_get_iommu_class_t get_iommu_class; /**< Get iommu class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
diff --git a/lib/librte_eal/common/include/rte_class.h b/lib/librte_eal/common/include/rte_class.h
index a79f3152e..85dad5a11 100644
--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -35,6 +35,7 @@ TAILQ_HEAD(rte_class_list, rte_class);
 struct rte_class {
 	TAILQ_ENTRY(rte_class) next; /**< Next device class in linked list */
 	const char *name; /**< Name of the class */
+	rte_dev_iterate_t dev_iterate; /**< Device iterator. */
 };
 
 /**
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index ba6e445fc..49000abac 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -284,6 +284,53 @@ __attribute__((used)) = str
 static const char DRV_EXP_TAG(name, kmod_dep_export)[] \
 __attribute__((used)) = str
 
+/**
+ * Iteration context.
+ *
+ * This context carries over the current iteration state.
+ */
+struct rte_dev_iterator {
+	const char *dev_str; /**< device string. */
+	const char *bus_str; /**< bus-related part of device string. */
+	const char *cls_str; /**< class-related part of device string. */
+	struct rte_bus *bus; /**< bus handle. */
+	struct rte_class *cls; /**< class handle. */
+	struct rte_device *device; /**< current position. */
+	void *class_device; /**< additional specialized context. */
+};
+
+/**
+ * Device iteration function.
+ *
+ * Find the next device matching properties passed in parameters.
+ * The function takes an additional ``start`` parameter, that is
+ * used as starting context when relevant.
+ *
+ * The function returns the current element in the iteration.
+ * This return value will potentially be used as a start parameter
+ * in subsequent calls to the function.
+ *
+ * The additional iterator parameter is only there if a specific
+ * implementation needs additional context. It must not be modified by
+ * the iteration function itself.
+ *
+ * @param start
+ *   Starting iteration context.
+ *
+ * @param devstr
+ *   Device description string.
+ *
+ * @param it
+ *   Device iterator.
+ *
+ * @return
+ *   The address of the current element matching the device description
+ *   string.
+ */
+typedef void *(*rte_dev_iterate_t)(const void *start,
+				   const char *devstr,
+				   const struct rte_dev_iterator *it);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 10/25] eal/dev: implement device iteration initialization
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (8 preceding siblings ...)
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 09/25] eal/dev: add device iterator interface Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration Gaetan Rivet
                     ` (15 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

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.rivet@6wind.com>
---
 lib/Makefile                            |  1 +
 lib/librte_eal/bsdapp/eal/Makefile      |  1 +
 lib/librte_eal/common/eal_common_dev.c  | 55 +++++++++++++++++++++++++
 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, 83 insertions(+)

diff --git a/lib/Makefile b/lib/Makefile
index 8a65525cd..afa604e20 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -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
diff --git a/lib/librte_eal/bsdapp/eal/Makefile b/lib/librte_eal/bsdapp/eal/Makefile
index b0a1c880a..67b10ae0d 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 ce4b51469..63e329bd8 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 <rte_spinlock.h>
 #include <rte_malloc.h>
@@ -343,3 +346,55 @@ dev_callback_process(char *device_name, enum rte_dev_event_type event)
 	}
 	rte_spinlock_unlock(&dev_event_lock);
 }
+
+__rte_experimental
+int
+rte_dev_iterator_init(struct rte_dev_iterator *it,
+		      const char *dev_str)
+{
+	struct rte_devargs devargs;
+	struct rte_class *cls = NULL;
+	struct rte_bus *bus = NULL;
+
+	/* Having both bus_str and cls_str NULL is illegal,
+	 * marking this iterator as invalid unless
+	 * everything goes well.
+	 */
+	it->bus_str = NULL;
+	it->cls_str = NULL;
+
+	devargs.data = dev_str;
+	if (rte_devargs_layers_parse(&devargs, dev_str))
+		goto get_out;
+
+	bus = devargs.bus;
+	cls = devargs.cls;
+	/* 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;
+	}
+	it->bus_str = devargs.bus_str;
+	it->cls_str = devargs.cls_str;
+	it->dev_str = dev_str;
+	it->bus = bus;
+	it->cls = cls;
+	it->device = NULL;
+	it->class_device = NULL;
+get_out:
+	return -rte_errno;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index 49000abac..fdc812ff8 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -331,6 +331,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 babc8617a..885c48110 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 19d36b4c7..ac04120d6 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -251,6 +251,7 @@ EXPERIMENTAL {
 	rte_dev_event_callback_unregister;
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
+	rte_dev_iterator_init;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (9 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 10/25] eal/dev: implement device iteration initialization Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-12 10:58     ` Shreyansh Jain
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 12/25] kvargs: add generic string matching callback Gaetan Rivet
                     ` (14 subsequent siblings)
  25 siblings, 1 reply; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Use the iteration hooks in the abstraction layers to perform the
requested filtering on the internal device lists.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++
 lib/librte_eal/common/include/rte_dev.h |  26 ++++
 lib/librte_eal/rte_eal_version.map      |   1 +
 3 files changed, 195 insertions(+)

diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
index 63e329bd8..b78845f02 100644
--- a/lib/librte_eal/common/eal_common_dev.c
+++ b/lib/librte_eal/common/eal_common_dev.c
@@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
 /* spinlock for device callbacks */
 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
 
+struct dev_next_ctx {
+	struct rte_dev_iterator *it;
+	const char *bus_str;
+	const char *cls_str;
+};
+
+#define CTX(it, bus_str, cls_str) \
+	(&(const struct dev_next_ctx){ \
+		.it = it, \
+		.bus_str = bus_str, \
+		.cls_str = cls_str, \
+	})
+
+#define ITCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
+
+#define BUSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->bus_str)
+
+#define CLSCTX(ptr) \
+	(((struct dev_next_ctx *)(intptr_t)ptr)->cls_str)
+
 static int cmp_detached_dev_name(const struct rte_device *dev,
 	const void *_name)
 {
@@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
 get_out:
 	return -rte_errno;
 }
+
+static char *
+dev_str_sane_copy(const char *str)
+{
+	size_t end;
+	char *copy;
+
+	end = strcspn(str, ",/");
+	if (str[end] == ',') {
+		copy = strdup(&str[end + 1]);
+	} else {
+		/* '/' or '\0' */
+		copy = strdup("");
+	}
+	if (copy == NULL) {
+		rte_errno = ENOMEM;
+	} else {
+		char *slash;
+
+		slash = strchr(copy, '/');
+		if (slash != NULL)
+			slash[0] = '\0';
+	}
+	return copy;
+}
+
+static int
+class_next_dev_cmp(const struct rte_class *cls,
+		   const void *ctx)
+{
+	struct rte_dev_iterator *it;
+	const char *cls_str = NULL;
+	void *dev;
+
+	if (cls->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	cls_str = CLSCTX(ctx);
+	dev = it->class_device;
+	/* it->cls_str != NULL means a class
+	 * was specified in the devstr.
+	 */
+	if (it->cls_str != NULL && cls != it->cls)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	dev = cls->dev_iterate(dev, cls_str, it);
+	it->class_device = dev;
+	return dev == NULL;
+}
+
+static int
+bus_next_dev_cmp(const struct rte_bus *bus,
+		 const void *ctx)
+{
+	struct rte_device *dev = NULL;
+	struct rte_class *cls = NULL;
+	struct rte_dev_iterator *it;
+	const char *bus_str = NULL;
+
+	if (bus->dev_iterate == NULL)
+		return 1;
+	it = ITCTX(ctx);
+	bus_str = BUSCTX(ctx);
+	dev = it->device;
+	/* it->bus_str != NULL means a bus
+	 * was specified in the devstr.
+	 */
+	if (it->bus_str != NULL && bus != it->bus)
+		return 1;
+	/* If an error occurred previously,
+	 * no need to test further.
+	 */
+	if (rte_errno != 0)
+		return -1;
+	if (it->cls_str == NULL) {
+		dev = bus->dev_iterate(dev, bus_str, it);
+		goto end;
+	}
+	/* cls_str != NULL */
+	if (dev == NULL) {
+next_dev_on_bus:
+		dev = bus->dev_iterate(dev, bus_str, it);
+		it->device = dev;
+	}
+	if (dev == NULL)
+		return 1;
+	if (it->cls != NULL)
+		cls = TAILQ_PREV(it->cls, rte_class_list, next);
+	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
+	if (cls != NULL) {
+		it->cls = cls;
+		goto end;
+	}
+	goto next_dev_on_bus;
+end:
+	it->device = dev;
+	return dev == NULL;
+}
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it)
+{
+	struct rte_bus *bus = NULL;
+	int old_errno = rte_errno;
+	char *bus_str = NULL;
+	char *cls_str = NULL;
+
+	rte_errno = 0;
+	if (it->bus_str == NULL && it->cls_str == NULL) {
+		/* Invalid iterator. */
+		rte_errno = EINVAL;
+		return NULL;
+	}
+	if (it->bus != NULL)
+		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
+	if (it->bus_str != NULL) {
+		bus_str = dev_str_sane_copy(it->bus_str);
+		if (bus_str == NULL)
+			goto out;
+	}
+	if (it->cls_str != NULL) {
+		cls_str = dev_str_sane_copy(it->cls_str);
+		if (cls_str == NULL)
+			goto out;
+	}
+	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
+				   CTX(it, bus_str, cls_str)))) {
+		if (it->device != NULL) {
+			it->bus = bus;
+			goto out;
+		}
+		if (it->bus_str != NULL ||
+		    rte_errno != 0)
+			break;
+	}
+	if (rte_errno == 0)
+		rte_errno = old_errno;
+out:
+	free(bus_str);
+	free(cls_str);
+	return it->device;
+}
diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
index fdc812ff8..8638a2bbd 100644
--- a/lib/librte_eal/common/include/rte_dev.h
+++ b/lib/librte_eal/common/include/rte_dev.h
@@ -355,6 +355,32 @@ __rte_experimental
 int
 rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
 
+/**
+ * Iterates on a device iterator.
+ *
+ * Generates a new rte_device handle corresponding to the next element
+ * in the list described in comprehension by the iterator.
+ *
+ * The next object is returned, and the iterator is updated.
+ *
+ * @param it
+ *   Device iterator handle.
+ *
+ * @return
+ *   An rte_device handle if found.
+ *   NULL if an error occurred (rte_errno is set).
+ *   NULL if no device could be found (rte_errno is not set).
+ */
+__rte_experimental
+struct rte_device *
+rte_dev_iterator_next(struct rte_dev_iterator *it);
+
+#define RTE_DEV_FOREACH(dev, devstr, it) \
+	for (rte_dev_iterator_init(it, devstr), \
+	     dev = rte_dev_iterator_next(it); \
+	     dev != NULL; \
+	     dev = rte_dev_iterator_next(it))
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
index ac04120d6..4cd5ab3df 100644
--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -252,6 +252,7 @@ EXPERIMENTAL {
 	rte_dev_event_monitor_start;
 	rte_dev_event_monitor_stop;
 	rte_dev_iterator_init;
+	rte_dev_iterator_next;
 	rte_devargs_add;
 	rte_devargs_dump;
 	rte_devargs_insert;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 12/25] kvargs: add generic string matching callback
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (10 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 13/25] bus/pci: implement device iteration and comparison Gaetan Rivet
                     ` (13 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_kvargs/rte_kvargs.c           | 10 +++++++++
 lib/librte_kvargs/rte_kvargs.h           | 26 ++++++++++++++++++++++++
 lib/librte_kvargs/rte_kvargs_version.map |  1 +
 3 files changed, 37 insertions(+)

diff --git a/lib/librte_kvargs/rte_kvargs.c b/lib/librte_kvargs/rte_kvargs.c
index 52262fe54..a28f76945 100644
--- a/lib/librte_kvargs/rte_kvargs.c
+++ b/lib/librte_kvargs/rte_kvargs.c
@@ -193,3 +193,13 @@ rte_kvargs_parse_delim(const char *args, const char * const valid_keys[],
 	free(copy);
 	return kvlist;
 }
+
+__rte_experimental
+int
+rte_kvargs_strcmp(const char *key __rte_unused,
+		  const char *value, void *opaque)
+{
+	const char *str = opaque;
+
+	return -abs(strcmp(str, value));
+}
diff --git a/lib/librte_kvargs/rte_kvargs.h b/lib/librte_kvargs/rte_kvargs.h
index 7f32fd1f6..fc041956e 100644
--- a/lib/librte_kvargs/rte_kvargs.h
+++ b/lib/librte_kvargs/rte_kvargs.h
@@ -153,6 +153,32 @@ int rte_kvargs_process(const struct rte_kvargs *kvlist,
 unsigned rte_kvargs_count(const struct rte_kvargs *kvlist,
 	const char *key_match);
 
+/**
+ * Generic kvarg handler for string comparison.
+ *
+ * This function can be used for a generic string comparison processing
+ * on a list of kvargs.
+ *
+ * @param key
+ *   kvarg pair key.
+ *
+ * @param value
+ *   kvarg pair value.
+ *
+ * @param opaque
+ *   Opaque pointer to a string.
+ *
+ * @return
+ *   0 if the strings match.
+ *   !0 otherwise or on error.
+ *
+ *   Unless strcmp, comparison ordering is not kept.
+ *   In order for rte_kvargs_process to stop processing on match error,
+ *   a negative value is returned even if strcmp had returned a positive one.
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_kvargs/rte_kvargs_version.map b/lib/librte_kvargs/rte_kvargs_version.map
index afce125a9..8f4b4e3f8 100644
--- a/lib/librte_kvargs/rte_kvargs_version.map
+++ b/lib/librte_kvargs/rte_kvargs_version.map
@@ -13,5 +13,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_kvargs_parse_delim;
+	rte_kvargs_strcmp;
 
 } DPDK_2.0;
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 13/25] bus/pci: implement device iteration and comparison
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (11 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 12/25] kvargs: add generic string matching callback Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 14/25] bus/pci: add device matching field id Gaetan Rivet
                     ` (12 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/Makefile     |  3 +-
 drivers/bus/pci/meson.build  |  6 +++-
 drivers/bus/pci/pci_common.c |  3 +-
 drivers/bus/pci/pci_params.c | 53 ++++++++++++++++++++++++++++++++++++
 drivers/bus/pci/private.h    | 25 +++++++++++++++++
 5 files changed, 86 insertions(+), 4 deletions(-)
 create mode 100644 drivers/bus/pci/pci_params.c

diff --git a/drivers/bus/pci/Makefile b/drivers/bus/pci/Makefile
index cf373068a..4de953f8f 100644
--- a/drivers/bus/pci/Makefile
+++ b/drivers/bus/pci/Makefile
@@ -26,10 +26,11 @@ CFLAGS += -I$(RTE_SDK)/lib/librte_eal/$(SYSTEM)app/eal
 CFLAGS += -DALLOW_EXPERIMENTAL_API
 
 LDLIBS += -lrte_eal -lrte_mbuf -lrte_mempool -lrte_ring
-LDLIBS += -lrte_ethdev -lrte_pci
+LDLIBS += -lrte_ethdev -lrte_pci -lrte_kvargs
 
 include $(RTE_SDK)/drivers/bus/pci/$(SYSTEM)/Makefile
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) := $(addprefix $(SYSTEM)/,$(SRCS))
+SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_params.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common.c
 SRCS-$(CONFIG_RTE_LIBRTE_PCI_BUS) += pci_common_uio.c
 
diff --git a/drivers/bus/pci/meson.build b/drivers/bus/pci/meson.build
index 72939e598..23d6a5fec 100644
--- a/drivers/bus/pci/meson.build
+++ b/drivers/bus/pci/meson.build
@@ -3,7 +3,9 @@
 
 deps += ['pci']
 install_headers('rte_bus_pci.h')
-sources = files('pci_common.c', 'pci_common_uio.c')
+sources = files('pci_common.c',
+	'pci_common_uio.c',
+	'pci_params.c')
 if host_machine.system() == 'linux'
 	sources += files('linux/pci.c',
 			'linux/pci_uio.c',
@@ -17,3 +19,5 @@ endif
 
 # memseg walk is not part of stable API yet
 allow_experimental_apis = true
+
+deps += ['kvargs']
diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 94b0f4143..5b7854490 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -29,8 +29,6 @@
 
 static void rte_pci_remove_device(struct rte_pci_device *pci_device);
 
-extern struct rte_pci_bus rte_pci_bus;
-
 #define SYSFS_PCI_DEVICES "/sys/bus/pci/devices"
 
 const char *rte_pci_get_sysfs_path(void)
@@ -437,6 +435,7 @@ struct rte_pci_bus rte_pci_bus = {
 		.unplug = pci_unplug,
 		.parse = pci_parse,
 		.get_iommu_class = rte_pci_get_iommu_class,
+		.dev_iterate = rte_pci_dev_iterate,
 	},
 	.device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list),
 	.driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
new file mode 100644
index 000000000..0fde75803
--- /dev/null
+++ b/drivers/bus/pci/pci_params.c
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_bus.h>
+#include <rte_dev.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_pci.h>
+
+#include "private.h"
+
+enum pci_params {
+	RTE_PCI_PARAMS_MAX,
+};
+
+static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_MAX] = NULL,
+};
+
+static int
+pci_dev_match(const struct rte_device *dev,
+	      const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) dev;
+	(void) kvlist;
+	return 0;
+}
+
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it __rte_unused)
+{
+	rte_bus_find_device_t find_device;
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, pci_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	find_device = rte_pci_bus.bus.find_device;
+	dev = find_device(start, pci_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 8ddd03e16..0e689fa74 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -10,6 +10,8 @@
 #include <rte_pci.h>
 #include <rte_bus_pci.h>
 
+extern struct rte_pci_bus rte_pci_bus;
+
 struct rte_pci_driver;
 struct rte_pci_device;
 
@@ -166,4 +168,27 @@ rte_pci_match(const struct rte_pci_driver *pci_drv,
 enum rte_iova_mode
 rte_pci_get_iommu_class(void);
 
+/*
+ * Iterate over internal devices,
+ * matching any device against the provided
+ * string.
+ *
+ * @param start
+ *   Iteration starting point.
+ *
+ * @param str
+ *   Device string to match against.
+ *
+ * @param it
+ *   (unused) iterator structure.
+ *
+ * @return
+ *   A pointer to the next matching device if any.
+ *   NULL otherwise.
+ */
+void *
+rte_pci_dev_iterate(const void *start,
+		    const char *str,
+		    const struct rte_dev_iterator *it);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 14/25] bus/pci: add device matching field id
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (12 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 13/25] bus/pci: implement device iteration and comparison Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 15/25] bus/vdev: implement device iteration Gaetan Rivet
                     ` (11 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The PCI bus can now parse a matching field "id" as follows:

   "bus=pci,id=0000:00:00.0"

           or

   "bus=pci,id=00:00.0"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_params.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 0fde75803..7630d4845 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -3,6 +3,7 @@
  */
 
 #include <rte_bus.h>
+#include <rte_bus_pci.h>
 #include <rte_dev.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
@@ -11,21 +12,45 @@
 #include "private.h"
 
 enum pci_params {
+	RTE_PCI_PARAMS_ID,
 	RTE_PCI_PARAMS_MAX,
 };
 
 static const char * const pci_params_keys[] = {
+	[RTE_PCI_PARAMS_ID] = "id",
 	[RTE_PCI_PARAMS_MAX] = NULL,
 };
 
+static int
+pci_addr_kv_cmp(const char *key __rte_unused,
+		const char *value,
+		void *_addr2)
+{
+	struct rte_pci_addr _addr1;
+	struct rte_pci_addr *addr1 = &_addr1;
+	struct rte_pci_addr *addr2 = _addr2;
+
+	if (rte_pci_addr_parse(value, addr1))
+		return -1;
+	return -abs(rte_pci_addr_cmp(addr1, addr2));
+}
+
 static int
 pci_dev_match(const struct rte_device *dev,
 	      const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_pci_device *pdev;
 
-	(void) dev;
-	(void) kvlist;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	pdev = RTE_DEV_TO_PCI_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "id",
+			       &pci_addr_kv_cmp,
+			       (void *)(intptr_t)&pdev->addr))
+		return 1;
 	return 0;
 }
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 15/25] bus/vdev: implement device iteration
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (13 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 14/25] bus/pci: add device matching field id Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 16/25] bus/vdev: add device matching field driver Gaetan Rivet
                     ` (10 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/Makefile       |  3 +-
 drivers/bus/vdev/meson.build    |  5 +++-
 drivers/bus/vdev/vdev.c         | 10 ++++---
 drivers/bus/vdev/vdev_params.c  | 51 +++++++++++++++++++++++++++++++++
 drivers/bus/vdev/vdev_private.h | 26 +++++++++++++++++
 5 files changed, 89 insertions(+), 6 deletions(-)
 create mode 100644 drivers/bus/vdev/vdev_params.c
 create mode 100644 drivers/bus/vdev/vdev_private.h

diff --git a/drivers/bus/vdev/Makefile b/drivers/bus/vdev/Makefile
index bd0bb8955..1f9cd7ebe 100644
--- a/drivers/bus/vdev/Makefile
+++ b/drivers/bus/vdev/Makefile
@@ -19,8 +19,9 @@ EXPORT_MAP := rte_bus_vdev_version.map
 LIBABIVER := 1
 
 SRCS-y += vdev.c
+SRCS-y += vdev_params.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
diff --git a/drivers/bus/vdev/meson.build b/drivers/bus/vdev/meson.build
index 2ee648b49..12605e5c7 100644
--- a/drivers/bus/vdev/meson.build
+++ b/drivers/bus/vdev/meson.build
@@ -1,7 +1,10 @@
 # SPDX-License-Identifier: BSD-3-Clause
 # Copyright(c) 2017 Intel Corporation
 
-sources = files('vdev.c')
+sources = files('vdev.c',
+	'vdev_params.c')
 install_headers('rte_bus_vdev.h')
 
 allow_experimental_apis = true
+
+deps += ['kvargs']
diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index 6139dd551..e8518833d 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -23,6 +23,7 @@
 
 #include "rte_bus_vdev.h"
 #include "vdev_logs.h"
+#include "vdev_private.h"
 
 #define VDEV_MP_KEY	"bus_vdev_mp"
 
@@ -493,9 +494,9 @@ vdev_probe(void)
 	return ret;
 }
 
-static struct rte_device *
-vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
-		 const void *data)
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
+		     const void *data)
 {
 	const struct rte_vdev_device *vstart;
 	struct rte_vdev_device *dev;
@@ -532,10 +533,11 @@ vdev_unplug(struct rte_device *dev)
 static struct rte_bus rte_vdev_bus = {
 	.scan = vdev_scan,
 	.probe = vdev_probe,
-	.find_device = vdev_find_device,
+	.find_device = rte_vdev_find_device,
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
 	.parse = vdev_parse,
+	.dev_iterate = rte_vdev_dev_iterate,
 };
 
 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
new file mode 100644
index 000000000..842a4684e
--- /dev/null
+++ b/drivers/bus/vdev/vdev_params.c
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#include <rte_dev.h>
+#include <rte_bus.h>
+#include <rte_kvargs.h>
+#include <rte_errno.h>
+
+#include "vdev_logs.h"
+#include "vdev_private.h"
+
+enum vdev_params {
+	RTE_VDEV_PARAMS_MAX,
+};
+
+static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_MAX] = NULL,
+};
+
+static int
+vdev_dev_match(const struct rte_device *dev,
+	       const void *_kvlist)
+{
+	const struct rte_kvargs *kvlist = _kvlist;
+
+	(void) kvlist;
+	(void) dev;
+	return 0;
+}
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it __rte_unused)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_device *dev;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, vdev_params_keys);
+		if (kvargs == NULL) {
+			VDEV_LOG(ERR, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	dev = rte_vdev_find_device(start, vdev_dev_match, kvargs);
+	rte_kvargs_free(kvargs);
+	return dev;
+}
diff --git a/drivers/bus/vdev/vdev_private.h b/drivers/bus/vdev/vdev_private.h
new file mode 100644
index 000000000..ba6dc48ff
--- /dev/null
+++ b/drivers/bus/vdev/vdev_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2018 Gaëtan Rivet
+ */
+
+#ifndef _VDEV_PRIVATE_H_
+#define _VDEV_PRIVATE_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct rte_device *
+rte_vdev_find_device(const struct rte_device *start,
+		     rte_dev_cmp_t cmp,
+		     const void *data);
+
+void *
+rte_vdev_dev_iterate(const void *start,
+		     const char *str,
+		     const struct rte_dev_iterator *it);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VDEV_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 16/25] bus/vdev: add device matching field driver
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (14 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 15/25] bus/vdev: implement device iteration Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 17/25] ethdev: add private generic device iterator Gaetan Rivet
                     ` (9 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:

   "bus=vdev,driver=xxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev_params.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
index 842a4684e..2f55f451f 100644
--- a/drivers/bus/vdev/vdev_params.c
+++ b/drivers/bus/vdev/vdev_params.c
@@ -4,6 +4,7 @@
 
 #include <rte_dev.h>
 #include <rte_bus.h>
+#include <rte_bus_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
 
@@ -11,10 +12,12 @@
 #include "vdev_private.h"
 
 enum vdev_params {
+	RTE_VDEV_PARAMS_DRIVER,
 	RTE_VDEV_PARAMS_MAX,
 };
 
 static const char * const vdev_params_keys[] = {
+	[RTE_VDEV_PARAMS_DRIVER] = "driver",
 	[RTE_VDEV_PARAMS_MAX] = NULL,
 };
 
@@ -23,9 +26,17 @@ vdev_dev_match(const struct rte_device *dev,
 	       const void *_kvlist)
 {
 	const struct rte_kvargs *kvlist = _kvlist;
+	const struct rte_vdev_device *vdev;
 
-	(void) kvlist;
-	(void) dev;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	vdev = RTE_DEV_TO_VDEV_CONST(dev);
+	/* if any field does not match. */
+	if (rte_kvargs_process(kvlist, "driver",
+		rte_kvargs_strcmp,
+		(void *)(intptr_t)vdev->device.driver->name))
+		return -1;
 	return 0;
 }
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 17/25] ethdev: add private generic device iterator
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (15 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 16/25] bus/vdev: add device matching field driver Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 18/25] ethdev: register ether layer as a class Gaetan Rivet
                     ` (8 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

This iterator can be customized with a comparison function that will
trigger a stopping condition.

It can be leveraged to write several different iterators that have
similar but non-identical purposes.

It is private to librte_ethdev.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile      |  1 +
 lib/librte_ethdev/eth_private.c | 31 +++++++++++++++++++++++++++++++
 lib/librte_ethdev/eth_private.h | 26 ++++++++++++++++++++++++++
 lib/librte_ethdev/meson.build   |  3 ++-
 4 files changed, 60 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ethdev/eth_private.c
 create mode 100644 lib/librte_ethdev/eth_private.h

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index c2f2f7d82..2fa133fbc 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -18,6 +18,7 @@ EXPORT_MAP := rte_ethdev_version.map
 
 LIBABIVER := 9
 
+SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
diff --git a/lib/librte_ethdev/eth_private.c b/lib/librte_ethdev/eth_private.c
new file mode 100644
index 000000000..d565568a0
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.c
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include "rte_ethdev.h"
+#include "eth_private.h"
+
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *start, rte_eth_cmp_t cmp,
+		const void *data)
+{
+	struct rte_eth_dev *edev;
+	ptrdiff_t idx;
+
+	/* Avoid Undefined Behaviour */
+	if (start != NULL &&
+	    (start < &rte_eth_devices[0] ||
+	     start > &rte_eth_devices[RTE_MAX_ETHPORTS]))
+		return NULL;
+	if (start != NULL)
+		idx = start - &rte_eth_devices[0] + 1;
+	else
+		idx = 0;
+	for (; idx < RTE_MAX_ETHPORTS; idx++) {
+		edev = &rte_eth_devices[idx];
+		if (cmp(edev, data) == 0)
+			return edev;
+	}
+	return NULL;
+}
+
diff --git a/lib/librte_ethdev/eth_private.h b/lib/librte_ethdev/eth_private.h
new file mode 100644
index 000000000..0f5c6d5c4
--- /dev/null
+++ b/lib/librte_ethdev/eth_private.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#ifndef _RTE_ETH_PRIVATE_H_
+#define _RTE_ETH_PRIVATE_H_
+
+#include "rte_ethdev.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Generic rte_eth_dev comparison function. */
+typedef int (*rte_eth_cmp_t)(const struct rte_eth_dev *, const void *);
+
+/* Generic rte_eth_dev iterator. */
+struct rte_eth_dev *
+eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
+		const void *data);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_ETH_PRIVATE_H_ */
diff --git a/lib/librte_ethdev/meson.build b/lib/librte_ethdev/meson.build
index aed5d2265..a0c001847 100644
--- a/lib/librte_ethdev/meson.build
+++ b/lib/librte_ethdev/meson.build
@@ -4,7 +4,8 @@
 name = 'ethdev'
 version = 9
 allow_experimental_apis = true
-sources = files('ethdev_profile.c',
+sources = files('eth_private.c',
+	'ethdev_profile.c',
 	'rte_ethdev.c',
 	'rte_flow.c',
 	'rte_mtr.c',
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 18/25] ethdev: register ether layer as a class
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (16 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 17/25] ethdev: add private generic device iterator Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 19/25] ethdev: add device matching field name Gaetan Rivet
                     ` (7 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/Makefile        |  3 +-
 lib/librte_ethdev/meson.build     |  1 +
 lib/librte_ethdev/rte_class_eth.c | 79 +++++++++++++++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletion(-)
 create mode 100644 lib/librte_ethdev/rte_class_eth.c

diff --git a/lib/librte_ethdev/Makefile b/lib/librte_ethdev/Makefile
index 2fa133fbc..d4c3a8d06 100644
--- a/lib/librte_ethdev/Makefile
+++ b/lib/librte_ethdev/Makefile
@@ -12,7 +12,7 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API
 CFLAGS += -O3
 CFLAGS += $(WERROR_FLAGS)
 LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring
-LDLIBS += -lrte_mbuf
+LDLIBS += -lrte_mbuf -lrte_kvargs
 
 EXPORT_MAP := rte_ethdev_version.map
 
@@ -20,6 +20,7 @@ LIBABIVER := 9
 
 SRCS-y += eth_private.c
 SRCS-y += rte_ethdev.c
+SRCS-y += rte_class_eth.c
 SRCS-y += rte_flow.c
 SRCS-y += rte_tm.c
 SRCS-y += rte_mtr.c
diff --git a/lib/librte_ethdev/meson.build b/lib/librte_ethdev/meson.build
index a0c001847..f9538770b 100644
--- a/lib/librte_ethdev/meson.build
+++ b/lib/librte_ethdev/meson.build
@@ -6,6 +6,7 @@ version = 9
 allow_experimental_apis = true
 sources = files('eth_private.c',
 	'ethdev_profile.c',
+	'rte_class_eth.c',
 	'rte_ethdev.c',
 	'rte_flow.c',
 	'rte_mtr.c',
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
new file mode 100644
index 000000000..32c736d32
--- /dev/null
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan Rivet
+ */
+
+#include <string.h>
+
+#include <rte_class.h>
+#include <rte_compat.h>
+#include <rte_errno.h>
+#include <rte_kvargs.h>
+#include <rte_log.h>
+
+#include "rte_ethdev.h"
+#include "rte_ethdev_core.h"
+#include "eth_private.h"
+
+enum eth_params {
+	RTE_ETH_PARAMS_MAX,
+};
+
+static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_MAX] = NULL,
+};
+
+struct eth_dev_match_arg {
+	struct rte_device *device;
+	struct rte_kvargs *kvlist;
+};
+
+#define eth_dev_match_arg(d, k) \
+	(&(const struct eth_dev_match_arg) { \
+		.device = (d), \
+		.kvlist = (k), \
+	})
+
+static int
+eth_dev_match(const struct rte_eth_dev *edev,
+	      const void *_arg)
+{
+	const struct eth_dev_match_arg *arg = _arg;
+	const struct rte_kvargs *kvlist = arg->kvlist;
+
+	if (edev->state == RTE_ETH_DEV_UNUSED)
+		return -1;
+	if (edev->device != arg->device)
+		return -1;
+	if (kvlist == NULL)
+		/* Empty string matches everything. */
+		return 0;
+	return 0;
+}
+
+static void *
+eth_dev_iterate(const void *start,
+		const char *str,
+		const struct rte_dev_iterator *it)
+{
+	struct rte_kvargs *kvargs = NULL;
+	struct rte_eth_dev *edev = NULL;
+
+	if (str != NULL) {
+		kvargs = rte_kvargs_parse(str, eth_params_keys);
+		if (kvargs == NULL) {
+			RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+			rte_errno = EINVAL;
+			return NULL;
+		}
+	}
+	edev = eth_find_device(start, eth_dev_match,
+			       eth_dev_match_arg(it->device, kvargs));
+	rte_kvargs_free(kvargs);
+	return edev;
+}
+
+struct rte_class rte_class_eth = {
+	.dev_iterate = eth_dev_iterate,
+};
+
+RTE_REGISTER_CLASS(eth, rte_class_eth);
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 19/25] ethdev: add device matching field name
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (17 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 18/25] ethdev: register ether layer as a class Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 20/25] app/testpmd: add show device command Gaetan Rivet
                     ` (6 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The eth device class can now parse a field name,
matching the eth_dev name with one passed as

   "class=eth,name=xxxxxx"

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
index 32c736d32..d8d8e8845 100644
--- a/lib/librte_ethdev/rte_class_eth.c
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -15,10 +15,12 @@
 #include "eth_private.h"
 
 enum eth_params {
+	RTE_ETH_PARAMS_NAME,
 	RTE_ETH_PARAMS_MAX,
 };
 
 static const char * const eth_params_keys[] = {
+	[RTE_ETH_PARAMS_NAME] = "name",
 	[RTE_ETH_PARAMS_MAX] = NULL,
 };
 
@@ -39,6 +41,7 @@ eth_dev_match(const struct rte_eth_dev *edev,
 {
 	const struct eth_dev_match_arg *arg = _arg;
 	const struct rte_kvargs *kvlist = arg->kvlist;
+	struct rte_eth_dev_data *data;
 
 	if (edev->state == RTE_ETH_DEV_UNUSED)
 		return -1;
@@ -47,6 +50,10 @@ eth_dev_match(const struct rte_eth_dev *edev,
 	if (kvlist == NULL)
 		/* Empty string matches everything. */
 		return 0;
+	data = edev->data;
+	if (rte_kvargs_process(kvlist, "name",
+			rte_kvargs_strcmp, data->name))
+		return -1;
 	return 0;
 }
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 20/25] app/testpmd: add show device command
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (18 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 19/25] ethdev: add device matching field name Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 21/25] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
                     ` (5 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

A new interactive command is offered:

   show device <device description>

This commands lists all rte_device element matching the device
description. e.g.:

   show device bus=pci
   show device bus=vdev
   show device bus=vdev/class=eth
   show device bus=vdev,driver=net_ring/class=eth
   show device bus=vdev/class=eth,name=net_ring0

These devices may not be otherwise useful, some buses will spawn devices
to keep track of their assets without having a driver to use them.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
Acked-by: Bernard Iremonger <bernard.iremonger@intel.com>
---
 app/test-pmd/cmdline.c                      | 54 +++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 +++++++++
 2 files changed, 78 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 74a8cd99e..238ecfc56 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -228,6 +228,9 @@ static void cmd_help_long_parsed(void *parsed_result,
                         "show port tm node stats (port_id) (node_id) (clear)\n"
                         "       Display the port TM node stats.\n\n"
 
+			"show device (device_string)\n"
+			"       Display devices matching the device string.\n\n"
+
 		);
 	}
 
@@ -7093,6 +7096,56 @@ cmdline_parse_inst_t cmd_showportall = {
 	},
 };
 
+/* *** SHOW DEVICE INFO *** */
+struct cmd_showdevice_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t device;
+	cmdline_fixed_string_t filter;
+};
+
+static void
+cmd_showdevice_dump_device(const struct rte_device *dev)
+{
+	const struct rte_driver *drv = dev->driver;
+
+	printf("0x%p: %s:%s\n", (const void *)dev, dev->name,
+		drv ? drv->name : "<nil>");
+}
+
+static void cmd_showdevice_parsed(void *parsed_result,
+				__attribute__((unused)) struct cmdline *cl,
+				__attribute__((unused)) void *data)
+{
+	struct cmd_showdevice_result *res = parsed_result;
+	struct rte_dev_iterator it;
+	const struct rte_device *dev;
+
+	RTE_DEV_FOREACH(dev, res->filter, &it)
+		cmd_showdevice_dump_device(dev);
+}
+
+cmdline_parse_token_string_t cmd_showdevice_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				show, "show");
+cmdline_parse_token_string_t cmd_showdevice_device =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+				device, "device");
+cmdline_parse_token_string_t cmd_showdevice_filter =
+	TOKEN_STRING_INITIALIZER(struct cmd_showdevice_result,
+			filter, NULL);
+
+cmdline_parse_inst_t cmd_showdevice = {
+	.f = cmd_showdevice_parsed,
+	.data = NULL,
+	.help_str = "show device <device string>",
+	.tokens = {
+		(void *)&cmd_showdevice_show,
+		(void *)&cmd_showdevice_device,
+		(void *)&cmd_showdevice_filter,
+		NULL,
+	},
+};
+
 /* *** SHOW PORT INFO *** */
 struct cmd_showport_result {
 	cmdline_fixed_string_t show;
@@ -17272,6 +17325,7 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_help_long,
 	(cmdline_parse_inst_t *)&cmd_quit,
 	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showdevice,
 	(cmdline_parse_inst_t *)&cmd_showport,
 	(cmdline_parse_inst_t *)&cmd_showqueue,
 	(cmdline_parse_inst_t *)&cmd_showportall,
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index 0d6fd50ca..4f1009a3a 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on the port::
 
    testpmd> set port tm hierarchy default (port_id)
 
+Device functions
+----------------
+
+Show devices
+~~~~~~~~~~~~
+
+Display any registered devices::
+
+   testpmd> show device <device_string>
+
+where:
+
+* ``device_string``: Device description string, of the format
+
+  layer[/layer[/layer]]
+
+  where one layer is in the form
+
+  layer_key=layer_name[,key1=value1[,...]]
+
+  Valid layer keys are ``bus`` and ``class``.
+  Their respective values is defined by registered ``bus`` and ``class``
+  drivers.
+
 Filter Functions
 ----------------
 
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 21/25] bus/pci: pre-process declarative PCI devargs
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (19 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 20/25] app/testpmd: add show device command Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 22/25] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
                     ` (4 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The new devargs format does not recognize a particular device name.
Each bus uses its specific format.

Instead of introducing a new bus API, process those devargs privately
for the moment. Prepare them for matching during scan against the
bus devices.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/bsd/pci.c    |  5 ++++
 drivers/bus/pci/linux/pci.c  |  5 ++++
 drivers/bus/pci/pci_params.c | 51 ++++++++++++++++++++++++++++++++++++
 drivers/bus/pci/private.h    | 16 +++++++++++
 4 files changed, 77 insertions(+)

diff --git a/drivers/bus/pci/bsd/pci.c b/drivers/bus/pci/bsd/pci.c
index 655b34b7e..046cd11d5 100644
--- a/drivers/bus/pci/bsd/pci.c
+++ b/drivers/bus/pci/bsd/pci.c
@@ -327,6 +327,7 @@ pci_scan_one(int dev_pci_fd, struct pci_conf *conf)
 int
 rte_pci_scan(void)
 {
+	struct rte_devargs *devargs;
 	int fd;
 	unsigned dev_count = 0;
 	struct pci_conf matches[16];
@@ -342,6 +343,10 @@ rte_pci_scan(void)
 	if (!rte_eal_has_pci())
 		return 0;
 
+	RTE_EAL_DEVARGS_FOREACH("pci", devargs)
+		if (rte_pci_devargs_prepare(devargs))
+			continue;
+
 	fd = open("/dev/pci", O_RDONLY);
 	if (fd < 0) {
 		RTE_LOG(ERR, EAL, "%s(): error opening /dev/pci\n", __func__);
diff --git a/drivers/bus/pci/linux/pci.c b/drivers/bus/pci/linux/pci.c
index 004600f1c..0c20a4337 100644
--- a/drivers/bus/pci/linux/pci.c
+++ b/drivers/bus/pci/linux/pci.c
@@ -430,6 +430,7 @@ parse_pci_addr_format(const char *buf, int bufsize, struct rte_pci_addr *addr)
 int
 rte_pci_scan(void)
 {
+	struct rte_devargs *devargs;
 	struct dirent *e;
 	DIR *dir;
 	char dirname[PATH_MAX];
@@ -439,6 +440,10 @@ rte_pci_scan(void)
 	if (!rte_eal_has_pci())
 		return 0;
 
+	RTE_EAL_DEVARGS_FOREACH("pci", devargs)
+		if (rte_pci_devargs_prepare(devargs))
+			continue;
+
 #ifdef VFIO_PRESENT
 	if (!pci_vfio_is_enabled())
 		RTE_LOG(DEBUG, EAL, "VFIO PCI modules not loaded\n");
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index 7630d4845..a09af3b1c 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -2,9 +2,12 @@
  * Copyright 2018 Gaëtan Rivet
  */
 
+#include <string.h>
+
 #include <rte_bus.h>
 #include <rte_bus_pci.h>
 #include <rte_dev.h>
+#include <rte_devargs.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
 #include <rte_pci.h>
@@ -76,3 +79,51 @@ rte_pci_dev_iterate(const void *start,
 	rte_kvargs_free(kvargs);
 	return dev;
 }
+
+static int
+pci_addr_kv_parse(const char *key __rte_unused,
+		  const char *value,
+		  void *_devargs)
+{
+	struct rte_devargs *devargs = _devargs;
+	struct rte_pci_addr addr;
+
+	/* Verify address is valid. */
+	if (rte_pci_addr_parse(value, &addr)) {
+		rte_errno = ENODEV;
+		return -1;
+	}
+	/* Write down the address as the devargs name. */
+	rte_pci_device_name(&addr, devargs->name, sizeof(devargs->name));
+	return 0;
+}
+
+int
+rte_pci_devargs_prepare(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvargs = NULL;
+	char *args;
+	int ret;
+
+	if (devargs->bus_str == NULL)
+		return 0;
+
+	args = strchr(devargs->bus_str, ',');
+	if (args == NULL)
+		return 0;
+	args++;
+
+	kvargs = rte_kvargs_parse(args, pci_params_keys);
+	if (kvargs == NULL) {
+		RTE_LOG(ERR, EAL, "unable to parse parameter list: %s\n",
+			devargs->bus_str);
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	ret = rte_kvargs_process(kvargs, "id",
+				 &pci_addr_kv_parse, devargs);
+
+	rte_kvargs_free(kvargs);
+	return ret;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 0e689fa74..9beb24c6a 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -191,4 +191,20 @@ rte_pci_dev_iterate(const void *start,
 		    const char *str,
 		    const struct rte_dev_iterator *it);
 
+/*
+ * Prepare a devargs meant for this bus.
+ * This function is only used for a transitory period,
+ * to translate the new devargs format in one
+ * compatible with the old form.
+ *
+ * @param da
+ *   Devargs to process.
+ *
+ * @return
+ *   0 on success.
+ *   <0 on error.
+ */
+int
+rte_pci_devargs_prepare(struct rte_devargs *da);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 22/25] bus/vdev: pre-process declarative vdev devargs
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (20 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 21/25] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 23/25] bus/pci: process declarative PCI devargs Gaetan Rivet
                     ` (3 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

The new devargs format does not recognize a particular device name.
Each bus uses its specific format.

Process each devargs privately prior to attempting a bus scan.
Prepare them if they are using the new devargs format.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/vdev/vdev.c         | 10 ++++---
 drivers/bus/vdev/vdev_params.c  | 50 +++++++++++++++++++++++++++++++++
 drivers/bus/vdev/vdev_private.h |  6 ++++
 3 files changed, 62 insertions(+), 4 deletions(-)

diff --git a/drivers/bus/vdev/vdev.c b/drivers/bus/vdev/vdev.c
index e8518833d..f2dace245 100644
--- a/drivers/bus/vdev/vdev.c
+++ b/drivers/bus/vdev/vdev.c
@@ -115,8 +115,8 @@ rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
 	return 0;
 }
 
-static int
-vdev_parse(const char *name, void *addr)
+int
+rte_vdev_parse(const char *name, void *addr)
 {
 	struct rte_vdev_driver **out = addr;
 	struct rte_vdev_driver *driver = NULL;
@@ -148,7 +148,7 @@ vdev_probe_all_drivers(struct rte_vdev_device *dev)
 	VDEV_LOG(DEBUG, "Search driver %s to probe device %s", name,
 		rte_vdev_device_name(dev));
 
-	if (vdev_parse(name, &driver))
+	if (rte_vdev_parse(name, &driver))
 		return -1;
 	dev->device.driver = &driver->driver;
 	ret = driver->probe(dev);
@@ -443,6 +443,8 @@ vdev_scan(void)
 
 	/* for virtual devices we scan the devargs_list populated via cmdline */
 	RTE_EAL_DEVARGS_FOREACH("vdev", devargs) {
+		if (rte_vdev_devargs_prepare(devargs))
+			continue;
 
 		dev = calloc(1, sizeof(*dev));
 		if (!dev)
@@ -536,7 +538,7 @@ static struct rte_bus rte_vdev_bus = {
 	.find_device = rte_vdev_find_device,
 	.plug = vdev_plug,
 	.unplug = vdev_unplug,
-	.parse = vdev_parse,
+	.parse = rte_vdev_parse,
 	.dev_iterate = rte_vdev_dev_iterate,
 };
 
diff --git a/drivers/bus/vdev/vdev_params.c b/drivers/bus/vdev/vdev_params.c
index 2f55f451f..aafaf3330 100644
--- a/drivers/bus/vdev/vdev_params.c
+++ b/drivers/bus/vdev/vdev_params.c
@@ -2,11 +2,14 @@
  * Copyright 2018 Gaëtan Rivet
  */
 
+#include <string.h>
+
 #include <rte_dev.h>
 #include <rte_bus.h>
 #include <rte_bus_vdev.h>
 #include <rte_kvargs.h>
 #include <rte_errno.h>
+#include <rte_devargs.h>
 
 #include "vdev_logs.h"
 #include "vdev_private.h"
@@ -60,3 +63,50 @@ rte_vdev_dev_iterate(const void *start,
 	rte_kvargs_free(kvargs);
 	return dev;
 }
+
+static int
+vdev_driver_kv_parse(const char *key __rte_unused,
+		     const char *value,
+		     void *_devargs)
+{
+	struct rte_devargs *devargs = _devargs;
+	struct rte_vdev_driver *driver;
+
+	/* Verify that the driver matches. */
+	if (rte_vdev_parse(value, &driver))
+		return -1;
+
+	/* Copy the driver name as-is. */
+	snprintf(devargs->name, sizeof(devargs->name), "%s", value);
+	return 0;
+}
+
+int
+rte_vdev_devargs_prepare(struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvargs = NULL;
+	char *args;
+	int ret;
+
+	if (devargs->bus_str == NULL)
+		return 0;
+
+	args = strchr(devargs->bus_str, ',');
+	if (args == NULL)
+		return 0;
+	args++;
+
+	kvargs = rte_kvargs_parse(args, vdev_params_keys);
+	if (kvargs == NULL) {
+		VDEV_LOG(ERR, "unable to parse parameter list: %s\n",
+			 devargs->bus_str);
+		rte_errno = EINVAL;
+		return -1;
+	}
+
+	ret = rte_kvargs_process(kvargs, "driver",
+				 vdev_driver_kv_parse, devargs);
+
+	rte_kvargs_free(kvargs);
+	return ret;
+}
diff --git a/drivers/bus/vdev/vdev_private.h b/drivers/bus/vdev/vdev_private.h
index ba6dc48ff..da57b84dd 100644
--- a/drivers/bus/vdev/vdev_private.h
+++ b/drivers/bus/vdev/vdev_private.h
@@ -19,6 +19,12 @@ rte_vdev_dev_iterate(const void *start,
 		     const char *str,
 		     const struct rte_dev_iterator *it);
 
+int
+rte_vdev_parse(const char *name, void *addr);
+
+int
+rte_vdev_devargs_prepare(struct rte_devargs *da);
+
 #ifdef __cplusplus
 }
 #endif
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 23/25] bus/pci: process declarative PCI devargs
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (21 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 22/25] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 24/25] ethdev: process declarative eth devargs Gaetan Rivet
                     ` (2 subsequent siblings)
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Introduce the facility to process future PCI parameters.

Once the matching between PCI devices and devargs has been done, it is
possible to process each devargs. New parameters would have the PCI
device handle to work with when parsing the device (bus specific)
parameters.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 drivers/bus/pci/pci_common.c |  3 +++
 drivers/bus/pci/pci_params.c | 10 ++++++++++
 drivers/bus/pci/private.h    | 13 +++++++++++++
 3 files changed, 26 insertions(+)

diff --git a/drivers/bus/pci/pci_common.c b/drivers/bus/pci/pci_common.c
index 5b7854490..15a3cf3ae 100644
--- a/drivers/bus/pci/pci_common.c
+++ b/drivers/bus/pci/pci_common.c
@@ -249,6 +249,9 @@ pci_probe_all_drivers(struct rte_pci_device *dev)
 	if (dev->driver != NULL)
 		return 0;
 
+	if (rte_pci_devargs_process(dev) < 0)
+		return -1;
+
 	FOREACH_DRIVER_ON_PCIBUS(dr) {
 		rc = rte_pci_probe_one_driver(dr, dev);
 		if (rc < 0)
diff --git a/drivers/bus/pci/pci_params.c b/drivers/bus/pci/pci_params.c
index a09af3b1c..f34bf3da9 100644
--- a/drivers/bus/pci/pci_params.c
+++ b/drivers/bus/pci/pci_params.c
@@ -127,3 +127,13 @@ rte_pci_devargs_prepare(struct rte_devargs *devargs)
 	rte_kvargs_free(kvargs);
 	return ret;
 }
+
+int
+rte_pci_devargs_process(struct rte_pci_device *pdev)
+{
+	/* For the moment, no PCI param
+	 * needs to be processed.
+	 */
+	(void) pdev;
+	return 0;
+}
diff --git a/drivers/bus/pci/private.h b/drivers/bus/pci/private.h
index 9beb24c6a..06dc85e85 100644
--- a/drivers/bus/pci/private.h
+++ b/drivers/bus/pci/private.h
@@ -207,4 +207,17 @@ rte_pci_dev_iterate(const void *start,
 int
 rte_pci_devargs_prepare(struct rte_devargs *da);
 
+/*
+ * Process the device devargs, if any.
+ *
+ * @param pdev
+ *   PCI device
+ *
+ * @return
+ *   0 on success.
+ *   <0 on error.
+ */
+int
+rte_pci_devargs_process(struct rte_pci_device *pdev);
+
 #endif /* _PCI_PRIVATE_H_ */
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 24/25] ethdev: process declarative eth devargs
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (22 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 23/25] bus/pci: process declarative PCI devargs Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 25/25] eal: add generic dev parameter Gaetan Rivet
  2018-07-15 21:54   ` [dpdk-dev] [PATCH v11 00/25] Device querying Thomas Monjalon
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Process the class-specific arguments in a devargs.
This processing takes the form of setting the proper eth_dev fields when
relevant.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_ethdev/eth_private.h   |  5 +++
 lib/librte_ethdev/rte_class_eth.c | 62 +++++++++++++++++++++++++++++++
 lib/librte_ethdev/rte_ethdev.c    |  7 ++++
 3 files changed, 74 insertions(+)

diff --git a/lib/librte_ethdev/eth_private.h b/lib/librte_ethdev/eth_private.h
index 0f5c6d5c4..c0c065165 100644
--- a/lib/librte_ethdev/eth_private.h
+++ b/lib/librte_ethdev/eth_private.h
@@ -19,6 +19,11 @@ struct rte_eth_dev *
 eth_find_device(const struct rte_eth_dev *_start, rte_eth_cmp_t cmp,
 		const void *data);
 
+/* Generic rte_eth_dev parameters processor. */
+int
+rte_eth_dev_args_parse(struct rte_eth_dev *eth_dev,
+		       struct rte_devargs *da);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_ethdev/rte_class_eth.c b/lib/librte_ethdev/rte_class_eth.c
index d8d8e8845..18fdef605 100644
--- a/lib/librte_ethdev/rte_class_eth.c
+++ b/lib/librte_ethdev/rte_class_eth.c
@@ -6,6 +6,7 @@
 
 #include <rte_class.h>
 #include <rte_compat.h>
+#include <rte_devargs.h>
 #include <rte_errno.h>
 #include <rte_kvargs.h>
 #include <rte_log.h>
@@ -35,6 +36,19 @@ struct eth_dev_match_arg {
 		.kvlist = (k), \
 	})
 
+typedef int (*eth_dev_set_t)(struct rte_eth_dev *edev, const char *value);
+
+static enum eth_params
+ethdev_param_id(const char *key)
+{
+	int i;
+
+	for (i = 0; i < RTE_ETH_PARAMS_MAX; i++)
+		if (strcmp(key, eth_params_keys[i]) == 0)
+			return i;
+	return RTE_ETH_PARAMS_MAX;
+}
+
 static int
 eth_dev_match(const struct rte_eth_dev *edev,
 	      const void *_arg)
@@ -79,6 +93,54 @@ eth_dev_iterate(const void *start,
 	return edev;
 }
 
+static int
+eth_dev_set_name(struct rte_eth_dev *edev,
+		 const char *value)
+{
+	snprintf(edev->data->name,
+		 sizeof(edev->data->name),
+		 "%s", value);
+	return 0;
+}
+
+static int
+ethdev_args_process(const char *key,
+		    const char *value,
+		    void *_edev)
+{
+	static eth_dev_set_t eth_dev_set[] = {
+		[RTE_ETH_PARAMS_NAME] = eth_dev_set_name,
+		[RTE_ETH_PARAMS_MAX] = NULL,
+	};
+	struct rte_eth_dev *edev = _edev;
+	int param;
+
+	param = ethdev_param_id(key);
+	if (eth_dev_set[param])
+		return eth_dev_set[param](edev, value);
+	return 0;
+}
+
+int
+rte_eth_dev_args_parse(struct rte_eth_dev *edev,
+		       struct rte_devargs *devargs)
+{
+	struct rte_kvargs *kvargs = NULL;
+
+	if (devargs == NULL || devargs->cls_str == NULL)
+		return 0;
+
+	kvargs = rte_kvargs_parse_delim(devargs->cls_str, eth_params_keys, "/");
+	if (kvargs == NULL) {
+		RTE_LOG(ERR, EAL, "cannot parse argument list\n");
+		return -EINVAL;
+	}
+	if (rte_kvargs_process(kvargs, NULL, ethdev_args_process, edev))
+		return -1;
+	rte_kvargs_free(kvargs);
+	return 0;
+}
+
 struct rte_class rte_class_eth = {
 	.dev_iterate = eth_dev_iterate,
 };
diff --git a/lib/librte_ethdev/rte_ethdev.c b/lib/librte_ethdev/rte_ethdev.c
index 98e089e58..cee4f5bee 100644
--- a/lib/librte_ethdev/rte_ethdev.c
+++ b/lib/librte_ethdev/rte_ethdev.c
@@ -41,6 +41,7 @@
 #include "rte_ethdev.h"
 #include "rte_ethdev_driver.h"
 #include "ethdev_profile.h"
+#include "eth_private.h"
 
 int rte_eth_dev_logtype;
 
@@ -3486,6 +3487,12 @@ rte_eth_dev_create(struct rte_device *device, const char *name,
 		}
 	}
 
+	retval = rte_eth_dev_args_parse(ethdev, device->devargs);
+	if (retval) {
+		RTE_LOG(ERR, EAL, "ethdev parsing failed");
+		goto probe_failed;
+	}
+
 	retval = ethdev_init(ethdev, init_params);
 	if (retval) {
 		RTE_LOG(ERR, EAL, "ethdev initialisation failed");
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* [dpdk-dev] [PATCH v11 25/25] eal: add generic dev parameter
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (23 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 24/25] ethdev: process declarative eth devargs Gaetan Rivet
@ 2018-07-11 21:45   ` Gaetan Rivet
  2018-07-15 21:54   ` [dpdk-dev] [PATCH v11 00/25] Device querying Thomas Monjalon
  25 siblings, 0 replies; 364+ messages in thread
From: Gaetan Rivet @ 2018-07-11 21:45 UTC (permalink / raw)
  To: dev; +Cc: Gaetan Rivet

Add the --dev parameter to the EAL.
This new parameter takes a generic device declaration as argument.

It uses the new devargs parsing API.

Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
---
 lib/librte_eal/common/eal_common_devargs.c |  4 +++
 lib/librte_eal/common/eal_common_options.c | 36 +++++++++++++++++++---
 lib/librte_eal/common/eal_options.h        |  2 ++
 3 files changed, 37 insertions(+), 5 deletions(-)

diff --git a/lib/librte_eal/common/eal_common_devargs.c b/lib/librte_eal/common/eal_common_devargs.c
index a22a2002e..22913b408 100644
--- a/lib/librte_eal/common/eal_common_devargs.c
+++ b/lib/librte_eal/common/eal_common_devargs.c
@@ -219,6 +219,10 @@ rte_devargs_parse(struct rte_devargs *da, const char *dev)
 	if (da == NULL)
 		return -EINVAL;
 
+	if (strncmp(dev, "bus=", 4) == 0 ||
+	    strncmp(dev, "class=", 6) == 0)
+		return rte_devargs_layers_parse(da, dev);
+
 	/* Retrieve eventual bus info */
 	do {
 		devname = dev;
diff --git a/lib/librte_eal/common/eal_common_options.c b/lib/librte_eal/common/eal_common_options.c
index ecebb2923..89d608180 100644
--- a/lib/librte_eal/common/eal_common_options.c
+++ b/lib/librte_eal/common/eal_common_options.c
@@ -54,6 +54,7 @@ const struct option
 eal_long_options[] = {
 	{OPT_BASE_VIRTADDR,     1, NULL, OPT_BASE_VIRTADDR_NUM    },
 	{OPT_CREATE_UIO_DEV,    0, NULL, OPT_CREATE_UIO_DEV_NUM   },
+	{OPT_DEV,               1, NULL, OPT_DEV_NUM              },
 	{OPT_FILE_PREFIX,       1, NULL, OPT_FILE_PREFIX_NUM      },
 	{OPT_HELP,              0, NULL, OPT_HELP_NUM             },
 	{OPT_HUGE_DIR,          1, NULL, OPT_HUGE_DIR_NUM         },
@@ -109,6 +110,7 @@ TAILQ_HEAD(device_option_list, device_option);
 struct device_option {
 	TAILQ_ENTRY(device_option) next;
 
+	int new;
 	enum rte_devtype type;
 	char arg[];
 };
@@ -121,7 +123,8 @@ static int mem_parsed;
 static int core_parsed;
 
 static int
-eal_option_device_add(enum rte_devtype type, const char *optarg)
+eal_option_device_add(enum rte_devtype type, const char *optarg,
+		      int new)
 {
 	struct device_option *devopt;
 	size_t optlen;
@@ -135,6 +138,7 @@ eal_option_device_add(enum rte_devtype type, const char *optarg)
 	}
 
 	devopt->type = type;
+	devopt->new = new;
 	ret = snprintf(devopt->arg, optlen, "%s", optarg);
 	if (ret < 0) {
 		RTE_LOG(ERR, EAL, "Unable to copy device option\n");
@@ -154,7 +158,22 @@ eal_option_device_parse(void)
 
 	TAILQ_FOREACH_SAFE(devopt, &devopt_list, next, tmp) {
 		if (ret == 0) {
-			ret = rte_devargs_add(devopt->type, devopt->arg);
+			if (devopt->new) {
+				struct rte_devargs *da;
+
+				da = calloc(1, sizeof(*da));
+				ret = rte_devargs_parse(da, devopt->arg);
+				if (ret) {
+					free(da);
+				} else {
+					ret = rte_devargs_insert(da);
+					if (ret)
+						free(da);
+				}
+			} else {
+				ret = rte_devargs_add(devopt->type,
+						      devopt->arg);
+			}
 			if (ret)
 				RTE_LOG(ERR, EAL, "Unable to parse device '%s'\n",
 					devopt->arg);
@@ -1038,7 +1057,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		if (w_used)
 			goto bw_used;
 		if (eal_option_device_add(RTE_DEVTYPE_BLACKLISTED_PCI,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		b_used = 1;
@@ -1048,7 +1067,7 @@ eal_parse_common_option(int opt, const char *optarg,
 		if (b_used)
 			goto bw_used;
 		if (eal_option_device_add(RTE_DEVTYPE_WHITELISTED_PCI,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		w_used = 1;
@@ -1177,9 +1196,16 @@ eal_parse_common_option(int opt, const char *optarg,
 		}
 		break;
 
+	case OPT_DEV_NUM:
+		if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
+				optarg, 1) < 0) {
+			return -1;
+		}
+		break;
+
 	case OPT_VDEV_NUM:
 		if (eal_option_device_add(RTE_DEVTYPE_VIRTUAL,
-				optarg) < 0) {
+				optarg, 0) < 0) {
 			return -1;
 		}
 		break;
diff --git a/lib/librte_eal/common/eal_options.h b/lib/librte_eal/common/eal_options.h
index 211ae06ae..b1851864f 100644
--- a/lib/librte_eal/common/eal_options.h
+++ b/lib/librte_eal/common/eal_options.h
@@ -21,6 +21,8 @@ enum {
 	OPT_BASE_VIRTADDR_NUM,
 #define OPT_CREATE_UIO_DEV    "create-uio-dev"
 	OPT_CREATE_UIO_DEV_NUM,
+#define OPT_DEV               "dev"
+	OPT_DEV_NUM,
 #define OPT_FILE_PREFIX       "file-prefix"
 	OPT_FILE_PREFIX_NUM,
 #define OPT_HUGE_DIR          "huge-dir"
-- 
2.18.0

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction Gaetan Rivet
@ 2018-07-12  6:49     ` Shreyansh Jain
  2018-07-12  7:41       ` Gaëtan Rivet
  2018-07-14  6:37     ` Thomas Monjalon
  1 sibling, 1 reply; 364+ messages in thread
From: Shreyansh Jain @ 2018-07-12  6:49 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Thursday 12 July 2018 03:14 AM, Gaetan Rivet wrote:
> This abstraction exists since the infancy of DPDK.
> It needs to be fleshed out however, to allow a generic
> description of devices properties and capabilities.
> 
> A device class is the northbound interface of the device, intended
> for applications to know what it can be used for.
> 
> It is conceptually just above buses.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---

[...]

> --- a/lib/librte_eal/rte_eal_version.map
> +++ b/lib/librte_eal/rte_eal_version.map
> @@ -244,6 +244,8 @@ DPDK_18.05 {
>   EXPERIMENTAL {
>   	global:
>   
> +	rte_class_register;
> +	rte_class_unregister;
>   	rte_ctrl_thread_create;
>   	rte_dev_event_callback_register;
>   	rte_dev_event_callback_unregister;
> 

Any reason you don't want the rte_class_find and rte_class_find_by_name 
as exposed APIs? There is no experimental tag on these APIs either.

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction
  2018-07-12  6:49     ` Shreyansh Jain
@ 2018-07-12  7:41       ` Gaëtan Rivet
  2018-07-14 10:35         ` Thomas Monjalon
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-07-12  7:41 UTC (permalink / raw)
  To: Shreyansh Jain; +Cc: dev

On Thu, Jul 12, 2018 at 12:19:09PM +0530, Shreyansh Jain wrote:
> On Thursday 12 July 2018 03:14 AM, Gaetan Rivet wrote:
> > This abstraction exists since the infancy of DPDK.
> > It needs to be fleshed out however, to allow a generic
> > description of devices properties and capabilities.
> > 
> > A device class is the northbound interface of the device, intended
> > for applications to know what it can be used for.
> > 
> > It is conceptually just above buses.
> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> 
> [...]
> 
> > --- a/lib/librte_eal/rte_eal_version.map
> > +++ b/lib/librte_eal/rte_eal_version.map
> > @@ -244,6 +244,8 @@ DPDK_18.05 {
> >   EXPERIMENTAL {
> >   	global:
> > +	rte_class_register;
> > +	rte_class_unregister;
> >   	rte_ctrl_thread_create;
> >   	rte_dev_event_callback_register;
> >   	rte_dev_event_callback_unregister;
> > 
> 
> Any reason you don't want the rte_class_find and rte_class_find_by_name as
> exposed APIs? There is no experimental tag on these APIs either.
> 

No actually I just overlooked that part! Thanks for catching this, I
think it should be exposed and tagged experimental.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers Gaetan Rivet
@ 2018-07-12  9:48     ` Shreyansh Jain
  2018-07-14 10:30     ` Thomas Monjalon
  1 sibling, 0 replies; 364+ messages in thread
From: Shreyansh Jain @ 2018-07-12  9:48 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Thursday 12 July 2018 03:14 AM, Gaetan Rivet wrote:
> 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>
> ---
>   lib/librte_eal/common/eal_common_devargs.c  | 144 ++++++++++++++++++++
>   lib/librte_eal/common/eal_private.h         |  34 +++++
>   lib/librte_eal/common/include/rte_devargs.h |  13 +-
>   3 files changed, 188 insertions(+), 3 deletions(-)
> 

[...]

Acked-by: Shreyansh Jain <shreyansh.jain@nxp.com>

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration Gaetan Rivet
@ 2018-07-12 10:58     ` Shreyansh Jain
  2018-07-12 15:08       ` Gaëtan Rivet
  0 siblings, 1 reply; 364+ messages in thread
From: Shreyansh Jain @ 2018-07-12 10:58 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

On Thursday 12 July 2018 03:15 AM, Gaetan Rivet wrote:
> Use the iteration hooks in the abstraction layers to perform the
> requested filtering on the internal device lists.
> 
> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> ---
>   lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++
>   lib/librte_eal/common/include/rte_dev.h |  26 ++++
>   lib/librte_eal/rte_eal_version.map      |   1 +
>   3 files changed, 195 insertions(+)
> 
> diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
> index 63e329bd8..b78845f02 100644
> --- a/lib/librte_eal/common/eal_common_dev.c
> +++ b/lib/librte_eal/common/eal_common_dev.c
> @@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
>   /* spinlock for device callbacks */
>   static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
>   
> +struct dev_next_ctx {
> +	struct rte_dev_iterator *it;
> +	const char *bus_str;
> +	const char *cls_str;
> +};
> +
> +#define CTX(it, bus_str, cls_str) \
> +	(&(const struct dev_next_ctx){ \
> +		.it = it, \
> +		.bus_str = bus_str, \
> +		.cls_str = cls_str, \
> +	})
> +
> +#define ITCTX(ptr) \
> +	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
> +
> +#define BUSCTX(ptr) \
> +	(((struct dev_next_ctx *)(intptr_t)ptr)->bus_str)
> +
> +#define CLSCTX(ptr) \
> +	(((struct dev_next_ctx *)(intptr_t)ptr)->cls_str)
> +
>   static int cmp_detached_dev_name(const struct rte_device *dev,
>   	const void *_name)
>   {
> @@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
>   get_out:
>   	return -rte_errno;
>   }
> +
> +static char *
> +dev_str_sane_copy(const char *str)
> +{
> +	size_t end;
> +	char *copy;
> +
> +	end = strcspn(str, ",/");
> +	if (str[end] == ',') {
> +		copy = strdup(&str[end + 1]);
> +	} else {
> +		/* '/' or '\0' */
> +		copy = strdup("");
> +	}

Though it doesn't change anything functionally, if you can separate 
blocks of if-else with new lines, it really makes it easier to read.
Like here...

> +	if (copy == NULL) {
> +		rte_errno = ENOMEM;
> +	} else {
> +		char *slash;
> +
> +		slash = strchr(copy, '/');
> +		if (slash != NULL)
> +			slash[0] = '\0';
> +	}
> +	return copy;
> +}
> +
> +static int
> +class_next_dev_cmp(const struct rte_class *cls,
> +		   const void *ctx)
> +{
> +	struct rte_dev_iterator *it;
> +	const char *cls_str = NULL;
> +	void *dev;
> +
> +	if (cls->dev_iterate == NULL)
> +		return 1;
> +	it = ITCTX(ctx);
> +	cls_str = CLSCTX(ctx);
> +	dev = it->class_device;
> +	/* it->cls_str != NULL means a class
> +	 * was specified in the devstr.
> +	 */
> +	if (it->cls_str != NULL && cls != it->cls)
> +		return 1;
> +	/* If an error occurred previously,
> +	 * no need to test further.
> +	 */
> +	if (rte_errno != 0)
> +		return -1;

I am guessing here by '..error occurred previously..' you mean 
sane_copy. If so, why wait until this point to return? Anyway the caller 
(rte_bus_find, probably) would only look for '0' or non-zero.

> +	dev = cls->dev_iterate(dev, cls_str, it);
> +	it->class_device = dev;
> +	return dev == NULL;
> +}
> +
> +static int
> +bus_next_dev_cmp(const struct rte_bus *bus,
> +		 const void *ctx)
> +{
> +	struct rte_device *dev = NULL;
> +	struct rte_class *cls = NULL;
> +	struct rte_dev_iterator *it;
> +	const char *bus_str = NULL;
> +
> +	if (bus->dev_iterate == NULL)
> +		return 1;
> +	it = ITCTX(ctx);
> +	bus_str = BUSCTX(ctx);
> +	dev = it->device;
> +	/* it->bus_str != NULL means a bus
> +	 * was specified in the devstr.
> +	 */
> +	if (it->bus_str != NULL && bus != it->bus)
> +		return 1;
> +	/* If an error occurred previously,
> +	 * no need to test further.
> +	 */
> +	if (rte_errno != 0)
> +		return -1;
> +	if (it->cls_str == NULL) {
> +		dev = bus->dev_iterate(dev, bus_str, it);
> +		goto end;

This is slightly confusing. If it->cls_str == NULL, you do 
bus->dev_iterate... but

> +	}
> +	/* cls_str != NULL */
> +	if (dev == NULL) {
> +next_dev_on_bus:
> +		dev = bus->dev_iterate(dev, bus_str, it);

When cls_str!=NULL, you still do bus->dev_iterate...
So, maybe they are OR case resulting in check of dev==NULL and return 
(as being done right now by jumping to out)...?

And, how can bus iterate over a 'null' device?

> +		it->device = dev;
> +	}
> +	if (dev == NULL)
> +		return 1;

Maybe, this check should move in the if(dev==NULL) above - that way, it 
can in path of 'next_dev_on_bus' yet do the same as function as its 
current location.

> +	if (it->cls != NULL)

In what case would (it->cls_str == NULL) but (it->cls != NULL)?

> +		cls = TAILQ_PREV(it->cls, rte_class_list, next);
> +	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
> +	if (cls != NULL) {
> +		it->cls = cls;
> +		goto end;
> +	}
> +	goto next_dev_on_bus;

Maybe I have completely mixed your intention of this function. So, if 
you still find the above comments naive - maybe you can tell me what you 
are attempting here?
Is it: find next bus and stop if no class specified. find next class as 
well, iff that too was specified?

Reason I am confused is that bus_next_dev_cmp attempts to compare both - 
bus and class, yet class_next_dev_cmp simply stops by comparing class only.

> +end:
> +	it->device = dev;
> +	return dev == NULL;
> +}

A new line should be added here - start of a new function.

> +__rte_experimental
> +struct rte_device *
> +rte_dev_iterator_next(struct rte_dev_iterator *it)
> +{
> +	struct rte_bus *bus = NULL;
> +	int old_errno = rte_errno;
> +	char *bus_str = NULL;
> +	char *cls_str = NULL;
> +
> +	rte_errno = 0;
> +	if (it->bus_str == NULL && it->cls_str == NULL) {
> +		/* Invalid iterator. */
> +		rte_errno = EINVAL;
> +		return NULL;
> +	}
> +	if (it->bus != NULL)
> +		bus = TAILQ_PREV(it->bus, rte_bus_list, next);
> +	if (it->bus_str != NULL) {
> +		bus_str = dev_str_sane_copy(it->bus_str);
> +		if (bus_str == NULL)
> +			goto out;
> +	}
> +	if (it->cls_str != NULL) {
> +		cls_str = dev_str_sane_copy(it->cls_str);
> +		if (cls_str == NULL)
> +			goto out;
> +	}
> +	while ((bus = rte_bus_find(bus, bus_next_dev_cmp,
> +				   CTX(it, bus_str, cls_str)))) {
> +		if (it->device != NULL) {
> +			it->bus = bus;
> +			goto out;
> +		}
> +		if (it->bus_str != NULL ||
> +		    rte_errno != 0)
> +			break;
> +	}
> +	if (rte_errno == 0)
> +		rte_errno = old_errno;
> +out:
> +	free(bus_str);
> +	free(cls_str);
> +	return it->device;
> +}
> diff --git a/lib/librte_eal/common/include/rte_dev.h b/lib/librte_eal/common/include/rte_dev.h
> index fdc812ff8..8638a2bbd 100644
> --- a/lib/librte_eal/common/include/rte_dev.h
> +++ b/lib/librte_eal/common/include/rte_dev.h
> @@ -355,6 +355,32 @@ __rte_experimental
>   int
>   rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str);
>   
> +/**
> + * Iterates on a device iterator.
> + *
> + * Generates a new rte_device handle corresponding to the next element
> + * in the list described in comprehension by the iterator.
> + *
> + * The next object is returned, and the iterator is updated.
> + *
> + * @param it
> + *   Device iterator handle.
> + *
> + * @return
> + *   An rte_device handle if found.
> + *   NULL if an error occurred (rte_errno is set).
> + *   NULL if no device could be found (rte_errno is not set).
> + */
> +__rte_experimental
> +struct rte_device *
> +rte_dev_iterator_next(struct rte_dev_iterator *it);
> +
> +#define RTE_DEV_FOREACH(dev, devstr, it) \
> +	for (rte_dev_iterator_init(it, devstr), \
> +	     dev = rte_dev_iterator_next(it); \
> +	     dev != NULL; \
> +	     dev = rte_dev_iterator_next(it))
> +
>   #ifdef __cplusplus
>   }
>   #endif
> diff --git a/lib/librte_eal/rte_eal_version.map b/lib/librte_eal/rte_eal_version.map
> index ac04120d6..4cd5ab3df 100644
> --- a/lib/librte_eal/rte_eal_version.map
> +++ b/lib/librte_eal/rte_eal_version.map
> @@ -252,6 +252,7 @@ EXPERIMENTAL {
>   	rte_dev_event_monitor_start;
>   	rte_dev_event_monitor_stop;
>   	rte_dev_iterator_init;
> +	rte_dev_iterator_next;
>   	rte_devargs_add;
>   	rte_devargs_dump;
>   	rte_devargs_insert;
> 

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration
  2018-07-12 10:58     ` Shreyansh Jain
@ 2018-07-12 15:08       ` Gaëtan Rivet
  2018-07-13  7:06         ` Shreyansh Jain
  0 siblings, 1 reply; 364+ messages in thread
From: Gaëtan Rivet @ 2018-07-12 15:08 UTC (permalink / raw)
  To: Shreyansh Jain; +Cc: dev

Hi Shreyansh,

On Thu, Jul 12, 2018 at 04:28:27PM +0530, Shreyansh Jain wrote:
> On Thursday 12 July 2018 03:15 AM, Gaetan Rivet wrote:
> > Use the iteration hooks in the abstraction layers to perform the
> > requested filtering on the internal device lists.
> > 
> > Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
> > ---
> >   lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++
> >   lib/librte_eal/common/include/rte_dev.h |  26 ++++
> >   lib/librte_eal/rte_eal_version.map      |   1 +
> >   3 files changed, 195 insertions(+)
> > 
> > diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
> > index 63e329bd8..b78845f02 100644
> > --- a/lib/librte_eal/common/eal_common_dev.c
> > +++ b/lib/librte_eal/common/eal_common_dev.c
> > @@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
> >   /* spinlock for device callbacks */
> >   static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
> > +struct dev_next_ctx {
> > +	struct rte_dev_iterator *it;
> > +	const char *bus_str;
> > +	const char *cls_str;
> > +};
> > +
> > +#define CTX(it, bus_str, cls_str) \
> > +	(&(const struct dev_next_ctx){ \
> > +		.it = it, \
> > +		.bus_str = bus_str, \
> > +		.cls_str = cls_str, \
> > +	})
> > +
> > +#define ITCTX(ptr) \
> > +	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
> > +
> > +#define BUSCTX(ptr) \
> > +	(((struct dev_next_ctx *)(intptr_t)ptr)->bus_str)
> > +
> > +#define CLSCTX(ptr) \
> > +	(((struct dev_next_ctx *)(intptr_t)ptr)->cls_str)
> > +
> >   static int cmp_detached_dev_name(const struct rte_device *dev,
> >   	const void *_name)
> >   {
> > @@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
> >   get_out:
> >   	return -rte_errno;
> >   }
> > +
> > +static char *
> > +dev_str_sane_copy(const char *str)
> > +{
> > +	size_t end;
> > +	char *copy;
> > +
> > +	end = strcspn(str, ",/");
> > +	if (str[end] == ',') {
> > +		copy = strdup(&str[end + 1]);
> > +	} else {
> > +		/* '/' or '\0' */
> > +		copy = strdup("");
> > +	}
> 
> Though it doesn't change anything functionally, if you can separate blocks
> of if-else with new lines, it really makes it easier to read.
> Like here...
> 

sure,

> > +	if (copy == NULL) {
> > +		rte_errno = ENOMEM;
> > +	} else {
> > +		char *slash;
> > +
> > +		slash = strchr(copy, '/');
> > +		if (slash != NULL)
> > +			slash[0] = '\0';
> > +	}
> > +	return copy;
> > +}
> > +
> > +static int
> > +class_next_dev_cmp(const struct rte_class *cls,
> > +		   const void *ctx)
> > +{
> > +	struct rte_dev_iterator *it;
> > +	const char *cls_str = NULL;
> > +	void *dev;
> > +
> > +	if (cls->dev_iterate == NULL)
> > +		return 1;
> > +	it = ITCTX(ctx);
> > +	cls_str = CLSCTX(ctx);
> > +	dev = it->class_device;
> > +	/* it->cls_str != NULL means a class
> > +	 * was specified in the devstr.
> > +	 */
> > +	if (it->cls_str != NULL && cls != it->cls)
> > +		return 1;
> > +	/* If an error occurred previously,
> > +	 * no need to test further.
> > +	 */
> > +	if (rte_errno != 0)
> > +		return -1;
> 
> I am guessing here by '..error occurred previously..' you mean sane_copy. If
> so, why wait until this point to return? Anyway the caller (rte_bus_find,
> probably) would only look for '0' or non-zero.
> 

No, rte_errno could be set by a bus / class implementation, for any
error occurring during a call to dev_iterate: maybe a device was lost
(hotplugged), etc. The return value of dev_iterate() cannot transmit an
error as not matching a filter is not an error. The only error channel
is rte_errno.

sane_copy was already checked before and should be cleared at this
point.

> > +	dev = cls->dev_iterate(dev, cls_str, it);
> > +	it->class_device = dev;
> > +	return dev == NULL;
> > +}
> > +
> > +static int
> > +bus_next_dev_cmp(const struct rte_bus *bus,
> > +		 const void *ctx)
> > +{
> > +	struct rte_device *dev = NULL;
> > +	struct rte_class *cls = NULL;
> > +	struct rte_dev_iterator *it;
> > +	const char *bus_str = NULL;
> > +
> > +	if (bus->dev_iterate == NULL)
> > +		return 1;
> > +	it = ITCTX(ctx);
> > +	bus_str = BUSCTX(ctx);
> > +	dev = it->device;
> > +	/* it->bus_str != NULL means a bus
> > +	 * was specified in the devstr.
> > +	 */
> > +	if (it->bus_str != NULL && bus != it->bus)
> > +		return 1;
> > +	/* If an error occurred previously,
> > +	 * no need to test further.
> > +	 */
> > +	if (rte_errno != 0)
> > +		return -1;
> > +	if (it->cls_str == NULL) {
> > +		dev = bus->dev_iterate(dev, bus_str, it);
> > +		goto end;
> 
> This is slightly confusing. If it->cls_str == NULL, you do
> bus->dev_iterate... but
> 
> > +	}
> > +	/* cls_str != NULL */
> > +	if (dev == NULL) {
> > +next_dev_on_bus:
> > +		dev = bus->dev_iterate(dev, bus_str, it);
> 
> When cls_str!=NULL, you still do bus->dev_iterate...
> So, maybe they are OR case resulting in check of dev==NULL and return (as
> being done right now by jumping to out)...?
> 

Yes, this iteration is pretty complex.

The best way to walk through it is to define the possible cases:

1. Iterating on one bus:

   if (bus_str != NULL && cls_str == NULL)

   Simplest case. You got one bus, no classes.
   Just call the current bus dev_iterate() callback, then report
   the result (whether NULL or not).

2. Iterating on one bus and one class:

   if (bus_str != NULL && cls_str != NULL)

   Possible states are:

   a. We are starting the iteration: dev is NULL.
      Iterate on the current bus.

      If device is not NULL anymore, iterate on the class.
      To ensure we stay on the same class, set cls to the previous class
      and call rte_class_find();

      If device is still NULL, return 1 to iterate on the next bus.

   b. We are in the middle of an iteration: dev is not NULL.
      We start iterating on the class to find a possible second instance
      of the same device in the class (e.g. mlx devices with multiple
      eth ports per PCI devices). If none is found, we
      come back to bus->dev_iterate() (bypassing the dev == NULL check),
      restarting this (b) cycle as many times as necessary.
      If the result is NULL, the iteration is finished.

3. Iterating on one class:

    if (bus_str == NULL && cls_str != NULL)

    The most complex case. Same as (2), however we start by the first
    bus, and if a device is NULL we will continue onto the next bus
    within the loop line 554 (within rte_dev_iterator_next).


The core of the complexity here lies in the next_dev_on_bus cycle
described in 2.b.

> And, how can bus iterate over a 'null' device?
> 

A NULL device means that we are starting the iteration: a bus will give
its first device.

> > +		it->device = dev;
> > +	}
> > +	if (dev == NULL)
> > +		return 1;
> 
> Maybe, this check should move in the if(dev==NULL) above - that way, it can
> in path of 'next_dev_on_bus' yet do the same as function as its current
> location.
> 

Yes

> > +	if (it->cls != NULL)
> 
> In what case would (it->cls_str == NULL) but (it->cls != NULL)?
> 

When one rte_device was used to spawn several class_devices: multiple
adapters per PCI addresses for example.

However, in this case, given that the matching would be useless, we skip
the class matching process and only return the rte_device. This single
rte_device is not returned multiple times.

However, if someone was giving:

bus=pci,id=00:02.0/class=eth
(str_sane_copy would set cls_str to "" here)

Then, if 00:02.0 had spawned several eth ports, it would be returned
once for each instance.

This is a pretty ambiguous case. I'm not sure of the best way to deal with
it. My decision here was to simplify the iteration if possible, as I
considered that someone that did not care for the class properties would
not care about counting the instances of the bus device. maybe I'm
wrong.

> > +		cls = TAILQ_PREV(it->cls, rte_class_list, next);
> > +	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
> > +	if (cls != NULL) {
> > +		it->cls = cls;
> > +		goto end;
> > +	}
> > +	goto next_dev_on_bus;
> 
> Maybe I have completely mixed your intention of this function. So, if you
> still find the above comments naive - maybe you can tell me what you are
> attempting here?
> Is it: find next bus and stop if no class specified. find next class as
> well, iff that too was specified?
> 
> Reason I am confused is that bus_next_dev_cmp attempts to compare both - bus
> and class, yet class_next_dev_cmp simply stops by comparing class only.
> 

You are right: bus comparator will produce an iteration on the bus
devices, then on the class devices iff class is specified.

Thus the class comparator only has to iterate on class, because we
called it from the bus iterator.

> > +end:
> > +	it->device = dev;
> > +	return dev == NULL;
> > +}
> 
> A new line should be added here - start of a new function.
> 

yes


I'm pretty sorry about this code, to be honest.
This is a nasty piece with a lot of states to care for.

At least it works. I'd like to have the properties integrated so that
developpers can add their own quickly. In the meantime I could rework
this function. But simple is not easy.

-- 
Gaëtan Rivet
6WIND

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration
  2018-07-12 15:08       ` Gaëtan Rivet
@ 2018-07-13  7:06         ` Shreyansh Jain
  0 siblings, 0 replies; 364+ messages in thread
From: Shreyansh Jain @ 2018-07-13  7:06 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev

(I am not reducing the thread as it contains quite interesting 
discussion - so, you might have to fish for inline comments...)

On Thursday 12 July 2018 08:38 PM, Gaëtan Rivet wrote:
> Hi Shreyansh,
> 
> On Thu, Jul 12, 2018 at 04:28:27PM +0530, Shreyansh Jain wrote:
>> On Thursday 12 July 2018 03:15 AM, Gaetan Rivet wrote:
>>> Use the iteration hooks in the abstraction layers to perform the
>>> requested filtering on the internal device lists.
>>>
>>> Signed-off-by: Gaetan Rivet <gaetan.rivet@6wind.com>
>>> ---
>>>    lib/librte_eal/common/eal_common_dev.c  | 168 ++++++++++++++++++++++++
>>>    lib/librte_eal/common/include/rte_dev.h |  26 ++++
>>>    lib/librte_eal/rte_eal_version.map      |   1 +
>>>    3 files changed, 195 insertions(+)
>>>
>>> diff --git a/lib/librte_eal/common/eal_common_dev.c b/lib/librte_eal/common/eal_common_dev.c
>>> index 63e329bd8..b78845f02 100644
>>> --- a/lib/librte_eal/common/eal_common_dev.c
>>> +++ b/lib/librte_eal/common/eal_common_dev.c
>>> @@ -45,6 +45,28 @@ static struct dev_event_cb_list dev_event_cbs;
>>>    /* spinlock for device callbacks */
>>>    static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER;
>>> +struct dev_next_ctx {
>>> +	struct rte_dev_iterator *it;
>>> +	const char *bus_str;
>>> +	const char *cls_str;
>>> +};
>>> +
>>> +#define CTX(it, bus_str, cls_str) \
>>> +	(&(const struct dev_next_ctx){ \
>>> +		.it = it, \
>>> +		.bus_str = bus_str, \
>>> +		.cls_str = cls_str, \
>>> +	})
>>> +
>>> +#define ITCTX(ptr) \
>>> +	(((struct dev_next_ctx *)(intptr_t)ptr)->it)
>>> +
>>> +#define BUSCTX(ptr) \
>>> +	(((struct dev_next_ctx *)(intptr_t)ptr)->bus_str)
>>> +
>>> +#define CLSCTX(ptr) \
>>> +	(((struct dev_next_ctx *)(intptr_t)ptr)->cls_str)
>>> +
>>>    static int cmp_detached_dev_name(const struct rte_device *dev,
>>>    	const void *_name)
>>>    {
>>> @@ -398,3 +420,149 @@ rte_dev_iterator_init(struct rte_dev_iterator *it,
>>>    get_out:
>>>    	return -rte_errno;
>>>    }
>>> +
>>> +static char *
>>> +dev_str_sane_copy(const char *str)
>>> +{
>>> +	size_t end;
>>> +	char *copy;
>>> +
>>> +	end = strcspn(str, ",/");
>>> +	if (str[end] == ',') {
>>> +		copy = strdup(&str[end + 1]);
>>> +	} else {
>>> +		/* '/' or '\0' */
>>> +		copy = strdup("");
>>> +	}
>>
>> Though it doesn't change anything functionally, if you can separate blocks
>> of if-else with new lines, it really makes it easier to read.
>> Like here...
>>
> 
> sure,
> 
>>> +	if (copy == NULL) {
>>> +		rte_errno = ENOMEM;
>>> +	} else {
>>> +		char *slash;
>>> +
>>> +		slash = strchr(copy, '/');
>>> +		if (slash != NULL)
>>> +			slash[0] = '\0';
>>> +	}
>>> +	return copy;
>>> +}
>>> +
>>> +static int
>>> +class_next_dev_cmp(const struct rte_class *cls,
>>> +		   const void *ctx)
>>> +{
>>> +	struct rte_dev_iterator *it;
>>> +	const char *cls_str = NULL;
>>> +	void *dev;
>>> +
>>> +	if (cls->dev_iterate == NULL)
>>> +		return 1;
>>> +	it = ITCTX(ctx);
>>> +	cls_str = CLSCTX(ctx);
>>> +	dev = it->class_device;
>>> +	/* it->cls_str != NULL means a class
>>> +	 * was specified in the devstr.
>>> +	 */
>>> +	if (it->cls_str != NULL && cls != it->cls)
>>> +		return 1;
>>> +	/* If an error occurred previously,
>>> +	 * no need to test further.
>>> +	 */
>>> +	if (rte_errno != 0)
>>> +		return -1;
>>
>> I am guessing here by '..error occurred previously..' you mean sane_copy. If
>> so, why wait until this point to return? Anyway the caller (rte_bus_find,
>> probably) would only look for '0' or non-zero.
>>
> 
> No, rte_errno could be set by a bus / class implementation, for any
> error occurring during a call to dev_iterate: maybe a device was lost
> (hotplugged), etc. The return value of dev_iterate() cannot transmit an
> error as not matching a filter is not an error. The only error channel
> is rte_errno.
> 
> sane_copy was already checked before and should be cleared at this
> point.
> 
>>> +	dev = cls->dev_iterate(dev, cls_str, it);
>>> +	it->class_device = dev;
>>> +	return dev == NULL;
>>> +}
>>> +
>>> +static int
>>> +bus_next_dev_cmp(const struct rte_bus *bus,
>>> +		 const void *ctx)
>>> +{
>>> +	struct rte_device *dev = NULL;
>>> +	struct rte_class *cls = NULL;
>>> +	struct rte_dev_iterator *it;
>>> +	const char *bus_str = NULL;
>>> +
>>> +	if (bus->dev_iterate == NULL)
>>> +		return 1;
>>> +	it = ITCTX(ctx);
>>> +	bus_str = BUSCTX(ctx);
>>> +	dev = it->device;
>>> +	/* it->bus_str != NULL means a bus
>>> +	 * was specified in the devstr.
>>> +	 */
>>> +	if (it->bus_str != NULL && bus != it->bus)
>>> +		return 1;
>>> +	/* If an error occurred previously,
>>> +	 * no need to test further.
>>> +	 */
>>> +	if (rte_errno != 0)
>>> +		return -1;
>>> +	if (it->cls_str == NULL) {
>>> +		dev = bus->dev_iterate(dev, bus_str, it);
>>> +		goto end;
>>
>> This is slightly confusing. If it->cls_str == NULL, you do
>> bus->dev_iterate... but
>>
>>> +	}
>>> +	/* cls_str != NULL */
>>> +	if (dev == NULL) {
>>> +next_dev_on_bus:
>>> +		dev = bus->dev_iterate(dev, bus_str, it);
>>
>> When cls_str!=NULL, you still do bus->dev_iterate...
>> So, maybe they are OR case resulting in check of dev==NULL and return (as
>> being done right now by jumping to out)...?
>>
> 
> Yes, this iteration is pretty complex.
> 
> The best way to walk through it is to define the possible cases:
> 
> 1. Iterating on one bus:
> 
>     if (bus_str != NULL && cls_str == NULL)
> 
>     Simplest case. You got one bus, no classes.
>     Just call the current bus dev_iterate() callback, then report
>     the result (whether NULL or not).
> 
> 2. Iterating on one bus and one class:
> 
>     if (bus_str != NULL && cls_str != NULL)
> 
>     Possible states are:
> 
>     a. We are starting the iteration: dev is NULL.
>        Iterate on the current bus.
> 
>        If device is not NULL anymore, iterate on the class.
>        To ensure we stay on the same class, set cls to the previous class
>        and call rte_class_find();
> 
>        If device is still NULL, return 1 to iterate on the next bus.
> 
>     b. We are in the middle of an iteration: dev is not NULL.
>        We start iterating on the class to find a possible second instance
>        of the same device in the class (e.g. mlx devices with multiple
>        eth ports per PCI devices). If none is found, we
>        come back to bus->dev_iterate() (bypassing the dev == NULL check),
>        restarting this (b) cycle as many times as necessary.
>        If the result is NULL, the iteration is finished.
> 
> 3. Iterating on one class:
> 
>      if (bus_str == NULL && cls_str != NULL)
> 
>      The most complex case. Same as (2), however we start by the first
>      bus, and if a device is NULL we will continue onto the next bus
>      within the loop line 554 (within rte_dev_iterator_next).
> 

This, above, is most useful. I had missed out the case (b) above 
entirely. I will re-review with this in mind. Thanks for writing this.

> 
> The core of the complexity here lies in the next_dev_on_bus cycle
> described in 2.b.
> 
>> And, how can bus iterate over a 'null' device?
>>
> 
> A NULL device means that we are starting the iteration: a bus will give
> its first device.
> 
>>> +		it->device = dev;
>>> +	}
>>> +	if (dev == NULL)
>>> +		return 1;
>>
>> Maybe, this check should move in the if(dev==NULL) above - that way, it can
>> in path of 'next_dev_on_bus' yet do the same as function as its current
>> location.
>>
> 
> Yes
> 
>>> +	if (it->cls != NULL)
>>
>> In what case would (it->cls_str == NULL) but (it->cls != NULL)?
>>
> 
> When one rte_device was used to spawn several class_devices: multiple
> adapters per PCI addresses for example.
> 
> However, in this case, given that the matching would be useless, we skip
> the class matching process and only return the rte_device. This single
> rte_device is not returned multiple times.
> 
> However, if someone was giving:
> 
> bus=pci,id=00:02.0/class=eth
> (str_sane_copy would set cls_str to "" here)
> 
> Then, if 00:02.0 had spawned several eth ports, it would be returned
> once for each instance.
> 
> This is a pretty ambiguous case. I'm not sure of the best way to deal with
> it. My decision here was to simplify the iteration if possible, as I
> considered that someone that did not care for the class properties would
> not care about counting the instances of the bus device. maybe I'm
> wrong.

Frankly, I have nothing extra to add as a use-case. For your approach of 
'simple is better': +1

> 
>>> +		cls = TAILQ_PREV(it->cls, rte_class_list, next);
>>> +	cls = rte_class_find(cls, class_next_dev_cmp, ctx);
>>> +	if (cls != NULL) {
>>> +		it->cls = cls;
>>> +		goto end;
>>> +	}
>>> +	goto next_dev_on_bus;
>>
>> Maybe I have completely mixed your intention of this function. So, if you
>> still find the above comments naive - maybe you can tell me what you are
>> attempting here?
>> Is it: find next bus and stop if no class specified. find next class as
>> well, iff that too was specified?
>>
>> Reason I am confused is that bus_next_dev_cmp attempts to compare both - bus
>> and class, yet class_next_dev_cmp simply stops by comparing class only.
>>
> 
> You are right: bus comparator will produce an iteration on the bus
> devices, then on the class devices iff class is specified.
> 
> Thus the class comparator only has to iterate on class, because we
> called it from the bus iterator.
> 
>>> +end:
>>> +	it->device = dev;
>>> +	return dev == NULL;
>>> +}
>>
>> A new line should be added here - start of a new function.
>>
> 
> yes
> 
> 
> I'm pretty sorry about this code, to be honest.
> This is a nasty piece with a lot of states to care for.

Actually, the cases that you have mentioned above indeed requires a 
complex logic. I am not sure I have any suggestion to make it simpler.
I will read again based on what you have explained.

> 
> At least it works. I'd like to have the properties integrated so that
> developpers can add their own quickly. In the meantime I could rework
> this function. But simple is not easy.
> 

Problem is that the 18.08 window is almost closed - I though I could 
review it within the window but now I am not confident. Maybe someone 
else too can look through the PCI/VDEV part after this patch..

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction Gaetan Rivet
  2018-07-12  6:49     ` Shreyansh Jain
@ 2018-07-14  6:37     ` Thomas Monjalon
  1 sibling, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-14  6:37 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

Hi,

Some doxygen parameters must be fixed.
See below:

11/07/2018 23:44, Gaetan Rivet:
> +/**
> + * Register a Class handle.
> + *
> + * @param
> + *   A pointer to a rte_class structure describing the class
> + *   to be registered.
> + */
> +__rte_experimental
> +void rte_class_register(struct rte_class *cls);
> +
> +/**
> + * Unregister a Class handle.
> + *
> + * @param class
> + *   A pointer to a rte_class structure describing the class
> + *   to be unregistered.
> + */
> +__rte_experimental
> +void rte_class_unregister(struct rte_class *cls);

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers
  2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers Gaetan Rivet
  2018-07-12  9:48     ` Shreyansh Jain
@ 2018-07-14 10:30     ` Thomas Monjalon
  1 sibling, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-14 10:30 UTC (permalink / raw)
  To: Gaetan Rivet; +Cc: dev

11/07/2018 23:44, Gaetan Rivet:
> 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>

There is a compilation issue.
It makes EAL depends on kvargs.
This change is required (to be squashed):

--- 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
 

--- a/lib/librte_eal/bsdapp/eal/meson.build
+++ b/lib/librte_eal/bsdapp/eal/meson.build
@@ -16,3 +16,5 @@ env_sources = files('eal_alarm.c',
                'eal_memory.c',
                'eal_dev.c'
 )
+
+deps += ['kvargs']

--- a/lib/librte_eal/linuxapp/eal/Makefile
+++ b/lib/librte_eal/linuxapp/eal/Makefile
@@ -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

--- a/lib/librte_eal/linuxapp/eal/meson.build
+++ b/lib/librte_eal/linuxapp/eal/meson.build
@@ -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

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction
  2018-07-12  7:41       ` Gaëtan Rivet
@ 2018-07-14 10:35         ` Thomas Monjalon
  0 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-14 10:35 UTC (permalink / raw)
  To: Gaëtan Rivet; +Cc: dev, Shreyansh Jain

12/07/2018 09:41, Gaëtan Rivet:
> On Thu, Jul 12, 2018 at 12:19:09PM +0530, Shreyansh Jain wrote:
> > Any reason you don't want the rte_class_find and rte_class_find_by_name as
> > exposed APIs? There is no experimental tag on these APIs either.
> 
> No actually I just overlooked that part! Thanks for catching this, I
> think it should be exposed and tagged experimental.

Fixup below:

--- a/lib/librte_eal/common/eal_common_class.c
+++ b/lib/librte_eal/common/eal_common_class.c
@@ -29,6 +29,7 @@ rte_class_unregister(struct rte_class *class)
        RTE_LOG(DEBUG, EAL, "Unregistered [%s] device class.\n", class->name);
 }
 
+__rte_experimental
 struct rte_class *
 rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
               const void *data)
@@ -55,6 +56,7 @@ cmp_class_name(const struct rte_class *class, const void *_name)
        return strcmp(class->name, name);
 }
 
+__rte_experimental
 struct rte_class *
 rte_class_find_by_name(const char *name)
 {

--- a/lib/librte_eal/common/include/rte_class.h
+++ b/lib/librte_eal/common/include/rte_class.h
@@ -76,6 +76,7 @@ typedef int (*rte_class_cmp_t)(const struct rte_class *cls, const void *data);
  * @return
  *      A pointer to a rte_class structure or NULL in case no class matches
  */
+__rte_experimental
 struct rte_class *
 rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
               const void *data);
@@ -83,6 +84,7 @@ rte_class_find(const struct rte_class *start, rte_class_cmp_t cmp,
 /**
  * Find the registered class for a given name.
  */
+__rte_experimental
 struct rte_class *
 rte_class_find_by_name(const char *name);
 

--- a/lib/librte_eal/rte_eal_version.map
+++ b/lib/librte_eal/rte_eal_version.map
@@ -254,6 +254,8 @@ DPDK_18.08 {
 EXPERIMENTAL {
        global:
 
+       rte_class_find;
+       rte_class_find_by_name;
        rte_class_register;
        rte_class_unregister;
        rte_ctrl_thread_create;

^ permalink raw reply	[flat|nested] 364+ messages in thread

* Re: [dpdk-dev] [PATCH v11 00/25] Device querying
  2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
                     ` (24 preceding siblings ...)
  2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 25/25] eal: add generic dev parameter Gaetan Rivet
@ 2018-07-15 21:54   ` Thomas Monjalon
  25 siblings, 0 replies; 364+ messages in thread
From: Thomas Monjalon @ 2018-07-15 21:54 UTC (permalink / raw)
  To: Gaetan Rivet
  Cc: dev, Neil Horman, Shreyansh Jain, Bruce Richardson, Andrew Rybchenko

11/07/2018 23:44, Gaetan Rivet:
> Gaetan Rivet (25):
>   devargs: use rte-log functions
>   devargs: add non-variadic parsing function
>   kvargs: remove error logs
>   kvargs: build before EAL
>   kvargs: introduce a more flexible parsing function
>   eal: introduce dtor macros
>   eal: introduce device class abstraction
>   devargs: add function to parse device layers
>   eal/dev: add device iterator interface
>   eal/dev: implement device iteration initialization
>   eal/dev: implement device iteration
>   kvargs: add generic string matching callback
>   bus/pci: implement device iteration and comparison
>   bus/pci: add device matching field id
>   bus/vdev: implement device iteration
>   bus/vdev: add device matching field driver
>   ethdev: add private generic device iterator
>   ethdev: register ether layer as a class
>   ethdev: add device matching field name
>   app/testpmd: add show device command
>   bus/pci: pre-process declarative PCI devargs
>   bus/vdev: pre-process declarative vdev devargs
>   bus/pci: process declarative PCI devargs
>   ethdev: process declarative eth devargs
>   eal: add generic dev parameter

This series did not get a lot of reviews, especially for the last half
of patches.
As it allows to make some progress to get a generic devargs syntax,
I decide to apply the first 12 patches, which brings a base for a
generic devargs syntax parsing.

The last half of patches are implementing some parsing/iteration
for PCI, vdev and ethdev. They need to be discussed and agreed
with more reviews. And more importantly, we need to add more properties
in the devargs syntax, and we need to address more buses and device classes.

Getting the parsing base in 18.08 should help to close the full syntax
in 18.11.

Thank you Gaetan for the big work.

^ permalink raw reply	[flat|nested] 364+ messages in thread

end of thread, other threads:[~2018-07-15 21:54 UTC | newest]

Thread overview: 364+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-15 17:49 [dpdk-dev] [PATCH v1 00/18] Device querying Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 01/18] eal: introduce dtor macros Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 02/18] eal: introduce device class abstraction Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 03/18] eal/class: register destructor Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 04/18] eal: add lightweight kvarg parsing utility Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 05/18] eal/dev: add device iterator interface Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 06/18] eal/dev: implement device iteration initialization Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 07/18] eal/class: add device iteration Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 08/18] eal/bus: " Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 09/18] eal/dev: implement " Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 10/18] ethdev: register ether layer as a class Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 11/18] ethdev: add device matching field name Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 12/18] bus/pci: fix find device implementation Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 13/18] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 14/18] bus/pci: add device matching field id Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 15/18] bus/vdev: fix find device implementation Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 16/18] bus/vdev: implement device iteration Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 17/18] bus/vdev: add device matching field driver Gaetan Rivet
2018-03-15 17:49 ` [dpdk-dev] [PATCH v1 18/18] app/testpmd: add show device command Gaetan Rivet
2018-03-19 11:33   ` Gaëtan Rivet
2018-03-20 17:51 ` [dpdk-dev] [PATCH v1 00/18] Device querying Gaëtan Rivet
2018-03-21 17:15 ` [dpdk-dev] [PATCH v2 " Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Gaetan Rivet
2018-03-22 11:35     ` Neil Horman
2018-03-22 13:51     ` Neil Horman
2018-03-22 15:56       ` Gaëtan Rivet
2018-03-22 15:58         ` [dpdk-dev] [PATCH] eal: list acceptable init priorities Gaetan Rivet
2018-03-23  0:40           ` Neil Horman
2018-03-23  0:38         ` [dpdk-dev] [PATCH v2 01/18] eal: introduce dtor macros Neil Horman
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 02/18] eal: introduce device class abstraction Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 03/18] eal/class: register destructor Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility Gaetan Rivet
2018-03-21 17:32     ` Wiles, Keith
2018-03-21 17:58       ` Gaëtan Rivet
2018-03-22 14:10       ` Neil Horman
2018-03-22 16:27         ` Gaëtan Rivet
2018-03-23  0:53           ` Neil Horman
2018-03-23  9:31             ` Gaëtan Rivet
2018-03-23 11:54               ` Neil Horman
2018-03-23 13:12                 ` Gaëtan Rivet
2018-03-23 18:45                   ` [dpdk-dev] [PATCH 1/2] kvargs: the life of the party Gaetan Rivet
2018-03-23 18:45                     ` [dpdk-dev] [PATCH 2/2] dev: use rte_kvargs Gaetan Rivet
2018-03-26 11:38                       ` Neil Horman
2018-03-26 13:59                         ` Gaëtan Rivet
2018-03-26 15:14                           ` Wiles, Keith
2018-03-26 11:23                   ` [dpdk-dev] [PATCH v2 04/18] eal: add lightweight kvarg parsing utility Neil Horman
2018-03-23 13:15               ` Wiles, Keith
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 05/18] eal/dev: add device iterator interface Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 06/18] eal/class: add device iteration Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 07/18] eal/bus: " Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 08/18] eal/dev: implement device iteration initialization Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 09/18] eal/dev: implement device iteration Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 10/18] bus/pci: fix find device implementation Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 11/18] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 12/18] bus/pci: add device matching field id Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 13/18] bus/vdev: fix find device implementation Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 14/18] bus/vdev: implement device iteration Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 15/18] bus/vdev: add device matching field driver Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 16/18] ethdev: register ether layer as a class Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 17/18] ethdev: add device matching field name Gaetan Rivet
2018-03-21 17:15   ` [dpdk-dev] [PATCH v2 18/18] app/testpmd: add show device command Gaetan Rivet
2018-03-22 11:31   ` [dpdk-dev] [PATCH v2 00/18] Device querying Bruce Richardson
2018-03-26 23:18   ` [dpdk-dev] [PATCH v3 00/20] " Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 01/20] kvargs: remove rte log dependency Gaetan Rivet
2018-03-27 18:19       ` Neil Horman
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 02/20] kvargs: build before EAL Gaetan Rivet
2018-03-27  9:12       ` Bruce Richardson
2018-03-27  9:53         ` Gaëtan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init priorities Gaetan Rivet
2018-03-27  7:18       ` Shreyansh Jain
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 04/20] eal: introduce dtor macros Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 05/20] eal: introduce device class abstraction Gaetan Rivet
2018-03-27  8:38       ` Shreyansh Jain
2018-03-27  9:51         ` Gaëtan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 06/20] eal/class: register destructor Gaetan Rivet
2018-03-27  8:42       ` Shreyansh Jain
2018-03-27  8:49         ` Gaëtan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 07/20] eal/dev: add device iterator interface Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 08/20] eal/class: add device iteration Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 09/20] eal/bus: " Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initialization Gaetan Rivet
2018-03-27 11:47       ` Neil Horman
2018-03-27 12:40         ` Gaëtan Rivet
2018-03-27 13:04           ` Gaëtan Rivet
2018-03-27 20:23             ` Gaëtan Rivet
2018-03-27 23:26               ` Neil Horman
2018-03-28 12:48                 ` Gaëtan Rivet
2018-03-27 13:08           ` Wiles, Keith
2018-03-27 18:26           ` Neil Horman
2018-03-27 20:20             ` Gaëtan Rivet
2018-03-27 20:28               ` Bruce Richardson
2018-03-27 20:35                 ` Gaëtan Rivet
2018-03-27 20:48                   ` Richardson, Bruce
2018-03-27 23:53                     ` Neil Horman
2018-03-28  8:10                       ` Gaëtan Rivet
2018-03-28 11:17                         ` Neil Horman
2018-04-22 22:29                           ` Thomas Monjalon
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 11/20] eal/dev: implement device iteration Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 12/20] bus/pci: fix find device implementation Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 13/20] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 14/20] bus/pci: add device matching field id Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 15/20] bus/vdev: fix find device implementation Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 16/20] bus/vdev: implement device iteration Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 17/20] bus/vdev: add device matching field driver Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 18/20] ethdev: register ether layer as a class Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 19/20] ethdev: add device matching field name Gaetan Rivet
2018-03-26 23:18     ` [dpdk-dev] [PATCH v3 20/20] app/testpmd: add show device command Gaetan Rivet
2018-03-29 21:23     ` [dpdk-dev] [PATCH v4 00/20] Device querying Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 01/20] kvargs: build before EAL Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 02/20] eal: list acceptable init priorities Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 03/20] eal: introduce dtor macros Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 04/20] eal: introduce device class abstraction Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 05/20] eal/class: register destructor Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 06/20] eal/dev: add device iterator interface Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 07/20] eal/class: add device iteration Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 08/20] eal/bus: " Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 09/20] eal/dev: implement device iteration initialization Gaetan Rivet
2018-03-30 15:22         ` Wiles, Keith
2018-03-30 15:53           ` Gaëtan Rivet
2018-03-30 16:22             ` Wiles, Keith
2018-03-31 15:33               ` Gaëtan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 10/20] eal/dev: implement device iteration Gaetan Rivet
2018-04-09  7:28         ` Matan Azrad
2018-04-09  8:16           ` Gaëtan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 11/20] kvargs: add generic string matching callback Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 12/20] bus/pci: fix find device implementation Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 13/20] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 14/20] bus/pci: add device matching field id Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 15/20] bus/vdev: fix find device implementation Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 16/20] bus/vdev: implement device iteration Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 17/20] bus/vdev: add device matching field driver Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 18/20] ethdev: register ether layer as a class Gaetan Rivet
2018-04-09  7:41         ` Matan Azrad
2018-04-09  7:47           ` Gaëtan Rivet
2018-04-09  7:58             ` Matan Azrad
2018-04-09  8:12               ` Gaëtan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 19/20] ethdev: add device matching field name Gaetan Rivet
2018-03-29 21:23       ` [dpdk-dev] [PATCH v4 20/20] app/testpmd: add show device command Gaetan Rivet
2018-04-11  0:04       ` [dpdk-dev] [PATCH v5 00/21] Device querying Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 01/21] kvargs: build before EAL Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 02/21] eal: list acceptable init priorities Gaetan Rivet
2018-04-12 11:28           ` Neil Horman
2018-04-12 21:57             ` Gaëtan Rivet
2018-04-13 11:42               ` Neil Horman
2018-04-13 12:52                 ` Shreyansh Jain
2018-04-13 12:55                   ` Gaëtan Rivet
2018-04-14 18:45                     ` Neil Horman
2018-04-15 15:13                       ` Gaëtan Rivet
2018-04-16 11:31                         ` Neil Horman
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 03/21] eal: introduce dtor macros Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 04/21] eal: introduce device class abstraction Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 05/21] eal/class: register destructor Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 06/21] eal/dev: add device iterator interface Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 07/21] eal/class: add device iteration Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 08/21] eal/bus: " Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 09/21] eal/dev: implement device iteration initialization Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 10/21] eal/dev: implement device iteration Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 11/21] kvargs: add generic string matching callback Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 12/21] bus/pci: fix find device implementation Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 13/21] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 14/21] bus/pci: add device matching field id Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 15/21] bus/vdev: fix find device implementation Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 16/21] bus/vdev: implement device iteration Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 17/21] bus/vdev: add device matching field driver Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 18/21] ethdev: add private generic device iterator Gaetan Rivet
2018-04-11  8:41           ` Gaëtan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 19/21] ethdev: register ether layer as a class Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 20/21] ethdev: add device matching field name Gaetan Rivet
2018-04-11  0:04         ` [dpdk-dev] [PATCH v5 21/21] app/testpmd: add show device command Gaetan Rivet
2018-04-13 13:22 ` [dpdk-dev] [PATCH v6 00/22] Device querying Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 01/22] kvargs: build before EAL Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 02/22] eal: list acceptable init priorities Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 03/22] eal: add last init priority Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 04/22] eal: introduce dtor macros Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 05/22] eal: introduce device class abstraction Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 06/22] eal/class: register destructor Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 07/22] eal/dev: add device iterator interface Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 08/22] eal/class: add device iteration Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 09/22] eal/bus: " Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 10/22] eal/dev: implement device iteration initialization Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 11/22] eal/dev: implement device iteration Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 12/22] kvargs: add generic string matching callback Gaetan Rivet
2018-04-13 14:49     ` Shreyansh Jain
2018-04-13 15:06       ` Gaëtan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 13/22] bus/pci: fix find device implementation Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 14/22] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 15/22] bus/pci: add device matching field id Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 16/22] bus/vdev: fix find device implementation Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 17/22] bus/vdev: implement device iteration Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 18/22] bus/vdev: add device matching field driver Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 19/22] ethdev: add private generic device iterator Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 20/22] ethdev: register ether layer as a class Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 21/22] ethdev: add device matching field name Gaetan Rivet
2018-04-13 13:22   ` [dpdk-dev] [PATCH v6 22/22] app/testpmd: add show device command Gaetan Rivet
2018-04-15 15:07 ` [dpdk-dev] [PATCH v7 00/22] Device querying Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 01/22] kvargs: build before EAL Gaetan Rivet
2018-06-14 14:10     ` Bruce Richardson
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 02/22] eal: list acceptable init priorities Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 03/22] eal: add last init priority Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 04/22] eal: introduce dtor macros Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 05/22] eal: introduce device class abstraction Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 06/22] eal/class: register destructor Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 07/22] eal/dev: add device iterator interface Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 08/22] eal/class: add device iteration Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 09/22] eal/bus: " Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 10/22] eal/dev: implement device iteration initialization Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 11/22] eal/dev: implement device iteration Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 12/22] kvargs: add generic string matching callback Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 13/22] bus/pci: fix find device implementation Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 14/22] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 15/22] bus/pci: add device matching field id Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 16/22] bus/vdev: fix find device implementation Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 17/22] bus/vdev: implement device iteration Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 18/22] bus/vdev: add device matching field driver Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 19/22] ethdev: add private generic device iterator Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 20/22] ethdev: register ether layer as a class Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 21/22] ethdev: add device matching field name Gaetan Rivet
2018-04-15 15:07   ` [dpdk-dev] [PATCH v7 22/22] app/testpmd: add show device command Gaetan Rivet
2018-06-14 10:59     ` Iremonger, Bernard
2018-06-14 11:35       ` Gaëtan Rivet
2018-04-22 22:54   ` [dpdk-dev] [PATCH v7 00/22] Device querying Thomas Monjalon
2018-04-24 10:03     ` Gaëtan Rivet
2018-06-26 16:56 ` [dpdk-dev] [PATCH v8 00/21] " Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 01/21] devargs: add non-variadic parsing function Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 02/21] kvargs: build before EAL Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 03/21] kvargs: introduce a more flexible parsing function Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 04/21] eal: introduce dtor macros Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 05/21] eal: introduce device class abstraction Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 06/21] eal/class: register destructor Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 07/21] devargs: add function to parse device layers Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 08/21] eal/dev: add device iterator interface Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 09/21] eal/class: add device iteration Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 10/21] eal/bus: " Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 11/21] eal/dev: implement device iteration initialization Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 12/21] eal/dev: implement device iteration Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 13/21] kvargs: add generic string matching callback Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 14/21] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 15/21] bus/pci: add device matching field id Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 16/21] bus/vdev: implement device iteration Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 17/21] bus/vdev: add device matching field driver Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 18/21] ethdev: add private generic device iterator Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 19/21] ethdev: register ether layer as a class Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 20/21] ethdev: add device matching field name Gaetan Rivet
2018-06-26 16:56   ` [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command Gaetan Rivet
2018-06-28 10:03     ` Iremonger, Bernard
2018-06-28 10:09       ` Gaëtan Rivet
2018-06-28 11:28         ` Iremonger, Bernard
2018-06-28 11:56           ` Gaëtan Rivet
2018-06-27 10:55   ` [dpdk-dev] [PATCH v8 00/21] Device querying Bruce Richardson
2018-06-27 11:29     ` Gaëtan Rivet
2018-07-03 22:14 ` [dpdk-dev] [PATCH v9 00/27] " Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 01/27] devargs: add non-variadic parsing function Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 02/27] kvargs: remove error logs Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 03/27] kvargs: build before EAL Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 04/27] kvargs: introduce a more flexible parsing function Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 05/27] eal: introduce dtor macros Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 06/27] eal: introduce device class abstraction Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 07/27] eal/class: register destructor Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 08/27] devargs: add function to parse device layers Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 09/27] eal/dev: add device iterator interface Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 10/27] eal/class: add device iteration Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 11/27] eal/bus: " Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 12/27] eal/dev: implement device iteration initialization Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 13/27] eal/dev: implement device iteration Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 14/27] kvargs: add generic string matching callback Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 15/27] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-07-03 22:14   ` [dpdk-dev] [PATCH v9 16/27] bus/pci: add device matching field id Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 17/27] bus/vdev: implement device iteration Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 18/27] bus/vdev: add device matching field driver Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 19/27] ethdev: add private generic device iterator Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 20/27] ethdev: register ether layer as a class Gaetan Rivet
2018-07-04 12:20     ` Andrew Rybchenko
2018-07-05  9:36       ` Gaëtan Rivet
2018-07-05 11:13         ` Bruce Richardson
2018-07-05 11:54           ` Gaëtan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 21/27] ethdev: add device matching field name Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 22/27] app/testpmd: add show device command Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 23/27] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 24/27] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 25/27] bus/pci: process declarative PCI devargs Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 26/27] ethdev: process declarative eth devargs Gaetan Rivet
2018-07-03 22:15   ` [dpdk-dev] [PATCH v9 27/27] eal: add generic dev parameter Gaetan Rivet
2018-07-05 11:48 ` [dpdk-dev] [PATCH v10 00/27] Device querying Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 01/27] devargs: add non-variadic parsing function Gaetan Rivet
2018-07-05 14:44     ` Thomas Monjalon
2018-07-11 11:46     ` Shreyansh Jain
2018-07-11 12:01       ` Gaëtan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 02/27] kvargs: remove error logs Gaetan Rivet
2018-07-05 21:51     ` Thomas Monjalon
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 03/27] kvargs: build before EAL Gaetan Rivet
2018-07-05 21:50     ` Thomas Monjalon
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 04/27] kvargs: introduce a more flexible parsing function Gaetan Rivet
2018-07-05 22:00     ` Thomas Monjalon
2018-07-11 11:55       ` Shreyansh Jain
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 05/27] eal: introduce dtor macros Gaetan Rivet
2018-07-06  4:17     ` Shreyansh Jain
2018-07-10 11:40     ` Thomas Monjalon
2018-07-10 12:56       ` Gaëtan Rivet
2018-07-10 13:06         ` Thomas Monjalon
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 06/27] eal: introduce device class abstraction Gaetan Rivet
2018-07-11  8:10     ` Thomas Monjalon
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 07/27] eal/class: register destructor Gaetan Rivet
2018-07-11  8:12     ` Thomas Monjalon
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 08/27] devargs: add function to parse device layers Gaetan Rivet
2018-07-11  8:19     ` Thomas Monjalon
2018-07-11  8:41       ` Gaëtan Rivet
2018-07-11  9:30         ` Thomas Monjalon
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 09/27] eal/dev: add device iterator interface Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 10/27] eal/class: add device iteration Gaetan Rivet
2018-07-11  9:47     ` Thomas Monjalon
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 11/27] eal/bus: " Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 12/27] eal/dev: implement device iteration initialization Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 13/27] eal/dev: implement device iteration Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 14/27] kvargs: add generic string matching callback Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 15/27] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 16/27] bus/pci: add device matching field id Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 17/27] bus/vdev: implement device iteration Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 18/27] bus/vdev: add device matching field driver Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 19/27] ethdev: add private generic device iterator Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 20/27] ethdev: register ether layer as a class Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 21/27] ethdev: add device matching field name Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 22/27] app/testpmd: add show device command Gaetan Rivet
2018-07-10 14:45     ` Iremonger, Bernard
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 23/27] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 24/27] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 25/27] bus/pci: process declarative PCI devargs Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 26/27] ethdev: process declarative eth devargs Gaetan Rivet
2018-07-05 11:48   ` [dpdk-dev] [PATCH v10 27/27] eal: add generic dev parameter Gaetan Rivet
2018-07-11 21:44 ` [dpdk-dev] [PATCH v11 00/25] Device querying Gaetan Rivet
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 01/25] devargs: use rte-log functions Gaetan Rivet
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 02/25] devargs: add non-variadic parsing function Gaetan Rivet
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 03/25] kvargs: remove error logs Gaetan Rivet
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 04/25] kvargs: build before EAL Gaetan Rivet
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 05/25] kvargs: introduce a more flexible parsing function Gaetan Rivet
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 06/25] eal: introduce dtor macros Gaetan Rivet
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 07/25] eal: introduce device class abstraction Gaetan Rivet
2018-07-12  6:49     ` Shreyansh Jain
2018-07-12  7:41       ` Gaëtan Rivet
2018-07-14 10:35         ` Thomas Monjalon
2018-07-14  6:37     ` Thomas Monjalon
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 08/25] devargs: add function to parse device layers Gaetan Rivet
2018-07-12  9:48     ` Shreyansh Jain
2018-07-14 10:30     ` Thomas Monjalon
2018-07-11 21:44   ` [dpdk-dev] [PATCH v11 09/25] eal/dev: add device iterator interface Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 10/25] eal/dev: implement device iteration initialization Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 11/25] eal/dev: implement device iteration Gaetan Rivet
2018-07-12 10:58     ` Shreyansh Jain
2018-07-12 15:08       ` Gaëtan Rivet
2018-07-13  7:06         ` Shreyansh Jain
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 12/25] kvargs: add generic string matching callback Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 13/25] bus/pci: implement device iteration and comparison Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 14/25] bus/pci: add device matching field id Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 15/25] bus/vdev: implement device iteration Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 16/25] bus/vdev: add device matching field driver Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 17/25] ethdev: add private generic device iterator Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 18/25] ethdev: register ether layer as a class Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 19/25] ethdev: add device matching field name Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 20/25] app/testpmd: add show device command Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 21/25] bus/pci: pre-process declarative PCI devargs Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 22/25] bus/vdev: pre-process declarative vdev devargs Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 23/25] bus/pci: process declarative PCI devargs Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 24/25] ethdev: process declarative eth devargs Gaetan Rivet
2018-07-11 21:45   ` [dpdk-dev] [PATCH v11 25/25] eal: add generic dev parameter Gaetan Rivet
2018-07-15 21:54   ` [dpdk-dev] [PATCH v11 00/25] Device querying Thomas Monjalon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).