Skip to contentSkip to conversation

Device querying

PATCH Superseded Gaetan Rivet 9 participants 364 messages Mar 15, 2018 – Jul 15, 2018 Page 2 of 3

Subsystems (3)
lore
Share & tools
lore
#146 lore raw

Re: [PATCH v5 02/21] eal: list acceptable init priorities

In reply to Gaëtan Rivet
Quoted 108 lines · Gaëtan Rivet

Hi Shreyansh,

Quoted 105 lines · Shreyansh Jain
Quoted 80 lines · Neil Horman
Quoted 70 lines · Gaëtan Rivet

Hello Neil,

Quoted 67 lines · Neil Horman
Quoted 55 lines · 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.

---
  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(-)
lib/librte_eal/common/eal_common_log.c +1 -1
index a27192620..36b9d6e08 100644
@@ -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)
  {
lib/librte_eal/common/include/rte_bus.h +1 -1
index 6fb08341a..eb9eded4e 100644
@@ -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);\
lib/librte_eal/common/include/rte_common.h +6 -0
index 6c5bc5a76..8f04518f7 100644
@@ -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.
   *

lib/librte_eal/common/include/rte_common.h static void __attribute__((constructor, used)) func(void) · line 111

Quoted 5 lines
lib/librte_eal/common/include/rte_common.h +1 -1
@@ -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.

Quoted 9 lines
Quoted 2 lines

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.

Quoted 6 lines

It was more just a way to unify the macros is all, probably not important.

Quoted 2 lines

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

Quoted 9 lines
Quoted 3 lines

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

Quoted 5 lines

Regards,

Signature · 2 lines
Gaëtan Rivet
6WIND
#147 lore raw

Re: [PATCH v5 02/21] eal: list acceptable init priorities

Hello Neil,

Quoted 113 lines · Neil Horman
Quoted 112 lines · Gaëtan Rivet

Hi Shreyansh,

Quoted 108 lines · Shreyansh Jain
Quoted 80 lines · Neil Horman
Quoted 70 lines · Gaëtan Rivet

Hello Neil,

Quoted 67 lines · Neil Horman
Quoted 55 lines · 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.

---
  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(-)
lib/librte_eal/common/eal_common_log.c +1 -1
index a27192620..36b9d6e08 100644
@@ -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)
  {
lib/librte_eal/common/include/rte_bus.h +1 -1
index 6fb08341a..eb9eded4e 100644
@@ -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);\
lib/librte_eal/common/include/rte_common.h +6 -0
index 6c5bc5a76..8f04518f7 100644
@@ -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.
   *

lib/librte_eal/common/include/rte_common.h static void __attribute__((constructor, used)) func(void) · line 111

Quoted 5 lines
lib/librte_eal/common/include/rte_common.h +1 -1
@@ -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.

Quoted 9 lines
Quoted 2 lines

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.

Quoted 6 lines

It was more just a way to unify the macros is all, probably not important.

Quoted 2 lines

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.

Quoted 7 lines
Quoted 5 lines

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/

Signature · 2 lines
Gaëtan Rivet
6WIND
#148 lore raw

Re: [PATCH v5 02/21] eal: list acceptable init priorities

Quoted 121 lines · Gaëtan Rivet

Hello Neil,

Quoted 118 lines · Neil Horman
Quoted 117 lines · Gaëtan Rivet

Hi Shreyansh,

Quoted 100 lines · Shreyansh Jain
Quoted 80 lines · Neil Horman
Quoted 70 lines · Gaëtan Rivet

Hello Neil,

Quoted 67 lines · Neil Horman
Quoted 55 lines · 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.

---
  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(-)
lib/librte_eal/common/eal_common_log.c +1 -1
index a27192620..36b9d6e08 100644
@@ -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)
  {
lib/librte_eal/common/include/rte_bus.h +1 -1
index 6fb08341a..eb9eded4e 100644
@@ -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);\
lib/librte_eal/common/include/rte_common.h +6 -0
index 6c5bc5a76..8f04518f7 100644
@@ -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.
   *

lib/librte_eal/common/include/rte_common.h static void __attribute__((constructor, used)) func(void) · line 111

Quoted 5 lines
lib/librte_eal/common/include/rte_common.h +1 -1
@@ -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.

Quoted 9 lines
Quoted 2 lines

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.

Quoted 6 lines

It was more just a way to unify the macros is all, probably not important.

Quoted 2 lines

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.

Quoted 8 lines

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 :) .

Quoted 6 lines
Quoted 2 lines

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 :)

Quoted 4 lines

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

Quoted 4 lines
Signature · 2 lines
Gaëtan Rivet
6WIND
#149 lore raw

PATCH v5 3/21 eal: introduce dtor macros

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
lib/librte_eal/common/include/rte_common.h +23 -0
index 8f04518f7..f326e1c30 100644
@@ -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))
Signature · 1 line
2.11.0
#150 lore raw

PATCH v5 4/21 eal: introduce device class abstraction

In reply to Gaetan Rivet
---
 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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index ed1d17b44..c7d5abcd9 100644
@@ -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
lib/librte_eal/common/Makefile +1 -1
index 75776d3e2..607ae0447 100644
@@ -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
lib/librte_eal/common/eal_common_class.c new file +62 -0

62 lines not on this page · raw message

lib/librte_eal/common/include/rte_class.h new file +121 -0

121 lines not on this page · raw message

lib/librte_eal/common/include/rte_common.h +1 -0
index f326e1c30..a3e7d582c 100644
@@ -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
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index b9c7727c8..06ab30cad 100644
@@ -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
lib/librte_eal/rte_eal_version.map +2 -0
index dd38783a2..afe6ce1b9 100644
@@ -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;
Signature · 1 line
2.11.0
#151 lore raw

PATCH v5 5/21 eal/class: register destructor

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)
lib/librte_eal/common/include/rte_class.h +5 -0
index b5e550a34..e8176f5e1 100644
@@ -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
Signature · 1 line
2.11.0
#152 lore raw

PATCH v5 6/21 eal/dev: add device iterator interface

In reply to 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.

---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
lib/librte_eal/common/include/rte_dev.h +47 -0
index b688f1efd..937ff6079 100644
@@ -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
Signature · 1 line
2.11.0
#153 lore raw

PATCH v5 7/21 eal/class: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_class.h +1 -0
index e8176f5e1..9d5b06807 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#154 lore raw

PATCH v5 8/21 eal/bus: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_bus.h +1 -0
index eb9eded4e..747baf140 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#155 lore raw

PATCH v5 9/21 eal/dev: implement device iteration initialization

In reply to Gaetan Rivet

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

---
 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(+)
lib/Makefile +1 -0
index fc7a55a37..1b17526f7 100644
@@ -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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index c7d5abcd9..c13b08ed1 100644
@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3
 LDLIBS += -lexecinfo
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
 
 EXPORT_MAP := ../../rte_eal_version.map
 
lib/librte_eal/common/eal_common_dev.c +148 -0

160 lines not on this page · raw message

lib/librte_eal/common/include/rte_dev.h +24 -0
index 937ff6079..f84128e5c 100644
@@ -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
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index 06ab30cad..6fb67bf7f 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index afe6ce1b9..cad24376f 100644
@@ -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;
Signature · 1 line
2.11.0
#156 lore raw

PATCH v5 10/21 eal/dev: implement device iteration

In reply to Gaetan Rivet

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

---
 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(+)
lib/librte_eal/common/eal_common_dev.c +168 -0
index 1a671758a..645cb2ce8 100644
@@ -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;
+}
lib/librte_eal/common/include/rte_dev.h +26 -0
index f84128e5c..b35fa3cd9 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index cad24376f..f75aa7245 100644
@@ -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;
Signature · 1 line
2.11.0
#157 lore raw

PATCH v5 11/21 kvargs: add generic string matching callback

In reply to Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

---
 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(+)
lib/Makefile +1 -0
index 1b17526f7..4206485d3 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +10 -0
index 0a1abf579..6ee04cbb9 100644
@@ -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);
+}
lib/librte_kvargs/rte_kvargs.h +28 -0
index 51b8120b8..c07c6fea5 100644
@@ -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
lib/librte_kvargs/rte_kvargs_version.map +7 -0
index 2030ec46c..e2f663a88 100644
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
Signature · 1 line
2.11.0
#158 lore raw

PATCH v5 12/21 bus/pci: fix find device implementation

In reply to Gaetan Rivet

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")
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)
drivers/bus/pci/pci_common.c +12 -9
index 2a00f365a..2c45f8151 100644
@@ -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;
 }
 
drivers/bus/pci/rte_bus_pci.h +3 -0
index 357afb912..458e6d076 100644
@@ -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, ...) */
Signature · 1 line
2.11.0
#159 lore raw

PATCH v5 13/21 bus/pci: implement device iteration and comparison

In reply to Gaetan Rivet
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
drivers/bus/pci/Makefile +1 -1
index f3df1c4ce..73498dc77 100644
@@ -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))
drivers/bus/pci/pci_common.c +42 -0

60 lines not on this page · raw message

Signature · 1 line
2.11.0
#160 lore raw

PATCH v5 14/21 bus/pci: add device matching field id

In reply to 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"

---
 drivers/bus/pci/pci_common.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_common.c +26 -2
index bd9ecddc6..3666e4caa 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#161 lore raw

PATCH v5 15/21 bus/vdev: fix find device implementation

In reply to Gaetan Rivet

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")
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)
drivers/bus/vdev/rte_bus_vdev.h +3 -0
index f9d8a2383..4da9967c6 100644
@@ -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)
 {
drivers/bus/vdev/vdev.c +9 -5
index 7eae319cb..66fe63e85 100644
@@ -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;
 }
Signature · 1 line
2.11.0
#162 lore raw

PATCH v5 16/21 bus/vdev: implement device iteration

In reply to Gaetan Rivet
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
drivers/bus/vdev/Makefile +1 -1
index 24d424a38..52728833c 100644
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
drivers/bus/vdev/vdev.c +42 -0

60 lines not on this page · raw message

Signature · 1 line
2.11.0
#163 lore raw

PATCH v5 17/21 bus/vdev: add device matching field driver

In reply to Gaetan Rivet

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

"bus=vdev,driver=xxxx"

---
 drivers/bus/vdev/Makefile |  1 +
 drivers/bus/vdev/vdev.c   | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)
drivers/bus/vdev/Makefile +1 -0
index 52728833c..db6bee98a 100644
@@ -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
drivers/bus/vdev/vdev.c +12 -2
index 1cc469da0..fae75d285 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#164 lore raw

PATCH v5 18/21 ethdev: add private generic device iterator

In reply to 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.

---
 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
lib/librte_ether/Makefile +1 -0
index c2f2f7d82..2fa133fbc 100644
@@ -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
lib/librte_ether/eth_private.c new file +32 -0
new file mode 100644
index 000000000..311c5d6b2
@@ -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;
+}
+
lib/librte_ether/eth_private.h new file +26 -0
new file mode 100644
index 000000000..c3c831dc9
@@ -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_ */
Signature · 1 line
2.11.0
#165 lore raw

Re: [PATCH v5 18/21] ethdev: add private generic device iterator

Quoted 35 lines · 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.

---
 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
lib/librte_ether/Makefile +1 -0
index c2f2f7d82..2fa133fbc 100644
@@ -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
lib/librte_ether/eth_private.c new file +0 -0
new file mode 100644
index 000000000..311c5d6b2

lib/librte_ether/eth_private.c line 2

Quoted 2 lines
lib/librte_ether/eth_private.c new file +2 -0
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Gaëtan

Forgot something here.

lib/librte_ether/eth_private.c line 9

Quoted 7 lines
lib/librte_ether/eth_private.c new file +7 -0
+ */
+
+#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

Signature · 2 lines
Gaëtan Rivet
6WIND
#166 lore raw

PATCH v5 19/21 ethdev: register ether layer as a class

In reply to Gaetan Rivet
---
 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
lib/Makefile +1 -1
index 4206485d3..47513f03f 100644
@@ -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
lib/librte_ether/Makefile +2 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
lib/librte_ether/rte_class_eth.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
2.11.0
#167 lore raw

PATCH v5 20/21 ethdev: add device matching field name

In reply to 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"

---
 lib/librte_ether/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)
lib/librte_ether/rte_class_eth.c +7 -0
index 32c736d32..d8d8e8845 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#168 lore raw

PATCH v5 21/21 app/testpmd: add show device command

In reply to 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.

---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
app/test-pmd/cmdline.c +52 -0
index 40b31ad7e..8ac5fb3ca 100644
@@ -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,
Signature · 1 line
2.11.0
#169 lore raw

v6 cover Device querying

In reply to 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.

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%)
Signature · 1 line
2.11.0
#170 lore raw

PATCH v6 1/22 kvargs: build before EAL

---
 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%)
lib/Makefile +1 -2
index ec965a606..fc7a55a37 100644
@@ -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
lib/librte_eal/common/Makefile +1 -1
index 48f870f24..dbd19331b 100644
@@ -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
lib/librte_kvargs/Makefile +2 -1
index 4eaa9334d..e026ecc21 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +1 -1
index d92a5f9dc..0a1abf579 100644
@@ -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"
 
 /*
lib/librte_kvargs/rte_string_fns.h renamed from lib/librte_eal/common/include/rte_string_fns.h +0 -0
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_kvargs/rte_string_fns.h
Signature · 1 line
2.11.0
#171 lore raw

PATCH v6 2/22 eal: list acceptable init priorities

In reply to 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.

---
 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(-)
lib/librte_eal/common/eal_common_log.c +1 -1
index a27192620..36b9d6e08 100644
@@ -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)
 {
lib/librte_eal/common/include/rte_bus.h +1 -1
index 6fb08341a..eb9eded4e 100644
@@ -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);\
lib/librte_eal/common/include/rte_common.h +7 -1
index 6c5bc5a76..8f04518f7 100644
@@ -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
Signature · 1 line
2.11.0
#172 lore raw

PATCH v6 3/22 eal: add last init priority

In reply to 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.

---
 lib/librte_eal/common/include/rte_common.h | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
lib/librte_eal/common/include/rte_common.h +12 -11
index 8f04518f7..69e5ed1e3 100644
@@ -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))
Signature · 1 line
2.11.0
#173 lore raw

PATCH v6 4/22 eal: introduce dtor macros

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
lib/librte_eal/common/include/rte_common.h +23 -0
index 69e5ed1e3..d48e0ec56 100644
@@ -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))
Signature · 1 line
2.11.0
#174 lore raw

PATCH v6 5/22 eal: introduce device class abstraction

In reply to Gaetan Rivet
---
 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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index 200285e01..de0e6d166 100644
@@ -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
lib/librte_eal/common/Makefile +1 -1
index dbd19331b..f9d17e7ec 100644
@@ -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
lib/librte_eal/common/eal_common_class.c new file +62 -0

62 lines not on this page · raw message

lib/librte_eal/common/include/rte_class.h new file +121 -0

121 lines not on this page · raw message

lib/librte_eal/common/include/rte_common.h +1 -0
index d48e0ec56..ab6b4cf2a 100644
@@ -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) \
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index 45517a27b..b11f92e03 100644
@@ -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
lib/librte_eal/rte_eal_version.map +2 -0
index d02d80b8a..75121b08d 100644
@@ -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;
Signature · 1 line
2.11.0
#175 lore raw

PATCH v6 6/22 eal/class: register destructor

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)
lib/librte_eal/common/include/rte_class.h +5 -0
index b5e550a34..e8176f5e1 100644
@@ -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
Signature · 1 line
2.11.0
#176 lore raw

PATCH v6 7/22 eal/dev: add device iterator interface

In reply to 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.

---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
lib/librte_eal/common/include/rte_dev.h +47 -0
index 0955e9adb..a789defc3 100644
@@ -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
Signature · 1 line
2.11.0
#177 lore raw

PATCH v6 8/22 eal/class: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_class.h +1 -0
index e8176f5e1..9d5b06807 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#178 lore raw

PATCH v6 9/22 eal/bus: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_bus.h +1 -0
index eb9eded4e..747baf140 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#179 lore raw

PATCH v6 10/22 eal/dev: implement device iteration initialization

In reply to Gaetan Rivet

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

---
 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(+)
lib/Makefile +1 -0
index fc7a55a37..1b17526f7 100644
@@ -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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index de0e6d166..35f98448c 100644
@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3
 LDLIBS += -lexecinfo
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
 
 EXPORT_MAP := ../../rte_eal_version.map
 
lib/librte_eal/common/eal_common_dev.c +148 -0

160 lines not on this page · raw message

lib/librte_eal/common/include/rte_dev.h +24 -0
index a789defc3..eb1ad6182 100644
@@ -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
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index b11f92e03..47fd07323 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index 75121b08d..1a41e9413 100644
@@ -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;
Signature · 1 line
2.11.0
#180 lore raw

PATCH v6 11/22 eal/dev: implement device iteration

In reply to Gaetan Rivet

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

---
 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(+)
lib/librte_eal/common/eal_common_dev.c +168 -0
index d8e306926..9d180f881 100644
@@ -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;
+}
lib/librte_eal/common/include/rte_dev.h +26 -0
index eb1ad6182..bfa57287a 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index 1a41e9413..483ed94c4 100644
@@ -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;
Signature · 1 line
2.11.0
#181 lore raw

PATCH v6 12/22 kvargs: add generic string matching callback

In reply to Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

---
 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(+)
lib/Makefile +1 -0
index 1b17526f7..4206485d3 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +10 -0
index 0a1abf579..6ee04cbb9 100644
@@ -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);
+}
lib/librte_kvargs/rte_kvargs.h +28 -0
index 51b8120b8..c07c6fea5 100644
@@ -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
lib/librte_kvargs/rte_kvargs_version.map +7 -0
index 2030ec46c..e2f663a88 100644
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
Signature · 1 line
2.11.0
#182 lore raw

Re: [PATCH v6 12/22] kvargs: add generic string matching callback

Quoted 72 lines · Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

---
  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(+)
lib/Makefile +1 -0
index 1b17526f7..4206485d3 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +10 -0
index 0a1abf579..6ee04cbb9 100644
@@ -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);
+}
lib/librte_kvargs/rte_kvargs.h +14 -0
index 51b8120b8..c07c6fea5 100644
@@ -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.
+ *

lib/librte_kvargs/rte_kvargs.h int rte_kvargs_process(const struct rte_kvargs *kvlist, · line 147

Quoted 10 lines
lib/librte_kvargs/rte_kvargs.h +10 -0
+ * @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?

lib/librte_kvargs/rte_kvargs.h int rte_kvargs_process(const struct rte_kvargs *kvlist, · line 148

Quoted 1 line
lib/librte_kvargs/rte_kvargs.h +1 -0
+	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.

Quoted 23 lines
lib/librte_kvargs/rte_kvargs.h +4 -0
+ */
+__rte_experimental
+int rte_kvargs_strcmp(const char *key, const char *value, void *opaque);
+
  #ifdef __cplusplus
  }
  #endif
lib/librte_kvargs/rte_kvargs_version.map +7 -0
index 2030ec46c..e2f663a88 100644
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
  	local: *;
  };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
#183 lore raw

Re: [PATCH v6 12/22] kvargs: add generic string matching callback

Quoted 97 lines · Shreyansh Jain
Quoted 67 lines · Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

---
  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(+)
lib/Makefile +1 -0
index 1b17526f7..4206485d3 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +10 -0
index 0a1abf579..6ee04cbb9 100644
@@ -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);
+}
lib/librte_kvargs/rte_kvargs.h +14 -0
index 51b8120b8..c07c6fea5 100644
@@ -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.
+ *

lib/librte_kvargs/rte_kvargs.h int rte_kvargs_process(const struct rte_kvargs *kvlist, · line 146

Quoted 10 lines
lib/librte_kvargs/rte_kvargs.h +10 -0
+ * @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?

lib/librte_kvargs/rte_kvargs.h int rte_kvargs_process(const struct rte_kvargs *kvlist, · line 147

Quoted 1 line
lib/librte_kvargs/rte_kvargs.h +1 -0
+	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;
        }
    }
Quoted 5 lines

--->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,

Signature · 2 lines
Gaëtan Rivet
6WIND
#184 lore raw

PATCH v6 13/22 bus/pci: fix find device implementation

In reply to Gaetan Rivet

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")
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)
drivers/bus/pci/pci_common.c +12 -9
index 2a00f365a..2c45f8151 100644
@@ -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;
 }
 
drivers/bus/pci/rte_bus_pci.h +3 -0
index 357afb912..458e6d076 100644
@@ -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, ...) */
Signature · 1 line
2.11.0
#185 lore raw

PATCH v6 14/22 bus/pci: implement device iteration and comparison

In reply to Gaetan Rivet
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
drivers/bus/pci/Makefile +1 -1
index 804a198d1..bbda567c1 100644
@@ -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))
drivers/bus/pci/pci_common.c +42 -0

60 lines not on this page · raw message

Signature · 1 line
2.11.0
#186 lore raw

PATCH v6 15/22 bus/pci: add device matching field id

In reply to 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"

---
 drivers/bus/pci/pci_common.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_common.c +26 -2
index bd9ecddc6..3666e4caa 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#187 lore raw

PATCH v6 16/22 bus/vdev: fix find device implementation

In reply to Gaetan Rivet

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")
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)
drivers/bus/vdev/rte_bus_vdev.h +3 -0
index 646d6c090..f9b5eb596 100644
@@ -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)
 {
drivers/bus/vdev/vdev.c +9 -5
index f8dd1f5e6..c135554c0 100644
@@ -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;
 }
Signature · 1 line
2.11.0
#188 lore raw

PATCH v6 17/22 bus/vdev: implement device iteration

In reply to Gaetan Rivet
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
drivers/bus/vdev/Makefile +1 -1
index 24d424a38..52728833c 100644
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
drivers/bus/vdev/vdev.c +42 -0

60 lines not on this page · raw message

Signature · 1 line
2.11.0
#189 lore raw

PATCH v6 18/22 bus/vdev: add device matching field driver

In reply to Gaetan Rivet

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

"bus=vdev,driver=xxxx"

---
 drivers/bus/vdev/Makefile |  1 +
 drivers/bus/vdev/vdev.c   | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)
drivers/bus/vdev/Makefile +1 -0
index 52728833c..db6bee98a 100644
@@ -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
drivers/bus/vdev/vdev.c +12 -2
index 5bb87af28..84192d79b 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#190 lore raw

PATCH v6 19/22 ethdev: add private generic device iterator

In reply to 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.

---
 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
lib/librte_ether/Makefile +1 -0
index c2f2f7d82..2fa133fbc 100644
@@ -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
lib/librte_ether/eth_private.c new file +31 -0
new file mode 100644
index 000000000..d565568a0
@@ -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;
+}
+
lib/librte_ether/eth_private.h new file +26 -0
new file mode 100644
index 000000000..0f5c6d5c4
@@ -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_ */
Signature · 1 line
2.11.0
#191 lore raw

PATCH v6 20/22 ethdev: register ether layer as a class

In reply to Gaetan Rivet
---
 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
lib/Makefile +1 -1
index 4206485d3..47513f03f 100644
@@ -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
lib/librte_ether/Makefile +2 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
lib/librte_ether/rte_class_eth.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
2.11.0
#192 lore raw

PATCH v6 21/22 ethdev: add device matching field name

In reply to 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"

---
 lib/librte_ether/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)
lib/librte_ether/rte_class_eth.c +7 -0
index 32c736d32..d8d8e8845 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#193 lore raw

PATCH v6 22/22 app/testpmd: add show device command

In reply to 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.

---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
app/test-pmd/cmdline.c +52 -0
index 40b31ad7e..8ac5fb3ca 100644
@@ -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,
Signature · 1 line
2.11.0
#194 lore raw

v7 cover Device querying

In reply to 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.

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%)
Signature · 1 line
2.11.0
#195 lore raw

PATCH v7 1/22 kvargs: build before EAL

---
 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%)
lib/Makefile +1 -2
index ec965a606..fc7a55a37 100644
@@ -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
lib/librte_eal/common/Makefile +1 -1
index 48f870f24..dbd19331b 100644
@@ -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
lib/librte_kvargs/Makefile +2 -1
index 4eaa9334d..e026ecc21 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +1 -1
index d92a5f9dc..0a1abf579 100644
@@ -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"
 
 /*
lib/librte_kvargs/rte_string_fns.h renamed from lib/librte_eal/common/include/rte_string_fns.h +0 -0
similarity index 100%
rename from lib/librte_eal/common/include/rte_string_fns.h
rename to lib/librte_kvargs/rte_string_fns.h
Signature · 1 line
2.11.0
#196 lore raw

Re: [PATCH v7 01/22] kvargs: build before EAL

Quoted 10 lines · Gaetan Rivet
---
 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

#197 lore raw

PATCH v7 2/22 eal: list acceptable init priorities

In reply to 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.

---
 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(-)
lib/librte_eal/common/eal_common_log.c +1 -1
index a27192620..36b9d6e08 100644
@@ -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)
 {
lib/librte_eal/common/include/rte_bus.h +1 -1
index 6fb08341a..eb9eded4e 100644
@@ -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);\
lib/librte_eal/common/include/rte_common.h +7 -1
index 6c5bc5a76..8f04518f7 100644
@@ -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
Signature · 1 line
2.11.0
#198 lore raw

PATCH v7 3/22 eal: add last init priority

In reply to 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.

---
 lib/librte_eal/common/include/rte_common.h | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)
lib/librte_eal/common/include/rte_common.h +12 -11
index 8f04518f7..69e5ed1e3 100644
@@ -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))
Signature · 1 line
2.11.0
#199 lore raw

PATCH v7 4/22 eal: introduce dtor macros

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
lib/librte_eal/common/include/rte_common.h +23 -0
index 69e5ed1e3..d48e0ec56 100644
@@ -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))
Signature · 1 line
2.11.0
#200 lore raw

PATCH v7 5/22 eal: introduce device class abstraction

In reply to Gaetan Rivet
---
 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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index 200285e01..de0e6d166 100644
@@ -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
lib/librte_eal/common/Makefile +1 -1
index dbd19331b..f9d17e7ec 100644
@@ -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
lib/librte_eal/common/eal_common_class.c new file +62 -0

62 lines not on this page · raw message

lib/librte_eal/common/include/rte_class.h new file +121 -0

121 lines not on this page · raw message

lib/librte_eal/common/include/rte_common.h +1 -0
index d48e0ec56..ab6b4cf2a 100644
@@ -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) \
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index 45517a27b..b11f92e03 100644
@@ -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
lib/librte_eal/rte_eal_version.map +2 -0
index d02d80b8a..75121b08d 100644
@@ -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;
Signature · 1 line
2.11.0
#201 lore raw

PATCH v7 6/22 eal/class: register destructor

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)
lib/librte_eal/common/include/rte_class.h +5 -0
index b5e550a34..e8176f5e1 100644
@@ -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
Signature · 1 line
2.11.0
#202 lore raw

PATCH v7 7/22 eal/dev: add device iterator interface

In reply to 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.

---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
lib/librte_eal/common/include/rte_dev.h +47 -0
index 0955e9adb..a789defc3 100644
@@ -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
Signature · 1 line
2.11.0
#203 lore raw

PATCH v7 8/22 eal/class: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_class.h +1 -0
index e8176f5e1..9d5b06807 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#204 lore raw

PATCH v7 9/22 eal/bus: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_bus.h +1 -0
index eb9eded4e..747baf140 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#205 lore raw

PATCH v7 10/22 eal/dev: implement device iteration initialization

In reply to Gaetan Rivet

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

---
 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(+)
lib/Makefile +1 -0
index fc7a55a37..1b17526f7 100644
@@ -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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index de0e6d166..35f98448c 100644
@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3
 LDLIBS += -lexecinfo
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
 
 EXPORT_MAP := ../../rte_eal_version.map
 
lib/librte_eal/common/eal_common_dev.c +149 -0

161 lines not on this page · raw message

lib/librte_eal/common/include/rte_dev.h +24 -0
index a789defc3..eb1ad6182 100644
@@ -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
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index b11f92e03..47fd07323 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index 75121b08d..1a41e9413 100644
@@ -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;
Signature · 1 line
2.11.0
#206 lore raw

PATCH v7 11/22 eal/dev: implement device iteration

In reply to Gaetan Rivet

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

---
 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(+)
lib/librte_eal/common/eal_common_dev.c +168 -0
index 9b6d8bab7..5a8cabfc4 100644
@@ -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;
+}
lib/librte_eal/common/include/rte_dev.h +26 -0
index eb1ad6182..bfa57287a 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index 1a41e9413..483ed94c4 100644
@@ -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;
Signature · 1 line
2.11.0
#207 lore raw

PATCH v7 12/22 kvargs: add generic string matching callback

In reply to Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

---
 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(+)
lib/Makefile +1 -0
index 1b17526f7..4206485d3 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +10 -0
index 0a1abf579..056754214 100644
@@ -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));
+}
lib/librte_kvargs/rte_kvargs.h +28 -0
index 51b8120b8..c07c6fea5 100644
@@ -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
lib/librte_kvargs/rte_kvargs_version.map +7 -0
index 2030ec46c..e2f663a88 100644
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_strcmp;
+
+} DPDK_2.0;
Signature · 1 line
2.11.0
#208 lore raw

PATCH v7 13/22 bus/pci: fix find device implementation

In reply to Gaetan Rivet

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")
---
 drivers/bus/pci/pci_common.c  | 21 ++++++++++++---------
 drivers/bus/pci/rte_bus_pci.h |  3 +++
 2 files changed, 15 insertions(+), 9 deletions(-)
drivers/bus/pci/pci_common.c +12 -9
index 2a00f365a..2c45f8151 100644
@@ -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;
 }
 
drivers/bus/pci/rte_bus_pci.h +3 -0
index 357afb912..458e6d076 100644
@@ -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, ...) */
Signature · 1 line
2.11.0
#209 lore raw

PATCH v7 14/22 bus/pci: implement device iteration and comparison

In reply to Gaetan Rivet
---
 drivers/bus/pci/Makefile     |  2 +-
 drivers/bus/pci/pci_common.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
drivers/bus/pci/Makefile +1 -1
index 804a198d1..bbda567c1 100644
@@ -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))
drivers/bus/pci/pci_common.c +42 -0

60 lines not on this page · raw message

Signature · 1 line
2.11.0
#210 lore raw

PATCH v7 15/22 bus/pci: add device matching field id

In reply to 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"

---
 drivers/bus/pci/pci_common.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_common.c +26 -2
index bd9ecddc6..3666e4caa 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#211 lore raw

PATCH v7 16/22 bus/vdev: fix find device implementation

In reply to Gaetan Rivet

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")
---
 drivers/bus/vdev/rte_bus_vdev.h |  3 +++
 drivers/bus/vdev/vdev.c         | 14 +++++++++-----
 2 files changed, 12 insertions(+), 5 deletions(-)
drivers/bus/vdev/rte_bus_vdev.h +3 -0
index 646d6c090..f9b5eb596 100644
@@ -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)
 {
drivers/bus/vdev/vdev.c +9 -5
index f8dd1f5e6..c135554c0 100644
@@ -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;
 }
Signature · 1 line
2.11.0
#212 lore raw

PATCH v7 17/22 bus/vdev: implement device iteration

In reply to Gaetan Rivet
---
 drivers/bus/vdev/Makefile |  2 +-
 drivers/bus/vdev/vdev.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)
drivers/bus/vdev/Makefile +1 -1
index 24d424a38..52728833c 100644
@@ -19,7 +19,7 @@ LIBABIVER := 1
 
 SRCS-y += vdev.c
 
-LDLIBS += -lrte_eal
+LDLIBS += -lrte_eal -lrte_kvargs
 
 #
 # Export include files
drivers/bus/vdev/vdev.c +42 -0

60 lines not on this page · raw message

Signature · 1 line
2.11.0
#213 lore raw

PATCH v7 18/22 bus/vdev: add device matching field driver

In reply to Gaetan Rivet

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

"bus=vdev,driver=xxxx"

---
 drivers/bus/vdev/Makefile |  1 +
 drivers/bus/vdev/vdev.c   | 14 ++++++++++++--
 2 files changed, 13 insertions(+), 2 deletions(-)
drivers/bus/vdev/Makefile +1 -0
index 52728833c..db6bee98a 100644
@@ -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
drivers/bus/vdev/vdev.c +12 -2
index 5bb87af28..84192d79b 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#214 lore raw

PATCH v7 19/22 ethdev: add private generic device iterator

In reply to 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.

---
 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
lib/librte_ether/Makefile +1 -0
index c2f2f7d82..2fa133fbc 100644
@@ -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
lib/librte_ether/eth_private.c new file +31 -0
new file mode 100644
index 000000000..d565568a0
@@ -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;
+}
+
lib/librte_ether/eth_private.h new file +26 -0
new file mode 100644
index 000000000..0f5c6d5c4
@@ -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_ */
Signature · 1 line
2.11.0
#215 lore raw

PATCH v7 20/22 ethdev: register ether layer as a class

In reply to Gaetan Rivet
---
 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
lib/Makefile +1 -1
index 4206485d3..47513f03f 100644
@@ -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
lib/librte_ether/Makefile +2 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
lib/librte_ether/rte_class_eth.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
2.11.0
#216 lore raw

PATCH v7 21/22 ethdev: add device matching field name

In reply to 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"

---
 lib/librte_ether/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)
lib/librte_ether/rte_class_eth.c +7 -0
index 32c736d32..d8d8e8845 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#217 lore raw

PATCH v7 22/22 app/testpmd: add show device command

In reply to 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.

---
 app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
app/test-pmd/cmdline.c +52 -0
index 40b31ad7e..8ac5fb3ca 100644
@@ -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,
Signature · 1 line
2.11.0
#218 lore raw

Re: [PATCH v7 22/22] app/testpmd: add show device command

Hi Gaetan,

Quoted 69 lines

-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Gaetan Rivet
Sent: Sunday, April 15, 2018 4:08 PM
To: [email protected]
Cc: Gaetan Rivet <[email protected]>
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.

---
 app/test-pmd/cmdline.c | 52
++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0 -0

40b31ad7e..8ac5fb3ca 100644

app/test-pmd/cmdline.c +31 -0
@@ -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,

app/test-pmd/cmdline.c cmdline_parse_inst_t cmd_showportall = { · line 6744

Quoted 10 lines
app/test-pmd/cmdline.c +10 -0
+				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.

Quoted 20 lines
app/test-pmd/cmdline.c +9 -1
+	.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,
--
Quoted 1 line

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.

#219 lore raw

Re: [PATCH v7 22/22] app/testpmd: add show device command

Hi Bernard,

Quoted 75 lines · Bernard

Hi Gaetan,

Quoted 73 lines

-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Gaetan Rivet
Sent: Sunday, April 15, 2018 4:08 PM
To: [email protected]
Cc: Gaetan Rivet <[email protected]>
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.

---
 app/test-pmd/cmdline.c | 52
++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0 -0

40b31ad7e..8ac5fb3ca 100644

app/test-pmd/cmdline.c +35 -0
@@ -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);
Quoted 9 lines

app/test-pmd/cmdline.c cmdline_parse_inst_t cmd_showportall = { · line 6746

Quoted 6 lines
app/test-pmd/cmdline.c +6 -0
+
+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.

Quoted 15 lines
Quoted 15 lines
app/test-pmd/cmdline.c +8 -0
+	.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,
Quoted 9 lines
Quoted 6 lines
app/test-pmd/cmdline.c +1 -1
+	(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.

Quoted 1 line

There should probably be an update to the testpmd documentation also in doc/guides/testpmd_app_ug/*.rst

I will look into it.

Regards,

Signature · 2 lines
Gaëtan Rivet
6WIND
#220 lore raw
In reply to Gaetan Rivet

15/04/2018 17:07, Gaetan Rivet:

Quoted 27 lines

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.

Quoted 8 lines

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?

#221 lore raw
Quoted 37 lines · Thomas Monjalon

15/04/2018 17:07, Gaetan Rivet:

Quoted 27 lines

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.

Quoted 8 lines

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"

Quoted 6 lines

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.

Quoted 4 lines

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.

Signature · 2 lines
Gaëtan Rivet
6WIND
#222 lore raw

v8 cover Device querying

In reply to 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.

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
Signature · 1 line
2.11.0
#223 lore raw

PATCH v8 1/21 devargs: add non-variadic parsing function

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose device strings.

---
 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(-)
drivers/net/failsafe/failsafe_args.c +1 -1
index 2c002b164..626883ce2 100644
@@ -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;
drivers/net/failsafe/failsafe_eal.c +1 -1
index 5672f3961..ce1633f13 100644
@@ -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);
lib/librte_eal/common/eal_common_dev.c +2 -2
index 61cb3b162..ce4b51469 100644
@@ -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;
 
lib/librte_eal/common/eal_common_devargs.c +32 -10

69 lines not on this page · raw message

lib/librte_eal/common/include/rte_devargs.h +38 -2
index 58fbd90a2..6c3b6326b 100644
@@ -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)));
 
 /**
lib/librte_eal/rte_eal_version.map +1 -0
index f7dd0e7bc..1c4db72fa 100644
@@ -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;
lib/librte_ethdev/rte_ethdev.c +1 -1
index a9977df97..cce20d9ae 100644
@@ -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);
Signature · 1 line
2.11.0
#224 lore raw

PATCH v8 2/21 kvargs: build before EAL

In reply to Gaetan Rivet
---
 lib/Makefile               | 3 +--
 lib/librte_kvargs/Makefile | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
lib/Makefile +1 -2
index d82462ba2..e8e903c8f 100644
@@ -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
lib/librte_kvargs/Makefile +1 -1
index 39d5ac33d..875939547 100644
@@ -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
 
Signature · 1 line
2.11.0
#225 lore raw

PATCH v8 3/21 kvargs: introduce a more flexible parsing function

In reply to Gaetan Rivet

This function permits defining additional terminating characters, ending the parsing to arbitrary delimiters.

---
 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(+)
lib/Makefile +1 -0
index e8e903c8f..8a65525cd 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +25 -0
index d92a5f9dc..cfbee3bd9 100644
@@ -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;
+}
lib/librte_kvargs/rte_kvargs.h +30 -0
index 51b8120b8..defdf10e4 100644
@@ -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
lib/librte_kvargs/rte_kvargs_version.map +7 -0
index 2030ec46c..b9fe44b98 100644
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_parse2;
+
+} DPDK_2.0;
Signature · 1 line
2.11.0
#226 lore raw

PATCH v8 4/21 eal: introduce dtor macros

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
lib/librte_eal/common/include/rte_common.h +23 -0
index 434adfd45..0dd832728 100644
@@ -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))
Signature · 1 line
2.11.0
#227 lore raw

PATCH v8 5/21 eal: introduce device class abstraction

In reply to Gaetan Rivet
---
 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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index 3fd33f1e4..b0a1c880a 100644
@@ -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
lib/librte_eal/common/Makefile +1 -1
index 48f870f24..750653093 100644
@@ -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
lib/librte_eal/common/eal_common_class.c new file +62 -0

62 lines not on this page · raw message

lib/librte_eal/common/include/rte_class.h new file +121 -0

121 lines not on this page · raw message

lib/librte_eal/common/include/rte_common.h +1 -0
index 0dd832728..a2e8e6e32 100644
@@ -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) \
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index 3719ec9d7..babc8617a 100644
@@ -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
lib/librte_eal/rte_eal_version.map +2 -0
index 1c4db72fa..19d36b4c7 100644
@@ -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;
Signature · 1 line
2.11.0
#228 lore raw

PATCH v8 6/21 eal/class: register destructor

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)
lib/librte_eal/common/include/rte_class.h +5 -0
index b5e550a34..e8176f5e1 100644
@@ -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
Signature · 1 line
2.11.0
#229 lore raw

PATCH v8 7/21 devargs: add function to parse device layers

In reply to 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.

---
 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(-)
lib/librte_eal/common/eal_common_devargs.c +144 -0
index 0a83beb94..9fee2153f 100644
@@ -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)
 {
lib/librte_eal/common/eal_private.h +27 -0
index bdadc4d50..c4c9283c8 100644
@@ -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_ */
lib/librte_eal/common/include/rte_devargs.h +10 -3
index 6c3b6326b..148600258 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#230 lore raw

PATCH v8 8/21 eal/dev: add device iterator interface

In reply to 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.

---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
lib/librte_eal/common/include/rte_dev.h +47 -0
index 3879ff3ca..120df729f 100644
@@ -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
Signature · 1 line
2.11.0
#231 lore raw

PATCH v8 9/21 eal/class: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_class.h +1 -0
index e8176f5e1..9d5b06807 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#232 lore raw

PATCH v8 10/21 eal/bus: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_bus.h +1 -0
index eb9eded4e..747baf140 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#233 lore raw

PATCH v8 11/21 eal/dev: implement device iteration initialization

In reply to Gaetan Rivet

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

---
 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(+)
lib/Makefile +1 -0
index 8a65525cd..afa604e20 100644
@@ -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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index b0a1c880a..67b10ae0d 100644
@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3
 LDLIBS += -lexecinfo
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
 
 EXPORT_MAP := ../../rte_eal_version.map
 
lib/librte_eal/common/eal_common_dev.c +55 -0

67 lines not on this page · raw message

lib/librte_eal/common/include/rte_dev.h +24 -0
index 120df729f..7b7bd83bc 100644
@@ -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
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index babc8617a..885c48110 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index 19d36b4c7..ac04120d6 100644
@@ -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;
Signature · 1 line
2.11.0
#234 lore raw

PATCH v8 12/21 eal/dev: implement device iteration

In reply to Gaetan Rivet

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

---
 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(+)
lib/librte_eal/common/eal_common_dev.c +168 -0
index 5b7956d17..3d486a841 100644
@@ -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;
+}
lib/librte_eal/common/include/rte_dev.h +26 -0
index 7b7bd83bc..1553c0970 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index ac04120d6..4cd5ab3df 100644
@@ -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;
Signature · 1 line
2.11.0
#235 lore raw

PATCH v8 13/21 kvargs: add generic string matching callback

In reply to Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

---
 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(+)
lib/librte_kvargs/rte_kvargs.c +10 -0
index cfbee3bd9..cf24b939e 100644
@@ -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));
+}
lib/librte_kvargs/rte_kvargs.h +28 -0
index defdf10e4..5c065c3a8 100644
@@ -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
lib/librte_kvargs/rte_kvargs_version.map +1 -0
index b9fe44b98..6a41a6b65 100644
@@ -13,5 +13,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_kvargs_parse2;
+	rte_kvargs_strcmp;
 
 } DPDK_2.0;
Signature · 1 line
2.11.0
#236 lore raw

PATCH v8 14/21 bus/pci: implement device iteration and comparison

In reply to Gaetan Rivet
---
 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
drivers/bus/pci/Makefile +2 -1
index cf373068a..4de953f8f 100644
@@ -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
 
drivers/bus/pci/pci_common.c +1 -2
index 7215aaec3..3c84207ff 100644
@@ -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),
drivers/bus/pci/pci_params.c new file +53 -0

53 lines not on this page · raw message

drivers/bus/pci/private.h +25 -0
index 88fa587e7..eafaeedc7 100644
@@ -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_ */
Signature · 1 line
2.11.0
#237 lore raw

PATCH v8 15/21 bus/pci: add device matching field id

In reply to 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"

---
 drivers/bus/pci/pci_params.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_params.c +27 -2
index 0fde75803..7630d4845 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#238 lore raw

PATCH v8 16/21 bus/vdev: implement device iteration

In reply to Gaetan Rivet
---
 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
drivers/bus/vdev/Makefile +2 -1
index bd0bb8955..1f9cd7ebe 100644
@@ -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
drivers/bus/vdev/vdev.c +6 -4
index 6139dd551..e8518833d 100644
@@ -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);
drivers/bus/vdev/vdev_params.c new file +51 -0

51 lines not on this page · raw message

drivers/bus/vdev/vdev_private.h new file +26 -0
new file mode 100644
index 000000000..ba6dc48ff
@@ -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_ */
Signature · 1 line
2.11.0
#239 lore raw

PATCH v8 17/21 bus/vdev: add device matching field driver

In reply to Gaetan Rivet

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

"bus=vdev,driver=xxxx"

---
 drivers/bus/vdev/vdev_params.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/bus/vdev/vdev_params.c +13 -2
index 842a4684e..2f55f451f 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#240 lore raw

PATCH v8 18/21 ethdev: add private generic device iterator

In reply to 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.

---
 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
lib/librte_ethdev/Makefile +1 -0
index c2f2f7d82..2fa133fbc 100644
@@ -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
lib/librte_ethdev/eth_private.c new file +31 -0
new file mode 100644
index 000000000..d565568a0
@@ -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;
+}
+
lib/librte_ethdev/eth_private.h new file +26 -0
new file mode 100644
index 000000000..0f5c6d5c4
@@ -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_ */
Signature · 1 line
2.11.0
#241 lore raw

PATCH v8 19/21 ethdev: register ether layer as a class

In reply to Gaetan Rivet
---
 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
lib/librte_ethdev/Makefile +2 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
lib/librte_ethdev/rte_class_eth.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
2.11.0
#242 lore raw

PATCH v8 20/21 ethdev: add device matching field name

In reply to 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"

---
 lib/librte_ethdev/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)
lib/librte_ethdev/rte_class_eth.c +7 -0
index 32c736d32..d8d8e8845 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#243 lore raw

PATCH v8 21/21 app/testpmd: add show device command

In reply to 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.

---
 app/test-pmd/cmdline.c                      | 51 +++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
 2 files changed, 75 insertions(+)
app/test-pmd/cmdline.c +51 -0
index 27e2aa8c8..872492b88 100644
@@ -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,
doc/guides/testpmd_app_ug/testpmd_funcs.rst +24 -0
index 0d6fd50ca..4f1009a3a 100644
@@ -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
 ----------------
 
Signature · 1 line
2.11.0
#244 lore raw

Re: [PATCH v8 21/21] app/testpmd: add show device command

Hi Gaetan,

Quoted 136 lines

-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Gaetan Rivet
Sent: Tuesday, June 26, 2018 5:56 PM
To: [email protected]
Cc: Gaetan Rivet <[email protected]>
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.

---
 app/test-pmd/cmdline.c                      | 51
+++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
 2 files changed, 75 insertions(+)
app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0 -0

27e2aa8c8..872492b88 100644

app/test-pmd/cmdline.c +49 -0
@@ -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

doc/guides/testpmd_app_ug/testpmd_funcs.rst +0 -0
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on

the port::

testpmd> set port tm hierarchy default (port_id)

doc/guides/testpmd_app_ug/testpmd_funcs.rst +24 -1
+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
 ----------------
 
--
Quoted 1 line

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.

#245 lore raw

Re: [PATCH v8 21/21] app/testpmd: add show device command

Hi Bernard,

Quoted 137 lines · Bernard

Hi Gaetan,

Quoted 135 lines

-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Gaetan Rivet
Sent: Tuesday, June 26, 2018 5:56 PM
To: [email protected]
Cc: Gaetan Rivet <[email protected]>
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.

---
 app/test-pmd/cmdline.c                      | 51
+++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
 2 files changed, 75 insertions(+)
app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0 -0

27e2aa8c8..872492b88 100644

app/test-pmd/cmdline.c +49 -0
@@ -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

doc/guides/testpmd_app_ug/testpmd_funcs.rst +0 -0
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy on

the port::

testpmd> set port tm hierarchy default (port_id)

doc/guides/testpmd_app_ug/testpmd_funcs.rst +24 -0
+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
 ----------------
Quoted 5 lines
Quoted 2 lines

--
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.

Quoted 2 lines

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?

Signature · 2 lines
Gaëtan Rivet
6WIND
#246 lore raw

Re: [PATCH v8 21/21] app/testpmd: add show device command

Hi Gaetan,

Quoted 162 lines

-----Original Message-----
From: Gaëtan Rivet [mailto:[email protected]]
Sent: Thursday, June 28, 2018 11:10 AM
To: Iremonger, Bernard <[email protected]>
Cc: [email protected]
Subject: Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command

Hi Bernard,

Quoted 15 lines · Bernard

Hi Gaetan,

Quoted 13 lines

-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Gaetan Rivet
Sent: Tuesday, June 26, 2018 5:56 PM
To: [email protected]
Cc: Gaetan Rivet <[email protected]>
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.

Quoted 122 lines
Quoted 122 lines

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.

---
 app/test-pmd/cmdline.c                      | 51
+++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
 2 files changed, 75 insertions(+)
app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0 -0

27e2aa8c8..872492b88 100644

app/test-pmd/cmdline.c +49 -0
@@ -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

doc/guides/testpmd_app_ug/testpmd_funcs.rst +0 -0
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy

on the port::

testpmd> set port tm hierarchy default (port_id)

doc/guides/testpmd_app_ug/testpmd_funcs.rst +24 -0
+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
 ----------------
Quoted 5 lines
Quoted 2 lines

--
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.

Quoted 1 line

There is no update to the internal testpmd documentation about this new

command.

Quoted 1 line
Quoted 8 lines

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

#247 lore raw

Re: [PATCH v8 21/21] app/testpmd: add show device command

Quoted 174 lines · Bernard

Hi Gaetan,

Quoted 162 lines

-----Original Message-----
From: Gaëtan Rivet [mailto:[email protected]]
Sent: Thursday, June 28, 2018 11:10 AM
To: Iremonger, Bernard <[email protected]>
Cc: [email protected]
Subject: Re: [dpdk-dev] [PATCH v8 21/21] app/testpmd: add show device command

Hi Bernard,

Quoted 15 lines · Bernard

Hi Gaetan,

Quoted 13 lines

-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Gaetan Rivet
Sent: Tuesday, June 26, 2018 5:56 PM
To: [email protected]
Cc: Gaetan Rivet <[email protected]>
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.

Quoted 122 lines
Quoted 122 lines

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.

---
 app/test-pmd/cmdline.c                      | 51
+++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 ++++++++++++++
 2 files changed, 75 insertions(+)
app/test-pmd/cmdline.c index renamed from app/test-pmd/cmdline.c +0 -0

27e2aa8c8..872492b88 100644

app/test-pmd/cmdline.c +49 -0
@@ -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

doc/guides/testpmd_app_ug/testpmd_funcs.rst +0 -0
@@ -2628,6 +2628,30 @@ set the traffic management default hierarchy

on the port::

testpmd> set port tm hierarchy default (port_id)

doc/guides/testpmd_app_ug/testpmd_funcs.rst +24 -0
+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
 ----------------
Quoted 5 lines
Quoted 2 lines

--
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.

Quoted 1 line

There is no update to the internal testpmd documentation about this new

command.

Quoted 1 line
Quoted 8 lines

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

Quoted 7 lines

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.

Signature · 2 lines
Gaëtan Rivet
6WIND
#248 lore raw
In reply to Gaetan Rivet
Quoted 108 lines · 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.

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:

Quoted 11 lines

* 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

#249 lore raw
Quoted 121 lines · Bruce Richardson
Quoted 108 lines · 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.

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:

Quoted 11 lines

* 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.

Quoted 7 lines

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.

Signature · 2 lines
Gaëtan Rivet
6WIND
#250 lore raw

v9 cover Device querying

In reply to 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.

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
Signature · 1 line
2.11.0
#251 lore raw

PATCH v9 1/27 devargs: add non-variadic parsing function

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose device strings.

---
 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(-)
drivers/net/failsafe/failsafe_args.c +1 -1
index 2c002b164..626883ce2 100644
@@ -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;
drivers/net/failsafe/failsafe_eal.c +1 -1
index 5672f3961..ce1633f13 100644
@@ -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);
lib/librte_eal/common/eal_common_dev.c +2 -2
index 61cb3b162..ce4b51469 100644
@@ -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;
 
lib/librte_eal/common/eal_common_devargs.c +32 -10

69 lines not on this page · raw message

lib/librte_eal/common/include/rte_devargs.h +38 -2
index 58fbd90a2..6c3b6326b 100644
@@ -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)));
 
 /**
lib/librte_eal/rte_eal_version.map +1 -0
index f7dd0e7bc..1c4db72fa 100644
@@ -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;
lib/librte_ethdev/rte_ethdev.c +1 -1
index a9977df97..cce20d9ae 100644
@@ -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);
Signature · 1 line
2.11.0
#252 lore raw

PATCH v9 2/27 kvargs: remove error logs

In reply to Gaetan Rivet

Error logs in kvargs parsing should be better handled in components calling the library.

This library must be as lean as possible.

---
 lib/librte_kvargs/rte_kvargs.c | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)
lib/librte_kvargs/rte_kvargs.c +5 -17
index d92a5f9dc..747f14964 100644
@@ -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;
 }
Signature · 1 line
2.11.0
#253 lore raw

PATCH v9 3/27 kvargs: build before EAL

In reply to Gaetan Rivet
---
 lib/Makefile               | 3 +--
 lib/librte_kvargs/Makefile | 2 +-
 2 files changed, 2 insertions(+), 3 deletions(-)
lib/Makefile +1 -2
index d82462ba2..e8e903c8f 100644
@@ -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
lib/librte_kvargs/Makefile +1 -1
index 39d5ac33d..875939547 100644
@@ -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
 
Signature · 1 line
2.11.0
#254 lore raw

PATCH v9 4/27 kvargs: introduce a more flexible parsing function

In reply to Gaetan Rivet

This function permits defining additional terminating characters, ending the parsing to arbitrary delimiters.

---
 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(+)
lib/Makefile +1 -0
index e8e903c8f..8a65525cd 100644
@@ -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
lib/librte_kvargs/rte_kvargs.c +25 -0
index 747f14964..519f77679 100644
@@ -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;
+}
lib/librte_kvargs/rte_kvargs.h +30 -0
index 51b8120b8..98c4ed1bf 100644
@@ -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
lib/librte_kvargs/rte_kvargs_version.map +7 -0
index 2030ec46c..b9fe44b98 100644
@@ -8,3 +8,10 @@ DPDK_2.0 {
 
 	local: *;
 };
+
+EXPERIMENTAL {
+	global:
+
+	rte_kvargs_parse2;
+
+} DPDK_2.0;
Signature · 1 line
2.11.0
#255 lore raw

PATCH v9 5/27 eal: introduce dtor macros

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)
lib/librte_eal/common/include/rte_common.h +23 -0
index 434adfd45..0dd832728 100644
@@ -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))
Signature · 1 line
2.11.0
#256 lore raw

PATCH v9 6/27 eal: introduce device class abstraction

In reply to Gaetan Rivet
---
 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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index 3fd33f1e4..b0a1c880a 100644
@@ -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
lib/librte_eal/common/Makefile +1 -1
index 48f870f24..750653093 100644
@@ -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
lib/librte_eal/common/eal_common_class.c new file +62 -0

62 lines not on this page · raw message

lib/librte_eal/common/include/rte_class.h new file +121 -0

121 lines not on this page · raw message

lib/librte_eal/common/include/rte_common.h +1 -0
index 0dd832728..a2e8e6e32 100644
@@ -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) \
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index 3719ec9d7..babc8617a 100644
@@ -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
lib/librte_eal/rte_eal_version.map +2 -0
index 1c4db72fa..19d36b4c7 100644
@@ -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;
Signature · 1 line
2.11.0
#257 lore raw

PATCH v9 7/27 eal/class: register destructor

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 5 +++++
 1 file changed, 5 insertions(+)
lib/librte_eal/common/include/rte_class.h +5 -0
index b5e550a34..e8176f5e1 100644
@@ -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
Signature · 1 line
2.11.0
#258 lore raw

PATCH v9 8/27 devargs: add function to parse device layers

In reply to 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.

---
 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(-)
lib/librte_eal/common/eal_common_devargs.c +144 -0
index 0a83beb94..5f89e0b6e 100644
@@ -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)
 {
lib/librte_eal/common/eal_private.h +27 -0
index bdadc4d50..c4c9283c8 100644
@@ -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_ */
lib/librte_eal/common/include/rte_devargs.h +10 -3
index 6c3b6326b..148600258 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#259 lore raw

PATCH v9 9/27 eal/dev: add device iterator interface

In reply to 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.

---
 lib/librte_eal/common/include/rte_dev.h | 47 +++++++++++++++++++++++++++++++++
 1 file changed, 47 insertions(+)
lib/librte_eal/common/include/rte_dev.h +47 -0
index 3879ff3ca..120df729f 100644
@@ -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
Signature · 1 line
2.11.0
#260 lore raw

PATCH v9 10/27 eal/class: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_class.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_class.h +1 -0
index e8176f5e1..9d5b06807 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#261 lore raw

PATCH v9 11/27 eal/bus: add device iteration

In reply to Gaetan Rivet
---
 lib/librte_eal/common/include/rte_bus.h | 1 +
 1 file changed, 1 insertion(+)
lib/librte_eal/common/include/rte_bus.h +1 -0
index eb9eded4e..747baf140 100644
@@ -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. */
 };
 
 /**
Signature · 1 line
2.11.0
#262 lore raw

PATCH v9 12/27 eal/dev: implement device iteration initialization

In reply to Gaetan Rivet

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

---
 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(+)
lib/Makefile +1 -0
index 8a65525cd..afa604e20 100644
@@ -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
lib/librte_eal/bsdapp/eal/Makefile +1 -0
index b0a1c880a..67b10ae0d 100644
@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3
 LDLIBS += -lexecinfo
 LDLIBS += -lpthread
 LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
 
 EXPORT_MAP := ../../rte_eal_version.map
 
lib/librte_eal/common/eal_common_dev.c +55 -0

67 lines not on this page · raw message

lib/librte_eal/common/include/rte_dev.h +24 -0
index 120df729f..7b7bd83bc 100644
@@ -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
lib/librte_eal/linuxapp/eal/Makefile +1 -0
index babc8617a..885c48110 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index 19d36b4c7..ac04120d6 100644
@@ -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;
Signature · 1 line
2.11.0
#263 lore raw

PATCH v9 13/27 eal/dev: implement device iteration

In reply to Gaetan Rivet

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

---
 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(+)
lib/librte_eal/common/eal_common_dev.c +168 -0
index 5b7956d17..3d486a841 100644
@@ -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;
+}
lib/librte_eal/common/include/rte_dev.h +26 -0
index 7b7bd83bc..1553c0970 100644
@@ -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
lib/librte_eal/rte_eal_version.map +1 -0
index ac04120d6..4cd5ab3df 100644
@@ -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;
Signature · 1 line
2.11.0
#264 lore raw

PATCH v9 14/27 kvargs: add generic string matching callback

In reply to Gaetan Rivet

This function can be used as a callback to
rte_kvargs_process.

This should reduce code duplication.

---
 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(+)
lib/librte_kvargs/rte_kvargs.c +10 -0
index 519f77679..8270d2939 100644
@@ -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));
+}
lib/librte_kvargs/rte_kvargs.h +28 -0
index 98c4ed1bf..ac2999ef3 100644
@@ -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
lib/librte_kvargs/rte_kvargs_version.map +1 -0
index b9fe44b98..6a41a6b65 100644
@@ -13,5 +13,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_kvargs_parse2;
+	rte_kvargs_strcmp;
 
 } DPDK_2.0;
Signature · 1 line
2.11.0
#265 lore raw

PATCH v9 15/27 bus/pci: implement device iteration and comparison

In reply to Gaetan Rivet
---
 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
drivers/bus/pci/Makefile +2 -1
index cf373068a..4de953f8f 100644
@@ -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
 
drivers/bus/pci/pci_common.c +1 -0
index 94b0f4143..749b6eee3 100644
@@ -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),
drivers/bus/pci/pci_params.c new file +53 -0

53 lines not on this page · raw message

drivers/bus/pci/private.h +25 -0
index 8ddd03e16..0e689fa74 100644
@@ -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_ */
Signature · 1 line
2.11.0
#266 lore raw

PATCH v9 16/27 bus/pci: add device matching field id

In reply to 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"

---
 drivers/bus/pci/pci_params.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_params.c +27 -2
index 0fde75803..7630d4845 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#267 lore raw

PATCH v9 17/27 bus/vdev: implement device iteration

In reply to Gaetan Rivet
---
 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
drivers/bus/vdev/Makefile +2 -1
index bd0bb8955..1f9cd7ebe 100644
@@ -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
drivers/bus/vdev/vdev.c +6 -4
index 6139dd551..e8518833d 100644
@@ -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);
drivers/bus/vdev/vdev_params.c new file +51 -0

51 lines not on this page · raw message

drivers/bus/vdev/vdev_private.h new file +26 -0
new file mode 100644
index 000000000..ba6dc48ff
@@ -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_ */
Signature · 1 line
2.11.0
#268 lore raw

PATCH v9 18/27 bus/vdev: add device matching field driver

In reply to Gaetan Rivet

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

"bus=vdev,driver=xxxx"

---
 drivers/bus/vdev/vdev_params.c | 15 +++++++++++++--
 1 file changed, 13 insertions(+), 2 deletions(-)
drivers/bus/vdev/vdev_params.c +13 -2
index 842a4684e..2f55f451f 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#269 lore raw

PATCH v9 19/27 ethdev: add private generic device iterator

In reply to 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.

---
 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
lib/librte_ethdev/Makefile +1 -0
index c2f2f7d82..2fa133fbc 100644
@@ -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
lib/librte_ethdev/eth_private.c new file +31 -0
new file mode 100644
index 000000000..d565568a0
@@ -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;
+}
+
lib/librte_ethdev/eth_private.h new file +26 -0
new file mode 100644
index 000000000..0f5c6d5c4
@@ -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_ */
Signature · 1 line
2.11.0
#270 lore raw

PATCH v9 20/27 ethdev: register ether layer as a class

In reply to Gaetan Rivet
---
 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
lib/librte_ethdev/Makefile +2 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
lib/librte_ethdev/rte_class_eth.c new file +79 -0

79 lines not on this page · raw message

Signature · 1 line
2.11.0
#271 lore raw

Re: [PATCH v9 20/27] ethdev: register ether layer as a class

Quoted 21 lines · Gaetan Rivet
---
  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

lib/librte_ethdev/Makefile +1 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
 

lib/librte_ethdev/Makefile LIBABIVER := 9 · line 26

Quoted 7 lines
lib/librte_ethdev/Makefile +1 -0
@@ -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.

#272 lore raw

Re: [PATCH v9 20/27] ethdev: register ether layer as a class

Hi Andrew,

Quoted 20 lines · Andrew Rybchenko
Quoted 19 lines · Gaetan Rivet
---
  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

lib/librte_ethdev/Makefile +1 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
Quoted 8 lines

lib/librte_ethdev/Makefile LIBABIVER := 9 · line 26

Quoted 6 lines
lib/librte_ethdev/Makefile +1 -0
  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.

Signature · 2 lines
Gaëtan Rivet
6WIND
#273 lore raw

Re: [PATCH v9 20/27] ethdev: register ether layer as a class

Quoted 32 lines · Gaëtan Rivet

Hi Andrew,

Quoted 20 lines · Andrew Rybchenko
Quoted 19 lines · Gaetan Rivet
---
  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

lib/librte_ethdev/Makefile +1 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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
Quoted 8 lines

lib/librte_ethdev/Makefile LIBABIVER := 9 · line 26

Quoted 6 lines
lib/librte_ethdev/Makefile +1 -0
  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.

Quoted 2 lines

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

#274 lore raw

Re: [PATCH v9 20/27] ethdev: register ether layer as a class

Quoted 33 lines · Bruce Richardson
Quoted 32 lines · Gaëtan Rivet

Hi Andrew,

Quoted 28 lines · Andrew Rybchenko
Quoted 19 lines · Gaetan Rivet
---
  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

lib/librte_ethdev/Makefile +1 -1
index 2fa133fbc..d4c3a8d06 100644
@@ -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

lib/librte_ethdev/Makefile LIBABIVER := 9 · line 25

Quoted 6 lines
lib/librte_ethdev/Makefile +1 -0
@@ -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.

Quoted 7 lines
Quoted 2 lines

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.

Signature · 2 lines
Gaëtan Rivet
6WIND
#275 lore raw

PATCH v9 21/27 ethdev: add device matching field name

In reply to 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"

---
 lib/librte_ethdev/rte_class_eth.c | 7 +++++++
 1 file changed, 7 insertions(+)
lib/librte_ethdev/rte_class_eth.c +7 -0
index 32c736d32..d8d8e8845 100644
@@ -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;
 }
 
Signature · 1 line
2.11.0
#276 lore raw

PATCH v9 22/27 app/testpmd: add show device command

In reply to 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.

---
 app/test-pmd/cmdline.c                      | 54 +++++++++++++++++++++++++++++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 24 +++++++++++++
 2 files changed, 78 insertions(+)
app/test-pmd/cmdline.c +54 -0
index 27e2aa8c8..3b86bfe48 100644
@@ -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,
doc/guides/testpmd_app_ug/testpmd_funcs.rst +24 -0
index 0d6fd50ca..4f1009a3a 100644
@@ -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
 ----------------
 
Signature · 1 line
2.11.0
#277 lore raw

PATCH v9 23/27 bus/pci: pre-process declarative PCI devargs

In reply to 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.

---
 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(+)
drivers/bus/pci/bsd/pci.c +5 -0
index 655b34b7e..046cd11d5 100644
@@ -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__);
drivers/bus/pci/linux/pci.c +5 -0
index 004600f1c..0c20a4337 100644
@@ -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");
drivers/bus/pci/pci_params.c +55 -0

67 lines not on this page · raw message

drivers/bus/pci/private.h +16 -0
index 0e689fa74..9beb24c6a 100644
@@ -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_ */
Signature · 1 line
2.11.0
#278 lore raw

PATCH v9 24/27 bus/vdev: pre-process declarative vdev devargs

In reply to 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.

---
 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(-)
drivers/bus/vdev/vdev.c +6 -4
index e8518833d..f2dace245 100644
@@ -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,
 };
 
drivers/bus/vdev/vdev_params.c +50 -0

64 lines not on this page · raw message

drivers/bus/vdev/vdev_private.h +6 -0
index ba6dc48ff..da57b84dd 100644
@@ -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
Signature · 1 line
2.11.0
#279 lore raw

PATCH v9 25/27 bus/pci: process declarative PCI devargs

In reply to 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.

---
 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(+)
drivers/bus/pci/pci_common.c +3 -0
index 749b6eee3..e2816eedb 100644
@@ -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)
drivers/bus/pci/pci_params.c +10 -0
index bb62bcb80..7dceef89b 100644
@@ -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;
+}
drivers/bus/pci/private.h +13 -0
index 9beb24c6a..06dc85e85 100644
@@ -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_ */
Signature · 1 line
2.11.0
#280 lore raw

PATCH v9 26/27 ethdev: process declarative eth devargs

In reply to Gaetan Rivet

Process the class-specific arguments in a devargs.
This processing takes the form of setting the proper eth_dev fields when relevant.

---
 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(+)
lib/librte_ethdev/eth_private.h +5 -0
index 0f5c6d5c4..c0c065165 100644
@@ -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
lib/librte_ethdev/rte_class_eth.c +61 -0

73 lines not on this page · raw message

lib/librte_ethdev/rte_ethdev.c +7 -0
index cce20d9ae..4583509dd 100644
@@ -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");
Signature · 1 line
2.11.0
#281 lore raw

PATCH v9 27/27 eal: add generic dev parameter

In reply to 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.

---
 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(-)
lib/librte_eal/common/eal_common_devargs.c +4 -0
index 5f89e0b6e..bc3ba9fe0 100644
@@ -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;
lib/librte_eal/common/eal_common_options.c +31 -5
index ecebb2923..89d608180 100644
@@ -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;
lib/librte_eal/common/eal_options.h +2 -0
index 211ae06ae..b1851864f 100644
@@ -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"
Signature · 1 line
2.11.0
#282 lore raw

v10 cover Device querying

In reply to 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.

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
Signature · 1 line
2.18.0
#283 lore raw

PATCH v10 1/27 devargs: add non-variadic parsing function

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose device strings.

---
 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(-)
drivers/net/failsafe/failsafe_args.c +1 -1
index 2c002b164..626883ce2 100644
@@ -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;
drivers/net/failsafe/failsafe_eal.c +1 -1
index 5672f3961..ce1633f13 100644
@@ -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);
lib/librte_eal/common/eal_common_dev.c +2 -2
index 61cb3b162..ce4b51469 100644
@@ -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;
 
lib/librte_eal/common/eal_common_devargs.c +32 -10

69 lines not on this page · raw message

lib/librte_eal/common/include/rte_devargs.h +38 -2
index 58fbd90a2..6c3b6326b 100644
@@ -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)));
 
 /**
lib/librte_eal/rte_eal_version.map +1 -0
index f7dd0e7bc..1c4db72fa 100644
@@ -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;
lib/librte_ethdev/rte_ethdev.c +1 -1
index a9977df97..cce20d9ae 100644
@@ -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);
Signature · 1 line
2.18.0
Acked-by on v10 1/27
#285 lore raw

Re: [PATCH v10 01/27] devargs: add non-variadic parsing function

In reply to Gaetan Rivet
Quoted 15 lines · Gaetan Rivet

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose device strings.

---
  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(-)

[...]

Quoted 8 lines
lib/librte_eal/common/eal_common_devargs.c +8 -0
+__rte_experimental
+int
+rte_devargs_parsef(struct rte_devargs *da, const char *format, ...)
+{
+	va_list ap;
+	size_t len;
+	char *dev;
+

lib/librte_eal/common/eal_common_devargs.c rte_devargs_parse(struct rte_devargs *da, const char *format, ...) · line 138

Quoted 10 lines
lib/librte_eal/common/eal_common_devargs.c +10 -0
+	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?

lib/librte_eal/common/eal_common_devargs.c rte_devargs_parse(struct rte_devargs *da, const char *format, ...) · line 151

Quoted 13 lines
lib/librte_eal/common/eal_common_devargs.c +10 -0
+		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:

#286 lore raw

Re: [PATCH v10 01/27] devargs: add non-variadic parsing function

Quoted 31 lines · Shreyansh Jain
Quoted 15 lines · Gaetan Rivet

rte_devargs_parse becomes non-variadic,
rte_devargs_parsef becomes the variadic version, to be used to compose device strings.

---
  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(-)

[...]

Quoted 12 lines
lib/librte_eal/common/eal_common_devargs.c +12 -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);
Quoted 9 lines

lib/librte_eal/common/eal_common_devargs.c rte_devargs_parse(struct rte_devargs *da, const char *format, ...) · line 138

Quoted 6 lines
lib/librte_eal/common/eal_common_devargs.c +6 -0
+	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.

Quoted 19 lines

lib/librte_eal/common/eal_common_devargs.c rte_devargs_parse(struct rte_devargs *da, const char *format, ...) · line 151

Quoted 13 lines
lib/librte_eal/common/eal_common_devargs.c +10 -0
+		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:

Signature · 2 lines
Gaëtan Rivet
6WIND
#287 lore raw

PATCH v10 2/27 kvargs: remove error logs

In reply to Gaetan Rivet

Error logs in kvargs parsing should be better handled in components calling the library.

This library must be as lean as possible.

---
 lib/librte_kvargs/rte_kvargs.c | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)
lib/librte_kvargs/rte_kvargs.c +5 -17
index d92a5f9dc..747f14964 100644
@@ -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;
 }
Signature · 1 line
2.18.0