Device querying
Subsystems (3)
cover Device querying
This patchset introduces a new EAL API for querying devices, filtered by arbitrary properties.
The following elements are introduced to this end:
* A new object, "rte_class", is used to describe the device class abstraction layer (eth, crypto, ...).
* Both rte_bus and rte_class now offer a way to
list their devices and filter the result
using locally defined properties.
* The rte_dev API now has an rte_dev_iterator, which is the way for the user to define the device filter and iterate upon the resulting set.
As an example, the "eth" device class is implemented.
Additionally, the device filters for
+ rte_bus_pci
+ rte_bus_vdev
+ rte_class_eth
are implemented and can be used with some
properties each, to show how to extend those.
Some example of filters:
"bus=pci/class=eth"
"bus=pci"
"class=eth"
"class=eth,name=net_ring0"
"bus=pci,id=00:00.0"
"bus=vdev,driver=net_ring"
Gaetan Rivet (18):
eal: introduce dtor macros
eal: introduce device class abstraction eal/class: register destructor
eal: add lightweight kvarg parsing utility eal/dev: add device iterator interface eal/dev: implement device iteration initialization eal/class: add device iteration
eal/bus: add device iteration
eal/dev: implement device iteration
ethdev: register ether layer as a class
ethdev: add device matching field name bus/pci: fix find device implementation bus/pci: implement device iteration and comparison bus/pci: add device matching field id bus/vdev: fix find device implementation bus/vdev: implement device iteration bus/vdev: add device matching field driver app/testpmd: add show device command
app/test-pmd/cmdline.c | 52 +++++++++ drivers/bus/pci/Makefile | 2 +- drivers/bus/pci/pci_common.c | 97 ++++++++++++++-- drivers/bus/pci/rte_bus_pci.h | 3 + drivers/bus/vdev/Makefile | 2 +- drivers/bus/vdev/rte_bus_vdev.h | 3 + drivers/bus/vdev/vdev.c | 86 +++++++++++++- lib/Makefile | 2 +- lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/Makefile | 2 +- lib/librte_eal/common/eal_common_class.c | 62 ++++++++++ lib/librte_eal/common/eal_common_dev.c | 177 +++++++++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 34 ++++++ lib/librte_eal/common/include/rte_bus.h | 1 + lib/librte_eal/common/include/rte_class.h | 127 +++++++++++++++++++++ lib/librte_eal/common/include/rte_common.h | 23 ++++ lib/librte_eal/common/include/rte_dev.h | 84 ++++++++++++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 4 + lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 100 ++++++++++++++++ 21 files changed, 847 insertions(+), 19 deletions(-) create mode 100644 lib/librte_eal/common/eal_common_class.c create mode 100644 lib/librte_eal/common/include/rte_class.h create mode 100644 lib/librte_ether/rte_class_eth.c
Signature · 1 line
2.11.0
PATCH 1/18 eal: introduce dtor macros
--- lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
lib/librte_eal/common/include/rte_common.h +23 -0
@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)static void __attribute__((constructor (prio), used))func (void )/** +* Run after main() with high priority. +* +* The destructor will be run *before* prioritized destructors. +* +* @param func +* Destructor function name. + */ +#define RTE_FINI (func) \ +static void __attribute__((destructor, used)) func(void) + +/** +* Run after main() with low priority. +* +* @param func +* Destructor function name. +* @param prio +* Priority number must be above 100. +* Lowest number is the last to run. +*/ +#define RTE_FINI_PRIO (func, prio) \ +static void __attribute__((destructor(prio), used)) func(void) + +/** * Force a function to be inlined */ #define __rte_always_inline inline __attribute__((always_inline))
Signature · 1 line
2.11.0
PATCH 2/18 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/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 2 + 6 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 lib/librte_eal/common/eal_common_class.c create mode 100644 lib/librte_eal/common/include/rte_class.h
lib/librte_eal/bsdapp/eal/Makefile +1 -0
@@ -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
@@ -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/linuxapp/eal/Makefile +1 -0
@@ -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
@@ -215,6 +215,8 @@ EXPERIMENTAL { global: rte_eal_cleanup; + rte_class_register; + rte_class_unregister; rte_eal_devargs_insert; rte_eal_devargs_parse; rte_eal_devargs_remove;
Signature · 1 line
2.11.0
PATCH 3/18 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
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \ {\ (cls).name =RTE_STR (nm);\rte_class_register (&cls); \ +} \ +RTE_FINI_PRIO(classfinifn_ ##nm, 120); \ +static void classfinifn_ ##nm(void) \ +{ \ + rte_class_unregister(&cls); \ }#ifdef __cplusplus
Signature · 1 line
2.11.0
PATCH 4/18 eal: add lightweight kvarg parsing utility
In reply to Gaetan RivetThis library offers a quick way to parse parameters passed with a key=value syntax.
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete librte_kvargs.
--- lib/librte_eal/common/eal_common_dev.c | 38 ++++++++++++++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 34 ++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+)
lib/librte_eal/common/eal_common_dev.c +38 -0
@@ -13,10 +13,48 @@#include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> #include <rte_log.h> #include "eal_private.h" +/* EAL-private function. */ +int +rte_parse_kv (const char *str,struct rte_kvarg *kv) +{ +const char *equal; +const char *end; + +if (str ==NULL || str[0 ] =='\0' ) +return 1 ; + equal =strchr (str,'=' ); +if (equal ==NULL ) { + rte_errno =EINVAL ; +return -1 ; + } + end =strchr (equal +1 ,',' ); + end = end ? end :strchr (equal +1 ,'/' ); + end = end ? end :strchr (equal +1 ,'\0' ); +if (end ==NULL ) { + rte_errno =ENODEV ; +return -1 ; + } +if (kv ==NULL ) +return 0 ; +snprintf (kv->data,sizeof (kv->data),"%s" , str); + kv->key = &kv->data[0 ]; +strchr (kv->data, end[0 ])[0 ] ='\0' ; +if (strchr (kv->data,'=' )) { + kv->value =strchr (kv->data,'=' ) +1 ; +strchr (kv->data,'=' )[0 ] ='\0' ; + } +if (end[0 ] =='\0' ) + kv->next =NULL ; +else + kv->next = end +1 ; +return 0 ; +} +static int cmp_detached_dev_name (const struct rte_device *dev,const void *_name) {
lib/librte_eal/common/eal_private.h +34 -0
@@ -205,4 +205,38 @@ struct rte_bus *rte_bus_find_by_device_name(const char *str);int rte_mp_channel_init (void ); +/* +* Lightweight kvarg parsing library. +*/ + +#define RTE_MAX_KVARG_LEN 64 + +/** +* Kvarg representation. +*/ +struct rte_kvarg { +char *key;/**< points the key in the data. */ +char *value;/**< points the value in the data. */ +const char *next;/**< next token to parse, if any. */ +char data[RTE_MAX_KVARG_LEN +1 ];/**< local copy of key and value. */ +}; + +/** +* Parse one kvarg. +* +* The key-value pair must be shorter than the rte_kvarg data size. +* +* @param[in] str +* text to parse. +* +* @param[out] kv +* kvarg structure to fill. +* +* @return +* 0 if parsing succeeded. +* >0 if there was nothing to parse. +* <0 on error, rte_errno is set. +*/ +int rte_parse_kv (const char *str,struct rte_kvarg *kv); +#endif /* _EAL_PRIVATE_H_ */
Signature · 1 line
2.11.0
PATCH 5/18 eal/dev: add device iterator interface
In reply to Gaetan RivetA device iterator allows iterating over a set of devices. This set is defined by the two descriptions offered,
* rte_bus
* rte_class
Only one description can be provided, or both. It is not allowed to provide no description at all.
Each layer of abstraction them performs a filter based on the description provided. This filtering allows iterating on their internal set of devices, stopping when a match is valid and storing the current iteration context.
This context allows starting the next iteration from the same point and going forward.
--- lib/librte_eal/common/include/rte_dev.h | 36 +++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+)
lib/librte_eal/common/include/rte_dev.h +36 -0
@@ -263,6 +263,42 @@ __attribute__((used)) = str static const char DRV_EXP_TAG(name, kmod_dep_export)[] \ __attribute__((used)) = str +/** +* Iteration context. +* +* This context carries over the current iteration state. +*/ +struct rte_dev_iterator { +const char *devstr;/**< device string. */ +/* Bus context. */ +struct rte_bus *bus;/**< bus handle. */ +const char *busstr;/**< bus-related part of device string. */ +struct rte_device *device;/**< current position. */ +/* Class context. */ +struct rte_class *cls;/**< class handle. */ +const char *clsstr;/**< class-related part of device string. */ +void *class_device;/**< additional specialized context. */ +}; + +/** +* Device iteration function. +* +* Iterate over a set of devices, defined in comprehension by +* the given iterator. +* +* This function must update the internal rte_dev_iterator ``device`` +* field. The ``context`` field can be used as an additional generic context +* when the current ``rte_device`` is insufficient. +* +* @param it +* Device iterator. +* +* @return +* The address of the current element when the stopping +* condition became valid. +*/ +typedef struct rte_device *(*rte_dev_iterate_t )(struct rte_dev_iterator *it); + #ifdef __cplusplus }#endif
Signature · 1 line
2.11.0
PATCH 6/18 eal/dev: implement device iteration initialization
In reply to Gaetan RivetParse a device description.
Split this description in their relevant part for both abstraction layer.
No dynamic allocation is performed.
--- lib/librte_eal/common/eal_common_dev.c | 58 +++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 82 insertions(+)
lib/librte_eal/common/eal_common_dev.c +58 -0
@@ -10,6 +10,7 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h>
@@ -245,3 +246,60 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str) +{ +struct rte_bus *bus =NULL ; +struct rte_class *cls =NULL ; +struct rte_kvarg kv; + +/* Having both busstr and clsstr NULL is illegal, +* marking this iterator as invalid unless +* everything goes well. +*/ + it->busstr =NULL ; + it->clsstr =NULL ; +/* Safety checks and prep-work */ +if (rte_parse_kv (str, &kv)) { +RTE_LOG (ERR ,EAL ,"Could not parse: %s\n" , str); +return -1 ; + } + it->device =NULL ; + it->class_device =NULL ; +if (strcmp (kv.key,"bus" ) ==0 ) { +char *slash; + + bus =rte_bus_find_by_name (kv.value); + it->busstr = str; + slash =strchr (str,'/' ); +if (slash !=NULL ) { +if (rte_parse_kv (slash +1 , &kv)) +return -1 ; + cls =rte_class_find_by_name (kv.value); + it->clsstr = slash +1 ; + } + }else if (strcmp (kv.key,"class" ) ==0 ) { + cls =rte_class_find_by_name (kv.value); + it->clsstr = str; + }else { + rte_errno =EINVAL ; +return -rte_errno; + } +/* The string should have at least +* one layer specified. +*/ +if (bus ==NULL && cls ==NULL ) { + rte_errno =EINVAL ; +return -rte_errno; + } +if ((bus !=NULL && bus->dev_iterate ==NULL ) || + (cls !=NULL && cls->dev_iterate ==NULL )) { + rte_errno =ENOTSUP ; +return -rte_errno; + } + it->devstr = str; + it->bus = bus; + it->cls = cls; +return 0 ; +}
lib/librte_eal/common/include/rte_dev.h +23 -0
@@ -299,6 +299,29 @@ struct rte_dev_iterator {*/ typedef struct rte_device *(*rte_dev_iterate_t )(struct rte_dev_iterator *it); +/** +* Initializes a device iterator. +* +* This iterator allows accessing a list of devices matching a criteria. +* The device matching is made among all buses and classes currently registered, +* filtered by the device description given as parameter. +* +* This function will not allocate any memory. It is safe to stop the +* iteration at any moment and let the iterator go out of context. +* +* @param it +* Device iterator handle. +* +* @param str +* Device description string. +* +* @return +* 0 on successful initialization. +* <0 on error. +*/ +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); + #ifdef __cplusplus }#endif
lib/librte_eal/rte_eal_version.map +1 -0
@@ -228,6 +228,7 @@ EXPERIMENTAL { rte_mp_sendmsg; rte_mp_request; rte_mp_reply; + rte_dev_iterator_init; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
PATCH 7/18 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
@@ -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
PATCH 8/18 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
@@ -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
PATCH 9/18 eal/dev: implement device iteration
In reply to Gaetan RivetUse 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 | 81 +++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 25 ++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 107 insertions(+)
lib/librte_eal/common/eal_common_dev.c +81 -0
@@ -303,3 +303,84 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str) it->cls = cls;return 0 ; } + +static int +class_next_dev_cmp (const struct rte_class *cls, +const void *_it) +{ +const struct rte_dev_iterator *cit = _it; +struct rte_dev_iterator *it; + +if (cls->dev_iterate ==NULL ) +return 1 ; +/* We need a mutable iterator. */ + it = (void *)(intptr_t )cit; +/* it->clsstr != NULL means a class +* was specified in the devstr. +*/ +if (it->clsstr !=NULL && cls != it->cls) +return 1 ; +return cls->dev_iterate (it) ==NULL ; +} + +static int +bus_next_dev_cmp (const struct rte_bus *bus, +const void *_it) +{ +const struct rte_dev_iterator *cit = _it; +struct rte_class *cls =NULL ; +struct rte_dev_iterator *it; + +if (bus->dev_iterate ==NULL ) +return 1 ; +/* We need a mutable iterator. */ + it = (void *)(intptr_t )cit; +/* it->busstr != NULL means a bus +* was specified in the devstr. +*/ +if (it->busstr !=NULL && bus != it->bus) +return 1 ; +if (it->clsstr ==NULL ) +return bus->dev_iterate (it) ==NULL ; +/* clsstr != NULL */ +if (it->device ==NULL ) +next_dev_on_bus: + bus->dev_iterate (it); +if (it->device ==NULL ) +return 1 ; +if (it->cls !=NULL ) + cls =TAILQ_PREV (it->cls, rte_class_list, next); + cls =rte_class_find (cls, class_next_dev_cmp, it); +if (cls !=NULL ) { + it->cls = cls; +return 0 ; + } + goto next_dev_on_bus; +} +__rte_experimental struct rte_device * +rte_dev_iterator_next (struct rte_dev_iterator *it) +{ +struct rte_bus *bus =NULL ; +int old_errno = rte_errno; + + rte_errno =0 ; +if (it->busstr ==NULL && it->clsstr ==NULL ) { +/* Invalid iterator. */ + rte_errno =EINVAL ; +return NULL ; + } +if (it->bus !=NULL ) + bus =TAILQ_PREV (it->bus, rte_bus_list, next); +while ((bus =rte_bus_find (bus, bus_next_dev_cmp, it))) { +if (it->device !=NULL ) { + it->bus = bus; +return it->device; + } +if (it->busstr !=NULL || + rte_errno !=0 ) +break ; + } +if (rte_errno ==0 ) + rte_errno = old_errno; +return NULL ; +}
lib/librte_eal/common/include/rte_dev.h +25 -0
@@ -322,6 +322,31 @@ typedef struct rte_device *(*rte_dev_iterate_t)(struct rte_dev_iterator *it); int __rte_experimentalrte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); +/** +* Iterates on a device iterator. +* +* Generates a new rte_device handle corresponding to the next element +* in the list described in comprehension by the iterator. +* +* The next object is returned, and the iterator is updated. +* +* @param it +* Device iterator handle. +* +* @return +* An rte_device handle if found. +* NULL if an error occurred (rte_errno is set). +* NULL if no device could be found (rte_errno is not set). +*/ +struct rte_device * __rte_experimental +rte_dev_iterator_next (struct rte_dev_iterator *it); + +#define RTE_DEV_FOREACH (dev, devstr, it) \ + for (rte_dev_iterator_init(it, devstr), \ + dev = rte_dev_iterator_next(it); \ + dev != NULL; \ + dev = rte_dev_iterator_next(it)) + #ifdef __cplusplus }#endif
lib/librte_eal/rte_eal_version.map +1 -0
@@ -229,6 +229,7 @@ EXPERIMENTAL { rte_mp_request; rte_mp_reply; rte_dev_iterator_init; + rte_dev_iterator_next; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
PATCH 10/18 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 | 86 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 lib/librte_ether/rte_class_eth.c
lib/Makefile +1 -1
@@ -20,7 +20,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline DEPDIRS-librte_cmdline := librte_eal DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring -DEPDIRS-librte_ether += librte_mbuf +DEPDIRS-librte_ether += librte_mbuf librte_kvargs DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
lib/librte_ether/Makefile +2 -1
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf +LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.c
lib/librte_ether/rte_class_eth.c new file +86 -0
86 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH 11/18 ethdev: add device matching field name
In reply to Gaetan RivetThe 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 | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
lib/librte_ether/rte_class_eth.c +16 -2
@@ -14,11 +14,25 @@#include "rte_ethdev_core.h" static int +eth_dev_str_cmp(const char *key __rte_unused, +const char *value, +void *_str) +{ +const char *str = _str; + +return strcmp (str, value); +} + +static int eth_dev_match (struct rte_eth_dev *edev,struct rte_kvargs *kvlist) { - (void ) kvlist; - (void ) edev; +struct rte_eth_dev_data *data; + + data = edev->data; +if (rte_kvargs_process (kvlist,"name" , + ð_dev_str_cmp, data->name)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH 12/18 bus/pci: fix find device implementation
In reply to Gaetan RivetIf start is set, and a device before it matches the data passed for comparison, then this first device is returned.
This produces potentially infinite loops.
--- 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
@@ -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
@@ -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
PATCH 13/18 bus/pci: implement device iteration and comparison
In reply to Gaetan Rivet--- drivers/bus/pci/Makefile | 2 +- drivers/bus/pci/pci_common.c | 54 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-)
drivers/bus/pci/Makefile +1 -1
@@ -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 +54 -0
72 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH 14/18 bus/pci: add device matching field id
In reply to Gaetan RivetThe 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 | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_common.c +24 -2
@@ -499,13 +499,35 @@ pci_unplug(struct rte_device *dev) }static int +pci_addr_kv_cmp(const char *key __rte_unused, +const char *value, +void *_addr2) +{ +struct rte_pci_addr _addr1; +struct rte_pci_addr *addr1 = &_addr1; +struct rte_pci_addr *addr2 = _addr2; + +if (rte_pci_addr_parse (value, addr1)) +return -1 ; +return rte_pci_addr_cmp (addr1, addr2); +} + +static int pci_dev_match (const struct rte_device *dev,const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_pci_device *pdev; - (void ) dev; - (void ) kvlist; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + pdev =RTE_DEV_TO_PCI_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"id" , + &pci_addr_kv_cmp, + (void *)(intptr_t )&pdev->addr)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH 15/18 bus/vdev: fix find device implementation
In reply to Gaetan RivetIf start is set and a device before it matches the data, this device is returned.
This produces induces potentially infinite loops.
--- 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
@@ -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
@@ -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
PATCH 16/18 bus/vdev: implement device iteration
In reply to Gaetan Rivet--- drivers/bus/vdev/Makefile | 2 +- drivers/bus/vdev/vdev.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-)
drivers/bus/vdev/Makefile +1 -1
@@ -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 +54 -0
72 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH 17/18 bus/vdev: add device matching field driver
In reply to Gaetan RivetThe vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:
"bus=vdev,driver=xxxx"
--- drivers/bus/vdev/vdev.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
drivers/bus/vdev/vdev.c +20 -2
@@ -417,13 +417,31 @@ vdev_unplug(struct rte_device *dev) }static int +vdev_str_kv_cmp(const char *key __rte_unused, +const char *value, +void *_str) +{ +const char *str = _str; + +return strcmp (str, value); +} + +static int vdev_dev_match (const struct rte_device *dev,const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_vdev_device *vdev; - (void ) kvlist; - (void ) dev; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + vdev =RTE_DEV_TO_VDEV_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"driver" , + &vdev_str_kv_cmp, + (void *)(intptr_t )vdev->device.driver->name)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH 18/18 app/testpmd: add show device command
In reply to Gaetan RivetA new interactive command is offered:
show device <device description>
This commands lists all rte_device element matching the device description. e.g.:
show device bus=pci
show device bus=vdev
show device bus=vdev,class=eth
show device bus=vdev,class=eth,name=net_ring0
These devices may not be otherwise useful, some buses will spawn devices to keep track of their assets without having a driver to use them.
--- app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)
app/test-pmd/cmdline.c +52 -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 ); + +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
Re: [PATCH v1 18/18] app/testpmd: add show device command
Quoted 11 lines · Gaetan Rivet
A new interactive command is offered:
show device <device description>
This commands lists all
rte_deviceelement matching the device description. e.g.:show device bus=pci
show device bus=vdev
show device bus=vdev,class=eth
show device bus=vdev,class=eth,name=net_ring0
Silly mistake, it should read instead:
show device bus=pci
show device bus=vdev
show device bus=vdev/class=eth
show device bus=vdev/class=eth,name=net_ring0
Quoted 82 lines
These devices may not be otherwise useful, some buses will spawn devices to keep track of their assets without having a driver to use them.
Signed-off-by Gaetan Rivet <[email protected]>--- app/test-pmd/cmdline.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+)app/test-pmd/cmdline.c +52
-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 ); + +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
Signature · 2 lines
Gaëtan Rivet 6WIND
Quoted 29 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_busandrte_classnow offer a way to
list their devices and filter the result
using locally defined properties.* The
rte_devAPI now has anrte_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_ethare implemented and can be used with some
properties each, to show how to extend those.Some example of filters:
Quoted 8 lines
"bus=pci/class=eth"
"bus=pci"
"class=eth"
"class=eth,name=net_ring0"
"bus=pci,id=00:00.0"
"bus=vdev,driver=net_ring"Gaetan Rivet (18):
To ease reviewing and have a state of this work, here is a summary of what to expect / my opinion of what's done:
Quoted 1 line
eal: introduce dtor macros
* Not sure this is necessary, but as long as the libc has a dlclose, it makes sense to have a way to cleanly unload objects.
Quoted 1 line
eal: introduce device class abstraction
* The class abstraction might seem controversial introduced there, but I do not think there is any other solution than adding it. The EAL needs a way to converse in a generic way with each types of devices, even if the technical solution I proposed afterward is not accepted.
Quoted 1 line
eal/class: register destructor
* If the dtor patch above is accepted, this patch could be squashed with the previous one. Otherwise, it can be dropped.
Quoted 2 lines
eal: add lightweight kvarg parsing utility
eal/dev: add device iterator interface
* An important question regarding device matching is how to deal when the query is ambiguous and several devices could match. I have taken the technical bias of leaving the management of this case to the user.
This has the beneficial side-effect of allowing to list all devices matching specific properties. I think this is useful. However, much of the complexity of this solution comes from this added functionality.
* The iterator only allows filtering on the two abstractions:
+ bus
+ class
This limitation is hard-coded, simplifying the implementation.
Quoted 1 line
eal/dev: implement device iteration initialization
* An important element of this initialization was to make it entirely static. To help the user correctly use this API, this seemed important. No dynamic allocation was to be performed here.
This means that the device description string must live for the time of the iteration. An iterator must be iterated in the same scope it has been initialized.
A big problem with this approach, is that the matching strings cannot be duplicated to be properly reformated, helping the subsequent parsing. Thus, the iteration operation implemented both in rte_bus and rte_class are more complex, having to take care of both cases where an ending '/' and '\0' are present, and this, for all implementations. I profoundly dislike this complexity being replicated thusly, but I think the advantage of having a lean iterator init is worth it.
Quoted 3 lines
eal/class: add device iteration
eal/bus: add device iteration
eal/dev: implement device iteration
* Iteration has been choosen over implementing only a match function, that would be used in conjunction with the existing bus->find_device
The reasoning for this is two-fold:
- Classes are not streamlined. They usually link rte_devices instead of extending the rte_device object with their own meta-data, like rte_buses are doing.
So the iteration itself had to be as flexible as possible, to allow rte_classes to do anything they might need to speed up / simplify the iteration.
- The filtering strings could have been made once for all filters, having only to call *_find_device with the proper matching function.
However, instead of replicating the string handling, each matching would thus have to parse the kvargs itself or have the kvargs parsed prior to being called. The latter would mean having the EAL dependent on librte_kvargs. The former meaning that kvargs would be repeated again and again, with dynamic allocations with it (meaning that they could not just be kept away until the next iteration as they would be already parsed, as the user could always break the iteration, loosing the reference).
I think the choice of iteration vs. match function is central to the design of this solution and should be carefully reviewed. I tried to make the right call, can be wrong.
vvvvvvvvv <-- the rest only builds upon the foundations layed out by the
previous patches, so choices here are less important.
Last point however: I havent yet implemented the rte_eth_dev finder taking a device description as input and giving the corresponding port_id. It should be simple to implement with this new API so I will do it shortly, once I have some time for it.
Quoted 27 lines
ethdev: register ether layer as a class
ethdev: add device matching field name bus/pci: fix find device implementation bus/pci: implement device iteration and comparison bus/pci: add device matching field id bus/vdev: fix find device implementation bus/vdev: implement device iteration bus/vdev: add device matching field driver app/testpmd: add show device commandapp/test-pmd/cmdline.c | 52 +++++++++ drivers/bus/pci/Makefile | 2 +- drivers/bus/pci/pci_common.c | 97 ++++++++++++++-- drivers/bus/pci/rte_bus_pci.h | 3 + drivers/bus/vdev/Makefile | 2 +- drivers/bus/vdev/rte_bus_vdev.h | 3 + drivers/bus/vdev/vdev.c | 86 +++++++++++++- lib/Makefile | 2 +- lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/Makefile | 2 +- lib/librte_eal/common/eal_common_class.c | 62 ++++++++++ lib/librte_eal/common/eal_common_dev.c | 177 +++++++++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 34 ++++++ lib/librte_eal/common/include/rte_bus.h | 1 + lib/librte_eal/common/include/rte_class.h | 127 +++++++++++++++++++++ lib/librte_eal/common/include/rte_common.h | 23 ++++ lib/librte_eal/common/include/rte_dev.h | 84 ++++++++++++++
Quoted 12 lines
lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 4 + lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 100 ++++++++++++++++ 21 files changed, 847 insertions(+), 19 deletions(-) create mode 100644 lib/librte_eal/common/eal_common_class.c create mode 100644 lib/librte_eal/common/include/rte_class.h create mode 100644 lib/librte_ether/rte_class_eth.cSignature · 1 line
2.11.0
Regards,
Signature · 2 lines
Gaëtan Rivet 6WIND
v2 cover Device querying
In reply to Gaetan RivetThis patchset introduces a new EAL API for querying devices, filtered by arbitrary properties.
The following elements are introduced to this end:
* A new object, "rte_class", is used to describe the device class abstraction layer (eth, crypto, ...).
* Both rte_bus and rte_class now offer a way to
list their devices and filter the result
using locally defined properties.
* The rte_dev API now has an rte_dev_iterator, which is the way for the user to define the device filter and iterate upon the resulting set.
As an example, the "eth" device class is implemented.
Additionally, the device filters for
+ rte_bus_pci
+ rte_bus_vdev
+ rte_class_eth
are implemented and can be used with some
properties each, to show how to extend those.
Some example of filters:
"bus=pci/class=eth"
"bus=pci"
"class=eth"
"class=eth,name=net_ring0"
"bus=pci,id=00:00.0"
"bus=vdev,driver=net_ring"
---
v2:
* Reworked the dev_iterate callback to simplify
its implementation.
Now dev_iterate implementation do not need to learn about the intricacies of the rte_dev_iterator. The rte_dev_iterator is managed purely by the rte_dev_iterator_next function. Buses and classes then do not have to care about settings things right.
Additionally, dev_iterate implementations do not have to sanitize their dev string anymore, they are prepared by the rte_dev layer prior, which also reduces the number of dynamic allocations.
Gaetan Rivet (18):
eal: introduce dtor macros
eal: introduce device class abstraction eal/class: register destructor
eal: add lightweight kvarg parsing utility eal/dev: add device iterator interface eal/class: add device iteration
eal/bus: add device iteration
eal/dev: implement device iteration initialization eal/dev: implement device iteration bus/pci: fix find device implementation bus/pci: implement device iteration and comparison bus/pci: add device matching field id bus/vdev: fix find device implementation bus/vdev: implement device iteration bus/vdev: add device matching field driver
ethdev: register ether layer as a class
ethdev: add device matching field name app/testpmd: add show device command
app/test-pmd/cmdline.c | 52 ++++++ drivers/bus/pci/Makefile | 2 +- drivers/bus/pci/pci_common.c | 77 ++++++++- drivers/bus/pci/rte_bus_pci.h | 3 + drivers/bus/vdev/Makefile | 2 +- drivers/bus/vdev/rte_bus_vdev.h | 3 + drivers/bus/vdev/vdev.c | 66 +++++++- lib/Makefile | 2 +- lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/Makefile | 2 +- lib/librte_eal/common/eal_common_class.c | 62 +++++++ lib/librte_eal/common/eal_common_dev.c | 255 +++++++++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 34 ++++ lib/librte_eal/common/include/rte_bus.h | 1 + lib/librte_eal/common/include/rte_class.h | 127 ++++++++++++++ lib/librte_eal/common/include/rte_common.h | 23 +++ lib/librte_eal/common/include/rte_dev.h | 95 +++++++++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 4 + lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 79 +++++++++ 21 files changed, 875 insertions(+), 19 deletions(-) create mode 100644 lib/librte_eal/common/eal_common_class.c create mode 100644 lib/librte_eal/common/include/rte_class.h create mode 100644 lib/librte_ether/rte_class_eth.c
Signature · 1 line
2.11.0
PATCH v2 1/18 eal: introduce dtor macros
--- lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)
lib/librte_eal/common/include/rte_common.h +23 -0
@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)static void __attribute__((constructor (prio), used))func (void )/** +* Run after main() with high priority. +* +* The destructor will be run *before* prioritized destructors. +* +* @param func +* Destructor function name. + */ +#define RTE_FINI (func) \ +static void __attribute__((destructor, used)) func(void) + +/** +* Run after main() with low priority. +* +* @param func +* Destructor function name. +* @param prio +* Priority number must be above 100. +* Lowest number is the last to run. +*/ +#define RTE_FINI_PRIO (func, prio) \ +static void __attribute__((destructor(prio), used)) func(void) + +/** * Force a function to be inlined */ #define __rte_always_inline inline __attribute__((always_inline))
Signature · 1 line
2.11.0
Re: [PATCH v2 01/18] eal: introduce dtor macros
Quoted 26 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)lib/librte_eal/common/include/rte_common.h +13
-0@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)static void __attribute__((constructor (prio), used))func (void )/** +* Run after main() with high priority. +* +* The destructor will be run *before* prioritized destructors. +* +* @param func +* Destructor function name. + */ +#define RTE_FINI (func) \ +static void __attribute__((destructor, used)) func(void) + +/** +* Run after main() with low priority. +*
lib/librte_eal/common/include/rte_common.h static void __attribute__((constructor, used)) func(void) · line 130
Quoted 10 lines
lib/librte_eal/common/include/rte_common.h +10
-0+* @param func +* Destructor function name. +* @param prio +* Priority number must be above 100. +* Lowest number is the last to run. +*/ +#define RTE_FINI_PRIO (func, prio) \ +static void __attribute__((destructor(prio), used)) func(void) + +/**
If you need to require that priority be above 100, you probably want to create a BUILD_BUG type macro to enforce that.
Neil
Quoted 7 lines
lib/librte_eal/common/include/rte_common.h +0
-0* Force a function to be inlined */ #define __rte_always_inline inline __attribute__((always_inline))Signature · 1 line
2.11.0
Re: [PATCH v2 01/18] eal: introduce dtor macros
In reply to Gaetan RivetQuoted 26 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)lib/librte_eal/common/include/rte_common.h +13
-0@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)static void __attribute__((constructor (prio), used))func (void )/** +* Run after main() with high priority. +* +* The destructor will be run *before* prioritized destructors. +* +* @param func +* Destructor function name. + */ +#define RTE_FINI (func) \ +static void __attribute__((destructor, used)) func(void) + +/** +* Run after main() with low priority. +*
lib/librte_eal/common/include/rte_common.h static void __attribute__((constructor, used)) func(void) · line 130
Quoted 10 lines
lib/librte_eal/common/include/rte_common.h +10
-0+* @param func +* Destructor function name. +* @param prio +* Priority number must be above 100. +* Lowest number is the last to run. +*/ +#define RTE_FINI_PRIO (func, prio) \ +static void __attribute__((destructor(prio), used)) func(void) + +/**
Additionally, it might be nice to further abstract the destructor priority to fixed levels so that people aren't always trying to guess what the right magic number should be. I.e. create several destructor macros of the form:
RTE_FINI_<NAME>
Where name is a meaningfull term like FINAL, PMD, EARLY, or some such set that implies a priority value encoded within the macro definition. That would also eliminate the need to create a BUILD BUG macro if the priority was specified to be too low
Neil
Quoted 7 lines
lib/librte_eal/common/include/rte_common.h +0
-0* Force a function to be inlined */ #define __rte_always_inline inline __attribute__((always_inline))Signature · 1 line
2.11.0
Re: [PATCH v2 01/18] eal: introduce dtor macros
Quoted 42 lines · Neil Horman
Quoted 26 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)lib/librte_eal/common/include/rte_common.h +13
-0@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)static void __attribute__((constructor (prio), used))func (void )/** +* Run after main() with high priority. +* +* The destructor will be run *before* prioritized destructors. +* +* @param func +* Destructor function name. + */ +#define RTE_FINI (func) \ +static void __attribute__((destructor, used)) func(void) + +/** +* Run after main() with low priority. +* lib/librte_eal/common/include/rte_common.h static void __attribute__((constructor, used)) func(void) · line 130
Quoted 10 lines
lib/librte_eal/common/include/rte_common.h +10
-0+* @param func +* Destructor function name. +* @param prio +* Priority number must be above 100. +* Lowest number is the last to run. +*/ +#define RTE_FINI_PRIO (func, prio) \ +static void __attribute__((destructor(prio), used)) func(void) + +/** Additionally, it might be nice to further abstract the destructor priority to fixed levels so that people aren't always trying to guess what the right magic number should be. I.e. create several destructor macros of the form:
RTE_FINI_<NAME>
Quoted 7 lines
Where name is a meaningfull term like FINAL, PMD, EARLY, or some such set that implies a priority value encoded within the macro definition. That would also eliminate the need to create a BUILD BUG macro if the priority was specified to be too low
Neil
Good idea, and I agree that we need helpers on this. Not sure about _FINAL and _EARLY however.
I will propose a patch as a response to this mail, let me know if that's what you had in mind.
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH 1/1 eal: list acceptable init priorities
Build a central list to quickly see each used priorities for constructors, allowing to verify that they are both above 100 and in the proper order.
--- 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
@@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = { };/* Logging should be first initializer (before drivers and bus) */ -RTE_INIT_PRIO (rte_log_init,101 ); +RTE_INIT_PRIO (rte_log_init,LOG );static void rte_log_init (void ) {
lib/librte_eal/common/include/rte_bus.h +1 -1
@@ -326,7 +326,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);* The constructor has higher priority than PMD constructors. */ #define RTE_REGISTER_BUS (nm, bus) \ -RTE_INIT_PRIO(businitfn_ ##nm, 110); \ +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \ static void businitfn_ ##nm(void) \ {\ (bus).name = RTE_STR(nm);\
lib/librte_eal/common/include/rte_common.h +7 -1
@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;*/ #define RTE_SET_USED (x) (void)(x) +#define RTE_PRIORITY_LOG 101 +#define RTE_PRIORITY_BUS 110 + +#define RTE_PRIO (prio) \ + RTE_PRIORITY_ ## prio +/** * Run function before main() with low priority. *
@@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)* Lowest number is the first to run. */ #define RTE_INIT_PRIO (func, prio) \ -static void __attribute__((constructor(prio), used)) func(void) +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)/** * Run after main() with high priority.
Signature · 1 line
2.11.0
Re: [PATCH] eal: list acceptable init priorities
Quoted 68 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.
Cc Neil Horman <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>--- 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@@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = { };/* Logging should be first initializer (before drivers and bus) */ -RTE_INIT_PRIO (rte_log_init,101 ); +RTE_INIT_PRIO (rte_log_init,LOG );static void rte_log_init (void ) {lib/librte_eal/common/include/rte_bus.h +1
-1@@ -326,7 +326,7 @@ enum rte_iova_mode rte_bus_get_iommu_class(void);* The constructor has higher priority than PMD constructors. */ #define RTE_REGISTER_BUS (nm, bus) \ -RTE_INIT_PRIO(businitfn_ ##nm, 110); \ +RTE_INIT_PRIO(businitfn_ ##nm, BUS); \ static void businitfn_ ##nm(void) \ {\ (bus).name = RTE_STR(nm);\lib/librte_eal/common/include/rte_common.h +7
-1@@ -81,6 +81,12 @@ typedef uint16_t unaligned_uint16_t;*/ #define RTE_SET_USED (x) (void)(x) +#define RTE_PRIORITY_LOG 101 +#define RTE_PRIORITY_BUS 110 + +#define RTE_PRIO (prio) \ + RTE_PRIORITY_ ## prio +/** * Run function before main() with low priority. * @@ -102,7 +108,7 @@ static void __attribute__((constructor, used)) func(void)* Lowest number is the first to run. */ #define RTE_INIT_PRIO (func, prio) \ -static void __attribute__((constructor(prio), used)) func(void) +static void __attribute__((constructor(RTE_PRIO(prio)), used)) func(void)/** * Run after main() with high priority. Signature · 1 line
2.11.0
This seems like a good start, something that we can expand if we need more priorities later
Re: [PATCH v2 01/18] eal: introduce dtor macros
In reply to Gaëtan RivetQuoted 48 lines · Gaëtan Rivet
Quoted 47 lines · Neil Horman
Quoted 26 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/librte_eal/common/include/rte_common.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+)lib/librte_eal/common/include/rte_common.h +13
-0@@ -105,6 +105,29 @@ static void __attribute__((constructor, used)) func(void)static void __attribute__((constructor (prio), used))func (void )/** +* Run after main() with high priority. +* +* The destructor will be run *before* prioritized destructors. +* +* @param func +* Destructor function name. + */ +#define RTE_FINI (func) \ +static void __attribute__((destructor, used)) func(void) + +/** +* Run after main() with low priority. +* lib/librte_eal/common/include/rte_common.h static void __attribute__((constructor, used)) func(void) · line 130
Quoted 10 lines
lib/librte_eal/common/include/rte_common.h +10
-0+* @param func +* Destructor function name. +* @param prio +* Priority number must be above 100. +* Lowest number is the last to run. +*/ +#define RTE_FINI_PRIO (func, prio) \ +static void __attribute__((destructor(prio), used)) func(void) + +/** Additionally, it might be nice to further abstract the destructor priority to fixed levels so that people aren't always trying to guess what the right magic number should be. I.e. create several destructor macros of the form:
RTE_FINI_<NAME>Where name is a meaningfull term like FINAL, PMD, EARLY, or some such set that implies a priority value encoded within the macro definition. That would also eliminate the need to create a BUILD BUG macro if the priority was specified to be too low
Quoted 6 lines
Quoted 2 lines
Neil
Good idea, and I agree that we need helpers on this. Not sure about
_FINALand_EARLYhowever.
Yeah, I don't like those either, but I couldn't think of any other priority suffixes off the top of my head
FWIW, the kernel creates these macros to register initcalls:
#define pure_initcall(fn) __define_initcall(fn, 0) #define core_initcall(fn) __define_initcall(fn, 1) #define core_initcall_sync(fn) __define_initcall(fn, 1s) #define postcore_initcall(fn) __define_initcall(fn, 2) #define postcore_initcall_sync(fn) __define_initcall(fn, 2s) #define arch_initcall(fn) __define_initcall(fn, 3) #define arch_initcall_sync(fn) __define_initcall(fn, 3s) #define subsys_initcall(fn) __define_initcall(fn, 4) #define subsys_initcall_sync(fn) __define_initcall(fn, 4s) #define fs_initcall(fn) __define_initcall(fn, 5) #define fs_initcall_sync(fn) __define_initcall(fn, 5s) #define rootfs_initcall(fn) __define_initcall(fn, rootfs) #define device_initcall(fn) __define_initcall(fn, 6) #define device_initcall_sync(fn) __define_initcall(fn, 6s) #define late_initcall(fn) __define_initcall(fn, 7) #define late_initcall_sync(fn) __define_initcall(fn, 7s)
Its not an exact match, but you could probably borrow from that somewhat.
Quoted 2 lines
I will propose a patch as a response to this mail, let me know if that's what you had in mind.
That was my hope yes, thanks!
Neil
Quoted 5 lines
Signature · 3 lines
-- Gaëtan Rivet 6WIND
PATCH v2 2/18 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/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 2 + 6 files changed, 188 insertions(+), 1 deletion(-) create mode 100644 lib/librte_eal/common/eal_common_class.c create mode 100644 lib/librte_eal/common/include/rte_class.h
lib/librte_eal/bsdapp/eal/Makefile +1 -0
@@ -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
@@ -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/linuxapp/eal/Makefile +1 -0
@@ -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
@@ -215,6 +215,8 @@ EXPERIMENTAL { global: rte_eal_cleanup; + rte_class_register; + rte_class_unregister; rte_eal_devargs_insert; rte_eal_devargs_parse; rte_eal_devargs_remove;
Signature · 1 line
2.11.0
PATCH v2 3/18 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
@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \ {\ (cls).name =RTE_STR (nm);\rte_class_register (&cls); \ +} \ +RTE_FINI_PRIO(classfinifn_ ##nm, 120); \ +static void classfinifn_ ##nm(void) \ +{ \ + rte_class_unregister(&cls); \ }#ifdef __cplusplus
Signature · 1 line
2.11.0
PATCH v2 4/18 eal: add lightweight kvarg parsing utility
In reply to Gaetan RivetThis library offers a quick way to parse parameters passed with a key=value syntax.
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete librte_kvargs.
--- lib/librte_eal/common/eal_common_dev.c | 38 ++++++++++++++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 34 ++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+)
lib/librte_eal/common/eal_common_dev.c +38 -0
@@ -13,10 +13,48 @@#include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> #include <rte_log.h> #include "eal_private.h" +/* EAL-private function. */ +int +rte_parse_kv (const char *str,struct rte_kvarg *kv) +{ +const char *equal; +const char *end; + +if (str ==NULL || str[0 ] =='\0' ) +return 1 ; + equal =strchr (str,'=' ); +if (equal ==NULL ) { + rte_errno =EINVAL ; +return -1 ; + } + end =strchr (equal +1 ,',' ); + end = end ? end :strchr (equal +1 ,'/' ); + end = end ? end :strchr (equal +1 ,'\0' ); +if (end ==NULL ) { + rte_errno =ENODEV ; +return -1 ; + } +if (kv ==NULL ) +return 0 ; +snprintf (kv->data,sizeof (kv->data),"%s" , str); + kv->key = &kv->data[0 ]; +strchr (kv->data, end[0 ])[0 ] ='\0' ; +if (strchr (kv->data,'=' )) { + kv->value =strchr (kv->data,'=' ) +1 ; +strchr (kv->data,'=' )[0 ] ='\0' ; + } +if (end[0 ] =='\0' ) + kv->next =NULL ; +else + kv->next = end +1 ; +return 0 ; +} +static int cmp_detached_dev_name (const struct rte_device *dev,const void *_name) {
lib/librte_eal/common/eal_private.h +34 -0
@@ -205,4 +205,38 @@ struct rte_bus *rte_bus_find_by_device_name(const char *str);int rte_mp_channel_init (void ); +/* +* Lightweight kvarg parsing library. +*/ + +#define RTE_MAX_KVARG_LEN 64 + +/** +* Kvarg representation. +*/ +struct rte_kvarg { +char *key;/**< points the key in the data. */ +char *value;/**< points the value in the data. */ +const char *next;/**< next token to parse, if any. */ +char data[RTE_MAX_KVARG_LEN +1 ];/**< local copy of key and value. */ +}; + +/** +* Parse one kvarg. +* +* The key-value pair must be shorter than the rte_kvarg data size. +* +* @param[in] str +* text to parse. +* +* @param[out] kv +* kvarg structure to fill. +* +* @return +* 0 if parsing succeeded. +* >0 if there was nothing to parse. +* <0 on error, rte_errno is set. +*/ +int rte_parse_kv (const char *str,struct rte_kvarg *kv); +#endif /* _EAL_PRIVATE_H_ */
Signature · 1 line
2.11.0
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
Quoted 7 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
Quoted 6 lines
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.
What is the big advantage with this code and the librte_kvargs code. Is it just no allocation, rte_kvargs needs to be build before parts of EAL or what?
My concern is we have now two flavors one in EAL and one in librte_kvargs, would it not be more reasonable to improve rte_kvargs to remove your objections? I am all for fast, better, stronger code :-)
Quoted 2 lines
Signed-off-by Gaetan Rivet <[email protected]>
Regards,
Keith
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
Hello Keith,
Quoted 7 lines · Keith
Quoted 7 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
Quoted 9 lines
Quoted 6 lines
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?
Pretty much, yes. I needed something lean and simple.
Quoted 2 lines
My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)
I hear you. I decided this was worth the trade-off.
librte_kvargs does the iteration on a kvlist in one-line.
It processes the input text and mangle as needed to be able to do so. Drivers using it will be able to declare first a set of acceptable keys, meaning that it is complementary to having a usage-help and more stringent input validation.
rte_kvargs does none of it. This means that each user would have to re-implement checks by hand, and reviewers would need to enforce that they are done, etc.
So, IMO, different use-cases. In this context, I think making the effort of moving around librte_kvargs within the EAL, tweaking its use for my needs, does not make much sense. It would complicate its implementation only for one less private function.
If people do not like using librte_kvargs, it could maybe evolve, be rewritten, then all drivers would need to follow suit, etc. But I haven't seen the need personally.
Regards,
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
In reply to Wiles, KeithQuoted 11 lines · Keith
Quoted 11 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
Quoted 7 lines
Quoted 2 lines
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)
+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in rte_kvargs_parse to an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time. librte_kvargs isn't necessecarily the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.
Neil
Quoted 7 lines
Quoted 2 lines
Signed-off-by Gaetan Rivet <[email protected]>Regards,
Keith
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
Quoted 17 lines · Neil Horman
Quoted 16 lines · Keith
Quoted 7 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
Quoted 6 lines
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?
Quoted 7 lines
Quoted 2 lines
My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parseto an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time.
I think the existing allocation scheme is fine for other usages (in drivers and so on). Not for what I wanted to do.
Quoted 4 lines
librte_kvargsisn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.
It serves a different purpose than the one I'm pursuing.
This helper is lightweight and private. If I wanted to integrate my needs with librte_kvargs, I would be adding new functionalities, making it more complex, and for a use-case that is useless for the vast majority of users of the lib.
If that's really an issue, I'm better off simply removing rte_parse_kv and writing the parsing by hand within my function. This would be ugly and tedious, but less than moving librte_kvargs within EAL and changing it to my needs.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
Quoted 20 lines · Gaëtan Rivet
Quoted 19 lines · Neil Horman
Quoted 18 lines · Keith
Quoted 7 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
Quoted 6 lines
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)
Quoted 9 lines
Quoted 5 lines
+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parseto an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time.I think the existing allocation scheme is fine for other usages (in drivers and so on). Not for what I wanted to do.
Ok, but thats an adressable issue. you can bifurcate the parse function to an internal function that accepts any preallocated kvargs struct, and export two wrapper functions, one which allocates the struct from the heap, another which allocated automatically on the stack.
Quoted 5 lines
Quoted 4 lines
librte_kvargsisn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.
Quoted 7 lines
It serves a different purpose than the one I'm pursuing.
This helper is lightweight and private. If I wanted to integrate my needs with
librte_kvargs, I would be adding new functionalities, making it more complex, and for a use-case that is useless for the vast majority of users of the lib.
Ok, to that end:
1) Privacy is not an issue (at least from my understanding of what your doing). If we start with the assumption that librte_kvargs is capable of satisfying your needs (even if its not done in an optimal way), the fact that your version of the function is internal to the library doesn't seem overly relevant, unless theres something critical to that privacy that I'm missing.
2) Lightweight function seems like something that can be integrated with librte_kvargs. Looking at it, what may I ask in librte_kvargs is insufficiently non-performant for your needs, specifically? We talked about the heap allocation above, is there something else? The string duplication perhaps?
Quoted 4 lines
If that's really an issue, I'm better off simply removing
rte_parse_kvand writing the parsing by hand within my function. This would be ugly and tedious, but less than movinglibrte_kvargswithin EAL and changing it to my needs.
I don't think thats necessecary, I just think if you can ennumerate the items that are non-performant for your needs we can make some changes to librte_kvargs to optimize around them, or offer parsing options to avoid them, and in the process avoid some code duplication
Neil
Quoted 5 lines
Signature · 3 lines
-- Gaëtan Rivet 6WIND
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
Quoted 27 lines · Neil Horman
Quoted 26 lines · Gaëtan Rivet
Quoted 24 lines · Neil Horman
Quoted 11 lines · Keith
Quoted 11 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
Quoted 7 lines
Quoted 2 lines
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parseto an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time.
Quoted 8 lines
Quoted 3 lines
I think the existing allocation scheme is fine for other usages (in drivers and so on). Not for what I wanted to do.
Ok, but thats an adressable issue. you can bifurcate the parse function to an internal function that accepts any preallocated kvargs struct, and export two wrapper functions, one which allocates the struct from the heap, another which allocated automatically on the stack.
Sure, everything is possible.
Quoted 12 lines
Quoted 5 lines
Quoted 4 lines
librte_kvargsisn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.Quoted 7 lines
It serves a different purpose than the one I'm pursuing.
This helper is lightweight and private. If I wanted to integrate my needs with
librte_kvargs, I would be adding new functionalities, making it more complex, and for a use-case that is useless for the vast majority of users of the lib.
Quoted 8 lines
Ok, to that end:
1) Privacy is not an issue (at least from my understanding of what your doing). If we start with the assumption that
librte_kvargsis capable of satisfying your needs (even if its not done in an optimal way), the fact that your version of the function is internal to the library doesn't seem overly relevant, unless theres something critical to that privacy that I'm missing.
Privacy is only a point I brought up to say that the impact of this function is minimal. People looking to parse their kvargs should not have any ambiguity regarding how they should do so. Only librte_kvargs is available.
Quoted 6 lines
2) Lightweight function seems like something that can be integrated with
librte_kvargs. Looking at it, what may I ask inlibrte_kvargsis insufficiently non-performant for your needs, specifically? We talked about the heap allocation above, is there something else? The string duplication perhaps?
Mostly the way to use it.
The filter strings are
bus=value,.../class=value,...
where either bus= list or class= list can be omitted, but at least one must appear.
I want to read a single kvarg. I do not want to parse the whole string. the '/' signifies the end of the current layer.
librte_kvargs does not care about those points. I cannot ask it to only read either bus or class, as it would then throw an error for all the other keys (which the EAL has necessarily no knowledge of).
So I would need to:
* Add a custom storage scheme
* Add a custom parsing mode stopping at the first kvarg
* Add an edge-case to ignore the '/', so as not to throw off the rest of the parsing (least it be considered part of the previous kvarg value field).
Seeing this, does adding those really specifics functionality help librte_kvargs to be more useful and usable? I do not think so.
It would only serve to disrupt the library for a marginal use-case, with the introduction of edge-cases that will blur the specs of the lib's API, making it harder to avoid subtle bugs.
Only way to do so sanely would be to add rte_parse_kv as part of librte_kvargs, as is. But then the whole thing does not make sense IMO:
no one would care to use it, the maintainance effort is the same, the likelyhood of bugs as well (but in the process we would disrupt the distribution of librte_kvargs by moving it within the EAL).
I see no benefit to either solution.
Quoted 9 lines
Quoted 4 lines
If that's really an issue, I'm better off simply removing
rte_parse_kvand writing the parsing by hand within my function. This would be ugly and tedious, but less than movinglibrte_kvargswithin EAL and changing it to my needs.I don't think thats necessecary, I just think if you can ennumerate the items that are non-performant for your needs we can make some changes to
librte_kvargsto optimize around them, or offer parsing options to avoid them, and in the process avoid some code duplication
I think it makes sense to have specialized functions for specialized use-cases, and forcing the code to be generic and work with all of them will make it more complicated.
The genericity would only be worth it if people actually needed to parse the device strings the same way I do. No one has any business doing so. This genericity adds complexity and issues, without even being useful in the first place.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
Quoted 31 lines · Gaëtan Rivet
Quoted 30 lines · Neil Horman
Quoted 29 lines · Gaëtan Rivet
Quoted 17 lines · Neil Horman
Quoted 16 lines · Keith
Quoted 7 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
Quoted 6 lines
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?Quoted 7 lines
Quoted 2 lines
My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parseto an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time.I think the existing allocation scheme is fine for other usages (in drivers and so on). Not for what I wanted to do.
Quoted 8 lines
Quoted 5 lines
Ok, but thats an adressable issue. you can bifurcate the parse function to an internal function that accepts any preallocated kvargs struct, and export two wrapper functions, one which allocates the struct from the heap, another which allocated automatically on the stack.
Sure, everything is possible.
Ok.
Quoted 21 lines
Quoted 12 lines
Quoted 5 lines
Quoted 4 lines
librte_kvargsisn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.Quoted 7 lines
It serves a different purpose than the one I'm pursuing.
This helper is lightweight and private. If I wanted to integrate my needs with
librte_kvargs, I would be adding new functionalities, making it more complex, and for a use-case that is useless for the vast majority of users of the lib.Quoted 8 lines
Ok, to that end:
1) Privacy is not an issue (at least from my understanding of what your doing). If we start with the assumption that
librte_kvargsis capable of satisfying your needs (even if its not done in an optimal way), the fact that your version of the function is internal to the library doesn't seem overly relevant, unless theres something critical to that privacy that I'm missing.
Quoted 5 lines
Privacy is only a point I brought up to say that the impact of this function is minimal. People looking to parse their kvargs should not have any ambiguity regarding how they should do so. Only
librte_kvargsis available.
Ok, would you also council others developing dpdk apps to write their own parsing routines when what they needed was trivial for the existing library? You are people too :)
Quoted 7 lines
Quoted 6 lines
2) Lightweight function seems like something that can be integrated with
librte_kvargs. Looking at it, what may I ask inlibrte_kvargsis insufficiently non-performant for your needs, specifically? We talked about the heap allocation above, is there something else? The string duplication perhaps?
Quoted 7 lines
Mostly the way to use it.
The filter strings are
bus=value,.../class=value,...where either bus= list or class= list can be omitted, but at least one must appear.
Ok, so whats the problem with using librte_kvargs for that? Is it that the list that acts as the value to the key isn't parsed out into its own set of tokens? That seems entirely addressable.
Quoted 3 lines
I want to read a single kvarg. I do not want to parse the whole string. the '/' signifies the end of the current layer.
This makes it seem like librte_kvargs can handle this as a trivial case of its functionality.
Quoted 4 lines
librte_kvargsdoes not care about those points. I cannot ask it to only read either bus or class, as it would then throw an error for all the other keys (which the EAL has necessarily no knowledge of).
But you can ask it to read both, and within your libraries logic make the determination as to the validitiy of receiving both. Alternatively you can modify the valid_keys check in kvargs to be a regex that matches on either bus or class, or accept an ignore parameter for keys that may appear but should be ignored in the light of other keys. Theres lots of options here.
Quoted 11 lines
So I would need to:
* Add a custom storage scheme
* Add a custom parsing mode stopping at the first kvarg
* Add an edge-case to ignore the '/', so as not to throw off the rest of the parsing (least it be considered part of the previous kvarg value field).Seeing this, does adding those really specifics functionality help
librte_kvargsto be more useful and usable? I do not think so.
I think you're overcomplicating this.
How about enhancing librte_kvargs to make parsing configurable such that invalid keys get ignored rather than generate errors?
Quoted 4 lines
It would only serve to disrupt the library for a marginal use-case, with the introduction of edge-cases that will blur the specs of the lib's API, making it harder to avoid subtle bugs.
What do you mean "disrupt the library"? What is its purpose of a library if not to do the jobs we want it to? If everyone created their own routine to do something that a library could do with some modifications, we'd be left with 1000 versions of the same routine. If the existing library does 99% of what you want it to, lets ennumerate what the missing %1 is and make the change, not throw the baby out with the bathwater.
Quoted 8 lines
Only way to do so sanely would be to add
rte_parse_kvas part oflibrte_kvargs, as is. But then the whole thing does not make sense IMO:
no one would care to use it, the maintainance effort is the same, the likelyhood of bugs as well (but in the process we would disrupt the distribution oflibrte_kvargsby moving it within the EAL).I see no benefit to either solution.
Again, thats an overcomplication. As I read it, you have a need to interrogate a key/value string, whos contents may contain invalid keys (for your parsing purposes), and whos values may themselves be lists, correct? If so, I don't see the problem in enhancing libkvargs to:
1) Allow for the parsing routine to ignore invalid keys (or even ignore specific invalid keys, and trigger on any unknown keys)
2) Allows for the subparsing of lists into their own set of tokens.
Quoted 10 lines
Quoted 9 lines
Quoted 4 lines
If that's really an issue, I'm better off simply removing
rte_parse_kvand writing the parsing by hand within my function. This would be ugly and tedious, but less than movinglibrte_kvargswithin EAL and changing it to my needs.I don't think thats necessecary, I just think if you can ennumerate the items that are non-performant for your needs we can make some changes to
librte_kvargsto optimize around them, or offer parsing options to avoid them, and in the process avoid some code duplication
Quoted 4 lines
I think it makes sense to have specialized functions for specialized use-cases, and forcing the code to be generic and work with all of them will make it more complicated.
This isn't specialized, its trivial. Its just a trivial case that libkvargs isn't built to handle at the moment. Lets get it there.
Quoted 5 lines
The genericity would only be worth it if people actually needed to parse the device strings the same way I do. No one has any business doing so. This genericity adds complexity and issues, without even being useful in the first place.
I really think you're trying to take a short cut here where none is needed, and I'm sorry, but I can't support that.
Neil
Quoted 4 lines
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
Quoted 100 lines · Neil Horman
Quoted 31 lines · Gaëtan Rivet
Quoted 30 lines · Neil Horman
Quoted 29 lines · Gaëtan Rivet
Quoted 17 lines · Neil Horman
Quoted 16 lines · Keith
Quoted 7 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
Quoted 6 lines
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?Quoted 7 lines
Quoted 2 lines
My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parseto an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time.I think the existing allocation scheme is fine for other usages (in drivers and so on). Not for what I wanted to do.
Quoted 8 lines
Quoted 5 lines
Ok, but thats an adressable issue. you can bifurcate the parse function to an internal function that accepts any preallocated kvargs struct, and export two wrapper functions, one which allocates the struct from the heap, another which allocated automatically on the stack.
Sure, everything is possible.
Ok.
Quoted 21 lines
Quoted 12 lines
Quoted 5 lines
Quoted 4 lines
librte_kvargsisn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.Quoted 7 lines
It serves a different purpose than the one I'm pursuing.
This helper is lightweight and private. If I wanted to integrate my needs with
librte_kvargs, I would be adding new functionalities, making it more complex, and for a use-case that is useless for the vast majority of users of the lib.Quoted 8 lines
Ok, to that end:
1) Privacy is not an issue (at least from my understanding of what your doing). If we start with the assumption that
librte_kvargsis capable of satisfying your needs (even if its not done in an optimal way), the fact that your version of the function is internal to the library doesn't seem overly relevant, unless theres something critical to that privacy that I'm missing.Quoted 5 lines
Privacy is only a point I brought up to say that the impact of this function is minimal. People looking to parse their kvargs should not have any ambiguity regarding how they should do so. Only
librte_kvargsis available.Ok, would you also council others developing dpdk apps to write their own parsing routines when what they needed was trivial for the existing library? You are people too :)
Quoted 7 lines
Quoted 6 lines
2) Lightweight function seems like something that can be integrated with
librte_kvargs. Looking at it, what may I ask inlibrte_kvargsis insufficiently non-performant for your needs, specifically? We talked about the heap allocation above, is there something else? The string duplication perhaps?Quoted 7 lines
Mostly the way to use it.
The filter strings are
bus=value,.../class=value,...where either bus= list or class= list can be omitted, but at least one must appear.
Ok, so whats the problem with using
librte_kvargsfor that? Is it that the list that acts as the value to the key isn't parsed out into its own set of tokens? That seems entirely addressable.Quoted 3 lines
I want to read a single kvarg. I do not want to parse the whole string. the '/' signifies the end of the current layer.
This makes it seem like
librte_kvargscan handle this as a trivial case of its functionality.Quoted 4 lines
librte_kvargsdoes not care about those points. I cannot ask it to only read either bus or class, as it would then throw an error for all the other keys (which the EAL has necessarily no knowledge of).
Quoted 6 lines
But you can ask it to read both, and within your libraries logic make the determination as to the validitiy of receiving both. Alternatively you can modify the
valid_keyscheck in kvargs to be a regex that matches on either bus or class, or accept an ignore parameter for keys that may appear but should be ignored in the light of other keys. Theres lots of options here.
No, I will not be adding regex parsing to express a set of acceptable token :)
Quoted 8 lines
Quoted 8 lines
So I would need to:
* Add a custom storage scheme
* Add a custom parsing mode stopping at the first kvarg
* Add an edge-case to ignore the '/', so as not to throw off the rest of the parsing (least it be considered part of the previous kvarg value field).
Quoted 7 lines
Quoted 3 lines
Seeing this, does adding those really specifics functionality help
librte_kvargsto be more useful and usable? I do not think so.I think you're overcomplicating this.
How about enhancinglibrte_kvargsto make parsing configurable such that invalid keys get ignored rather than generate errors?
Invalid keys can already be ignored, it's not an issue.
Quoted 24 lines
Quoted 4 lines
It would only serve to disrupt the library for a marginal use-case, with the introduction of edge-cases that will blur the specs of the lib's API, making it harder to avoid subtle bugs.
What do you mean "disrupt the library"? What is its purpose of a library if not to do the jobs we want it to? If everyone created their own routine to do something that a library could do with some modifications, we'd be left with 1000 versions of the same routine. If the existing library does 99% of what you want it to, lets ennumerate what the missing %1 is and make the change, not throw the baby out with the bathwater.
Quoted 8 lines
Only way to do so sanely would be to add
rte_parse_kvas part oflibrte_kvargs, as is. But then the whole thing does not make sense IMO:
no one would care to use it, the maintainance effort is the same, the likelyhood of bugs as well (but in the process we would disrupt the distribution oflibrte_kvargsby moving it within the EAL).I see no benefit to either solution.
Again, thats an overcomplication. As I read it, you have a need to interrogate a key/value string, whos contents may contain invalid keys (for your parsing purposes), and whos values may themselves be lists, correct? If so, I don't see the problem in enhancing libkvargs to:
Quoted 5 lines
1) Allow for the parsing routine to ignore invalid keys (or even ignore specific invalid keys, and trigger on any unknown keys)
2) Allows for the subparsing of lists into their own set of tokens.
What I would do if I wanted to use librte_kvargs, would be to duplicate the input text, mangle it to respect the intended format, and feed it to librte_kvargs for parsing. Then I would iterate over the pairs, and stop on the two I'm concerned about.
What I dislike here:
* I actually do the bulk of the parsing by hand (recognizing first a valid input, modifying it to respect the lib, and after iterating on the list of pairs and strcmp-ing the ones I want). This is approximately as complicated as the current helper function.
* I have to move librte_kvargs in the EAL.
Quoted 10 lines
Quoted 10 lines
Quoted 9 lines
Quoted 4 lines
If that's really an issue, I'm better off simply removing
rte_parse_kvand writing the parsing by hand within my function. This would be ugly and tedious, but less than movinglibrte_kvargswithin EAL and changing it to my needs.I don't think thats necessecary, I just think if you can ennumerate the items that are non-performant for your needs we can make some changes to
librte_kvargsto optimize around them, or offer parsing options to avoid them, and in the process avoid some code duplication
Quoted 7 lines
Quoted 4 lines
I think it makes sense to have specialized functions for specialized use-cases, and forcing the code to be generic and work with all of them will make it more complicated.
This isn't specialized, its trivial. Its just a trivial case that libkvargs isn't built to handle at the moment. Lets get it there.
My use-case is trivial. Putting it within the librte_kvargs makes it more complicated to write. I hate this.
Quoted 7 lines
Quoted 5 lines
The genericity would only be worth it if people actually needed to parse the device strings the same way I do. No one has any business doing so. This genericity adds complexity and issues, without even being useful in the first place.
I really think you're trying to take a short cut here where none is needed, and I'm sorry, but I can't support that.
There are countably infinite solutions, we will probably reach one (and it might even do what we want).
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH 1/2 kvargs: the life of the party
---
This is a rough sketch of what would be done to move rte_kvargs within the EAL and change the parsing in rte_dev to use it.
drivers/baseband/Makefile | 2 +-
lib/Makefile | 5 +-
lib/librte_eal/Makefile | 2 +
lib/librte_eal/common/Makefile | 2 +-
lib/librte_eal/kvargs/Makefile | 23 ++++++++++
.../kvargs}/meson.build | 0
.../kvargs}/rte_kvargs.c | 12 +++--
.../kvargs}/rte_kvargs.h | 0
.../kvargs}/rte_kvargs_version.map | 0
.../{common/include => kvargs}/rte_string_fns.h | 0
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c | 2 +-
lib/librte_kvargs/Makefile | 53 ----------------------
12 files changed, 37 insertions(+), 64 deletions(-)
create mode 100644 lib/librte_eal/kvargs/Makefile
rename lib/{librte_kvargs => librte_eal/kvargs}/meson.build (100%)
rename lib/{librte_kvargs => librte_eal/kvargs}/rte_kvargs.c (96%)
rename lib/{librte_kvargs => librte_eal/kvargs}/rte_kvargs.h (100%)
rename lib/{librte_kvargs => librte_eal/kvargs}/rte_kvargs_version.map (100%)
rename lib/librte_eal/{common/include => kvargs}/rte_string_fns.h (100%)
delete mode 100644 lib/librte_kvargs/Makefiledrivers/baseband/Makefile +1 -1
@@ -4,7 +4,7 @@ include $(RTE_SDK)/mk/rte.vars.mk core-libs := librte_eal librte_mbuf librte_mempool librte_ring -core-libs += librte_bbdev librte_kvargs librte_cfgfile +core-libs += librte_bbdev librte_cfgfile DIRS-$(CONFIG_RTE_LIBRTE_PMD_BBDEV_NULL) += null DEPDIRS-null = $(core-libs)
lib/Makefile +1 -4
@@ -20,12 +20,11 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline DEPDIRS-librte_cmdline := librte_eal DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring -DEPDIRS-librte_ether += librte_mbuf librte_kvargs +DEPDIRS-librte_ether += librte_mbuf DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev DEPDIRS-librte_cryptodev := librte_eal librte_mempool librte_ring librte_mbuf -DEPDIRS-librte_cryptodev += librte_kvargs DIRS-$(CONFIG_RTE_LIBRTE_SECURITY) += librte_security DEPDIRS-librte_security := librte_eal librte_mempool librte_ring librte_mbuf DEPDIRS-librte_security += librte_ether
@@ -71,8 +70,6 @@ DEPDIRS-librte_flow_classify := librte_net librte_table librte_acl DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += librte_sched DEPDIRS-librte_sched := librte_eal librte_mempool librte_mbuf librte_net DEPDIRS-librte_sched += librte_timer -DIRS-$(CONFIG_RTE_LIBRTE_KVARGS) += librte_kvargs -DEPDIRS-librte_kvargs := librte_eal DIRS-$(CONFIG_RTE_LIBRTE_DISTRIBUTOR) += librte_distributor DEPDIRS-librte_distributor := librte_eal librte_mbuf librte_ether DIRS-$(CONFIG_RTE_LIBRTE_PORT) += librte_port
lib/librte_eal/Makefile +2 -0
@@ -3,7 +3,9 @@ include $(RTE_SDK)/mk/rte.vars.mk +DIRS-y += kvargs DIRS-y += common +DEPDIRS-common := kvargs DIRS-$(CONFIG_RTE_EXEC_ENV_LINUXAPP) += linuxapp DEPDIRS-linuxapp := common DIRS-$(CONFIG_RTE_EXEC_ENV_BSDAPP) += bsdapp
lib/librte_eal/common/Makefile +1 -1
@@ -9,7 +9,7 @@ INC += rte_errno.h rte_launch.h rte_lcore.h INC += rte_log.h rte_memory.h rte_memzone.h INC += rte_per_lcore.h rte_random.h INC += rte_tailq.h rte_interrupts.h rte_alarm.h -INC += rte_string_fns.h rte_version.h +INC += rte_version.h INC += rte_eal_memconfig.h rte_malloc_heap.h INC += rte_hexdump.h rte_devargs.h rte_bus.h rte_dev.h rte_class.h INC += rte_pci_dev_feature_defs.h rte_pci_dev_features.h
lib/librte_eal/kvargs/Makefile new file +23 -0
@@ -0,0 +1,23 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright(c) 2014 6WIND S.A. + +include $(RTE_SDK)/mk/rte.vars.mk + +# library name +LIB = librte_kvargs.a + +CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 + +EXPORT_MAP := rte_kvargs_version.map + +LIBABIVER := 1 + +# all source are stored in SRCS-y +SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c + +# install includes +INCS := rte_kvargs.h +INCS += rte_string_fns.h +SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS) + +include $(RTE_SDK)/mk/rte.lib.mk
lib/librte_eal/kvargs/meson.build renamed from lib/librte_kvargs/meson.build +0 -0
lib/librte_eal/kvargs/rte_kvargs.c renamed from lib/librte_kvargs/rte_kvargs.c +8 -4
@@ -3,13 +3,17 @@* Copyright(c) 2014 6WIND S.A. */ -#include <string.h> +#include <stdio.h> #include <stdlib.h> - -#include <rte_log.h> -#include <rte_string_fns.h> +#include <string.h> #include "rte_kvargs.h" +#include "rte_string_fns.h" + +#define ERR stderr +#define PMD "[PMD]" +#define RTE_LOG (lvl, prefix, ...) \ + fprintf(lvl, prefix " " __VA_ARGS__);/* * Receive a string with a list of arguments following the pattern
lib/librte_eal/kvargs/rte_kvargs.h renamed from lib/librte_kvargs/rte_kvargs.h +0 -0
lib/librte_eal/kvargs/rte_kvargs_version.map renamed from lib/librte_kvargs/rte_kvargs_version.map +0 -0
lib/librte_eal/kvargs/rte_string_fns.h renamed from lib/librte_eal/common/include/rte_string_fns.h +0 -0
lib/librte_eal/linuxapp/eal/eal_hugepage_info.c +1 -1
@@ -24,7 +24,7 @@#include <rte_debug.h> #include <rte_log.h> #include <rte_common.h> -#include "rte_string_fns.h" +#include <rte_string_fns.h> #include "eal_internal_cfg.h" #include "eal_hugepages.h" #include "eal_filesystem.h"
lib/librte_kvargs/Makefile deleted +0 -53
53 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH 2/2 dev: use rte_kvargs
---
I find using rte_parse_kv cleaner.
The function rte_dev_iterator_init is already ugly enough as it is. This is really not helping.
lib/librte_eal/common/eal_common_dev.c | 127 +++++++++++++++++++++------------ lib/librte_eal/linuxapp/eal/Makefile | 1 + 2 files changed, 83 insertions(+), 45 deletions(-)
lib/librte_eal/common/eal_common_dev.c +82 -45
@@ -15,6 +15,7 @@#include <rte_devargs.h> #include <rte_debug.h> #include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h"
@@ -270,12 +271,15 @@ rte_eal_hotplug_remove(const char *busname, const char *devname) } int __rte_experimental -rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str) +rte_dev_iterator_init (struct rte_dev_iterator *it, +const char *devstr) { -struct rte_bus *bus =NULL ; +struct rte_kvargs *kvlist =NULL ;struct rte_class *cls =NULL ; -struct rte_kvarg kv; -char *slash; +struct rte_bus *bus =NULL ; +struct rte_kvargs_pair *kv; +char *slash =NULL ; +char *str =NULL ;/* Having both busstr and clsstr NULL is illegal, * marking this iterator as invalid unless
@@ -283,98 +287,131 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)*/ it->busstr =NULL ; it->clsstr =NULL ; + str =strdup (devstr); +if (str ==NULL ) { + rte_errno =ENOMEM ; + goto get_out; + } + slash =strchr (str,'/' ); +if (slash !=NULL ) { + slash[0 ] ='\0' ; + slash =strchr (devstr,'/' ) +1 ; + }/* Safety checks and prep-work */ -if (rte_parse_kv (str, &kv)) { + kvlist =rte_kvargs_parse (str,NULL ); +if (kvlist ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not parse: %s\n" , str); rte_errno =EINVAL ; -return -rte_errno; + goto get_out; } it->device =NULL ; it->class_device =NULL ; -if (strcmp (kv.key,"bus" ) ==0 ) { - bus =rte_bus_find_by_name (kv.value); + kv = &kvlist->pairs[0 ]; +if (strcmp (kv->key,"bus" ) ==0 ) { + bus =rte_bus_find_by_name (kv->value);if (bus ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not find bus \"%s\"\n" , - kv.value); + kv->value); rte_errno =EFAULT ; -return -rte_errno; + goto get_out; } - slash =strchr (str,'/' );if (slash !=NULL ) { -if (rte_parse_kv (slash +1 , &kv)) { +rte_kvargs_free (kvlist); + kvlist =rte_kvargs_parse (slash,NULL ); +if (kvlist ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not parse: %s\n" , - slash +1 ); + slash); rte_errno =EINVAL ; -return -rte_errno; + goto get_out; } - cls =rte_class_find_by_name (kv.value); + kv = &kvlist->pairs[0 ]; +if (strcmp (kv->key,"class" )) { +RTE_LOG (ERR ,EAL ,"Additional layer must be a class\n" ); + rte_errno =EINVAL ; + goto get_out; + } + cls =rte_class_find_by_name (kv->value);if (cls ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not find class \"%s\"\n" , - kv.value); + kv->value); rte_errno =EFAULT ; -return -rte_errno; + goto get_out; } } - }else if (strcmp (kv.key,"class" ) ==0 ) { - cls =rte_class_find_by_name (kv.value); + }else if (strcmp (kv->key,"class" ) ==0 ) { + cls =rte_class_find_by_name (kv->value);if (cls ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not find class \"%s\"\n" , - kv.value); + kv->value); rte_errno =EFAULT ; -return -rte_errno; + goto get_out; } }else { rte_errno =EINVAL ; -return -rte_errno; + goto get_out; }/* The string should have at least * one layer specified. */ if (bus ==NULL && cls ==NULL ) { rte_errno =EINVAL ; -return -rte_errno; + goto get_out; }if ((bus !=NULL && bus->dev_iterate ==NULL ) || (cls !=NULL && cls->dev_iterate ==NULL )) { rte_errno =ENOTSUP ; -return -rte_errno; + goto get_out; }if (bus !=NULL ) { - it->busstr = str; + it->busstr = devstr;if (cls !=NULL ) - it->clsstr = slash +1 ; + it->clsstr = slash; }else if (cls !=NULL ) { - it->clsstr = str; + it->clsstr = devstr; } - it->devstr = str; + it->devstr = devstr; it->bus = bus; it->cls = cls; -return 0 ; +get_out: +rte_kvargs_free (kvlist); +free (str); +return -rte_errno; +} + +/* '\0' forbidden in sym */ +static const char * +strfirstof (const char *str, +const char *sym) +{ +const char *s; + +for (s = str; s[0 ] !='\0' ; s++) { +const char *c; + +for (c = sym; c[0 ] !='\0' ; c++) { +if (c[0 ] == s[0 ]) +return s; + } + } +return NULL ; }static char *dev_str_sane_cpy (const char *str) { -struct rte_kvarg kv; -char *end; +const char *end;char *cpy; -if (rte_parse_kv (str, &kv)) { - rte_errno =EINVAL ; -return NULL ; - } -/* copying '\0' is valid. */ -if (kv.next !=NULL ) - cpy =strdup (kv.next); -else + end =strfirstof (str,",/" ); +if (end !=NULL && + end[0 ] ==',' ) { + cpy =strdup (end +1 ); + }else { +/* '/' or '\0' */ cpy =strdup ("" ); -if (cpy ==NULL ) { - rte_errno =ENOMEM ; -return NULL ; } - end =strchr (cpy,'/' ); -if (end !=NULL ) - end[0 ] ='\0' ; +if (cpy ==NULL ) + rte_errno =ENOMEM ;return cpy; }
lib/librte_eal/linuxapp/eal/Makefile +1 -0
@@ -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
Signature · 1 line
2.11.0
Re: [PATCH 2/2] dev: use rte_kvargs
Quoted 5 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>---
Cc Neil Horman <[email protected]>
I'm actually ok with this, but as Keith noted, I'm not sure why you didn't just:
1) Add the ability to create a grouping key, so that key value pairs could contain a list of comma separated values (something like '{}' to denote that everything between the characters was the value in a kv pair, regardless of other tokenizing characters in the value).
2) Add the ability to recursively parse the value into a list of tokens
3) Layer your functionality on top of (1) and (2), as Keith noted
Neil
Quoted 229 lines
I find using
rte_parse_kvcleaner.
The functionrte_dev_iterator_initis already ugly enough as it is. This is really not helping.lib/librte_eal/common/eal_common_dev.c | 127 +++++++++++++++++++++------------ lib/librte_eal/linuxapp/eal/Makefile | 1 + 2 files changed, 83 insertions(+), 45 deletions(-)lib/librte_eal/common/eal_common_dev.c +82
-45@@ -15,6 +15,7 @@#include <rte_devargs.h> #include <rte_debug.h> #include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -270,12 +271,15 @@ rte_eal_hotplug_remove(const char *busname, const char *devname) } int __rte_experimental -rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str) +rte_dev_iterator_init (struct rte_dev_iterator *it, +const char *devstr) { -struct rte_bus *bus =NULL ; +struct rte_kvargs *kvlist =NULL ;struct rte_class *cls =NULL ; -struct rte_kvarg kv; -char *slash; +struct rte_bus *bus =NULL ; +struct rte_kvargs_pair *kv; +char *slash =NULL ; +char *str =NULL ;/* Having both busstr and clsstr NULL is illegal, * marking this iterator as invalid unless @@ -283,98 +287,131 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str)*/ it->busstr =NULL ; it->clsstr =NULL ; + str =strdup (devstr); +if (str ==NULL ) { + rte_errno =ENOMEM ; + goto get_out; + } + slash =strchr (str,'/' ); +if (slash !=NULL ) { + slash[0 ] ='\0' ; + slash =strchr (devstr,'/' ) +1 ; + }/* Safety checks and prep-work */ -if (rte_parse_kv (str, &kv)) { + kvlist =rte_kvargs_parse (str,NULL ); +if (kvlist ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not parse: %s\n" , str); rte_errno =EINVAL ; -return -rte_errno; + goto get_out; } it->device =NULL ; it->class_device =NULL ; -if (strcmp (kv.key,"bus" ) ==0 ) { - bus =rte_bus_find_by_name (kv.value); + kv = &kvlist->pairs[0 ]; +if (strcmp (kv->key,"bus" ) ==0 ) { + bus =rte_bus_find_by_name (kv->value);if (bus ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not find bus \"%s\"\n" , - kv.value); + kv->value); rte_errno =EFAULT ; -return -rte_errno; + goto get_out; } - slash =strchr (str,'/' );if (slash !=NULL ) { -if (rte_parse_kv (slash +1 , &kv)) { +rte_kvargs_free (kvlist); + kvlist =rte_kvargs_parse (slash,NULL ); +if (kvlist ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not parse: %s\n" , - slash +1 ); + slash); rte_errno =EINVAL ; -return -rte_errno; + goto get_out; } - cls =rte_class_find_by_name (kv.value); + kv = &kvlist->pairs[0 ]; +if (strcmp (kv->key,"class" )) { +RTE_LOG (ERR ,EAL ,"Additional layer must be a class\n" ); + rte_errno =EINVAL ; + goto get_out; + } + cls =rte_class_find_by_name (kv->value);if (cls ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not find class \"%s\"\n" , - kv.value); + kv->value); rte_errno =EFAULT ; -return -rte_errno; + goto get_out; } } - }else if (strcmp (kv.key,"class" ) ==0 ) { - cls =rte_class_find_by_name (kv.value); + }else if (strcmp (kv->key,"class" ) ==0 ) { + cls =rte_class_find_by_name (kv->value);if (cls ==NULL ) {RTE_LOG (ERR ,EAL ,"Could not find class \"%s\"\n" , - kv.value); + kv->value); rte_errno =EFAULT ; -return -rte_errno; + goto get_out; } }else { rte_errno =EINVAL ; -return -rte_errno; + goto get_out; }/* The string should have at least * one layer specified. */ if (bus ==NULL && cls ==NULL ) { rte_errno =EINVAL ; -return -rte_errno; + goto get_out; }if ((bus !=NULL && bus->dev_iterate ==NULL ) || (cls !=NULL && cls->dev_iterate ==NULL )) { rte_errno =ENOTSUP ; -return -rte_errno; + goto get_out; }if (bus !=NULL ) { - it->busstr = str; + it->busstr = devstr;if (cls !=NULL ) - it->clsstr = slash +1 ; + it->clsstr = slash; }else if (cls !=NULL ) { - it->clsstr = str; + it->clsstr = devstr; } - it->devstr = str; + it->devstr = devstr; it->bus = bus; it->cls = cls; -return 0 ; +get_out: +rte_kvargs_free (kvlist); +free (str); +return -rte_errno; +} + +/* '\0' forbidden in sym */ +static const char * +strfirstof (const char *str, +const char *sym) +{ +const char *s; + +for (s = str; s[0 ] !='\0' ; s++) { +const char *c; + +for (c = sym; c[0 ] !='\0' ; c++) { +if (c[0 ] == s[0 ]) +return s; + } + } +return NULL ; }static char *dev_str_sane_cpy (const char *str) { -struct rte_kvarg kv; -char *end; +const char *end;char *cpy; -if (rte_parse_kv (str, &kv)) { - rte_errno =EINVAL ; -return NULL ; - } -/* copying '\0' is valid. */ -if (kv.next !=NULL ) - cpy =strdup (kv.next); -else + end =strfirstof (str,",/" ); +if (end !=NULL && + end[0 ] ==',' ) { + cpy =strdup (end +1 ); + }else { +/* '/' or '\0' */ cpy =strdup ("" ); -if (cpy ==NULL ) { - rte_errno =ENOMEM ; -return NULL ; } - end =strchr (cpy,'/' ); -if (end !=NULL ) - end[0 ] ='\0' ; +if (cpy ==NULL ) + rte_errno =ENOMEM ;return cpy; }lib/librte_eal/linuxapp/eal/Makefile +1
-0@@ -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.cSignature · 1 line
2.11.0
Re: [PATCH 2/2] dev: use rte_kvargs
Hi Neil,
Quoted 6 lines · Neil Horman
Quoted 5 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>---
Cc Neil Horman <[email protected]>
Keep in mind that all of this is to achieve the trivial task I was doing in 20 lines or so.
Quoted 9 lines
I'm actually ok with this but as Keith noted, I'm not sure why you didn't just:
1) Add the ability to create a grouping key, so that key value pairs could contain a list of comma separated values (something like '{}' to denote that everything between the characters was the value in a kv pair, regardless of other tokenizing characters in the value).
2) Add the ability to recursively parse the value into a list of tokens
I don't need a recursive construct or a tree-like structure. I only need an alternative to '\0' to signify "end-of-list".
This seems like an edge-case to librte_kvargs that would only be useful to a specific case. It does not seem a wise addition.
So maybe I did not understand your suggestion. Can you give an example of inputs?
I need to parse something like
"bus=pci,vendor_id=0x8086/class=eth"
(and I only care about bus=pci and class=eth).
how can grouping help? My issue is that librte_kvargs would parse
key:vendor_id
value:0x8086/class
and would then stumble on the unexpected '='.
Quoted 1 line
3) Layer your functionality on top of (1) and (2), as Keith noted
The stack allocator seems like a nice-to-have that would interest people using librte_kvargs. I find librte_kvargs to be cumbersome. I cannot rewrite it from scratch, unless I update everything that relies on it as well. So I do not touch it, because I don't care *that* much.
Why not simply leave my helper alongside? If people care enough about it and would prefer to use it over librte_kvargs, then maybe we could think about doing the effort of exposing it cleanly (or maybe they could). Right now, I see only me needing it and I do not see this effort as worth it.
Regards,
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH 2/2] dev: use rte_kvargs
Quoted 40 lines · Gaëtan Rivet
Hi Neil,
Quoted 6 lines · Neil Horman
Quoted 5 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>---
Cc Neil Horman <[email protected]>Keep in mind that all of this is to achieve the trivial task I was doing in 20 lines or so.
Quoted 9 lines
I'm actually ok with this but as Keith noted, I'm not sure why you didn't just:
1) Add the ability to create a grouping key, so that key value pairs could contain a list of comma separated values (something like '{}' to denote that everything between the characters was the value in a kv pair, regardless of other tokenizing characters in the value).
2) Add the ability to recursively parse the value into a list of tokens
I don't need a recursive construct or a tree-like structure. I only need an alternative to '\0' to signify "end-of-list".
This seems like an edge-case tolibrte_kvargsthat would only be useful to a specific case. It does not seem a wise addition.So maybe I did not understand your suggestion. Can you give an example of inputs?
I need to parse something like
"bus=pci,vendor_id=0x8086/class=eth"
(and I only care about bus=pci and class=eth).
Quoted 6 lines
how can grouping help? My issue is that
librte_kvargswould parsekey:vendor_id
value:0x8086/classand would then stumble on the unexpected '=‘.
Let me try to remember what I did here.
Created a new list structure of top level keywords like ‘bus’, ‘class’, …
The new list is passed into the new API that splits up the string by ‘/‘ then for each string you call into the original kvargs routines to parse the remaining items within each string. I believe I passed a function pointer in the new array of structures that allowed me to handle the top level keywords. What is passed to the top level keyword function is the string to be parsed by the normal kvargs routines. Each routine then used kvargs routines as normal. I am sure the layer could be done differently and the structure could maybe even contain the kvargs list or keywords if you want.
Anyway it worked out pretty well, just adding new APIs to handle and layer on top of kvargs APIs.
Quoted 8 lines
Quoted 2 lines
3) Layer your functionality on top of (1) and (2), as Keith noted
The stack allocator seems like a nice-to-have that would interest people using
librte_kvargs. I findlibrte_kvargsto be cumbersome. I cannot rewrite it from scratch, unless I update everything that relies on it as well. So I do not touch it, because I don't care *that* much.
Quoted 10 lines
Why not simply leave my helper alongside? If people care enough about it and would prefer to use it over
librte_kvargs, then maybe we could think about doing the effort of exposing it cleanly (or maybe they could). Right now, I see only me needing it and I do not see this effort as worth it.Regards,
Signature · 2 lines
Gaëtan Rivet 6WIND
Regards,
Keith
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
In reply to Gaëtan RivetQuoted 108 lines · Gaëtan Rivet
Quoted 100 lines · Neil Horman
Quoted 31 lines · Gaëtan Rivet
Quoted 30 lines · Neil Horman
Quoted 29 lines · Gaëtan Rivet
Quoted 17 lines · Neil Horman
Quoted 16 lines · Keith
Quoted 7 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
Quoted 6 lines
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?Quoted 7 lines
Quoted 2 lines
My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parseto an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time.I think the existing allocation scheme is fine for other usages (in drivers and so on). Not for what I wanted to do.
Quoted 8 lines
Quoted 5 lines
Ok, but thats an adressable issue. you can bifurcate the parse function to an internal function that accepts any preallocated kvargs struct, and export two wrapper functions, one which allocates the struct from the heap, another which allocated automatically on the stack.
Sure, everything is possible.
Ok.
Quoted 21 lines
Quoted 12 lines
Quoted 5 lines
Quoted 4 lines
librte_kvargsisn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.Quoted 7 lines
It serves a different purpose than the one I'm pursuing.
This helper is lightweight and private. If I wanted to integrate my needs with
librte_kvargs, I would be adding new functionalities, making it more complex, and for a use-case that is useless for the vast majority of users of the lib.Quoted 8 lines
Ok, to that end:
1) Privacy is not an issue (at least from my understanding of what your doing). If we start with the assumption that
librte_kvargsis capable of satisfying your needs (even if its not done in an optimal way), the fact that your version of the function is internal to the library doesn't seem overly relevant, unless theres something critical to that privacy that I'm missing.Quoted 5 lines
Privacy is only a point I brought up to say that the impact of this function is minimal. People looking to parse their kvargs should not have any ambiguity regarding how they should do so. Only
librte_kvargsis available.Ok, would you also council others developing dpdk apps to write their own parsing routines when what they needed was trivial for the existing library? You are people too :)
Quoted 7 lines
Quoted 6 lines
2) Lightweight function seems like something that can be integrated with
librte_kvargs. Looking at it, what may I ask inlibrte_kvargsis insufficiently non-performant for your needs, specifically? We talked about the heap allocation above, is there something else? The string duplication perhaps?Quoted 7 lines
Mostly the way to use it.
The filter strings are
bus=value,.../class=value,...where either bus= list or class= list can be omitted, but at least one must appear.
Ok, so whats the problem with using
librte_kvargsfor that? Is it that the list that acts as the value to the key isn't parsed out into its own set of tokens? That seems entirely addressable.Quoted 3 lines
I want to read a single kvarg. I do not want to parse the whole string. the '/' signifies the end of the current layer.
This makes it seem like
librte_kvargscan handle this as a trivial case of its functionality.Quoted 4 lines
librte_kvargsdoes not care about those points. I cannot ask it to only read either bus or class, as it would then throw an error for all the other keys (which the EAL has necessarily no knowledge of).Quoted 6 lines
But you can ask it to read both, and within your libraries logic make the determination as to the validitiy of receiving both. Alternatively you can modify the
valid_keyscheck in kvargs to be a regex that matches on either bus or class, or accept an ignore parameter for keys that may appear but should be ignored in the light of other keys. Theres lots of options here.
Quoted 3 lines
No, I will not be adding regex parsing to express a set of acceptable token :)
Thats fine, Just making suggestions as to how to add the functionality you need to the command line parsing library. I'm not sure what you're opposision is, but there are lots of other ways to skin this cat.
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
So I would need to:
* Add a custom storage scheme
* Add a custom parsing mode stopping at the first kvarg
* Add an edge-case to ignore the '/', so as not to throw off the rest of the parsing (least it be considered part of the previous kvarg value field).Seeing this, does adding those really specifics functionality help
librte_kvargsto be more useful and usable? I do not think so.
Quoted 7 lines
Quoted 4 lines
I think you're overcomplicating this.
How about enhancinglibrte_kvargsto make parsing configurable such that invalid keys get ignored rather than generate errors?Invalid keys can already be ignored, it's not an issue.
Ok, that eliminates one problem and seems like it makes even more sense to use the standard parsing library.
Quoted 35 lines
Quoted 24 lines
Quoted 4 lines
It would only serve to disrupt the library for a marginal use-case, with the introduction of edge-cases that will blur the specs of the lib's API, making it harder to avoid subtle bugs.
What do you mean "disrupt the library"? What is its purpose of a library if not to do the jobs we want it to? If everyone created their own routine to do something that a library could do with some modifications, we'd be left with 1000 versions of the same routine. If the existing library does 99% of what you want it to, lets ennumerate what the missing %1 is and make the change, not throw the baby out with the bathwater.
Quoted 8 lines
Only way to do so sanely would be to add
rte_parse_kvas part oflibrte_kvargs, as is. But then the whole thing does not make sense IMO:
no one would care to use it, the maintainance effort is the same, the likelyhood of bugs as well (but in the process we would disrupt the distribution oflibrte_kvargsby moving it within the EAL).I see no benefit to either solution.
Again, thats an overcomplication. As I read it, you have a need to interrogate a key/value string, whos contents may contain invalid keys (for your parsing purposes), and whos values may themselves be lists, correct? If so, I don't see the problem in enhancing libkvargs to:
Quoted 5 lines
1) Allow for the parsing routine to ignore invalid keys (or even ignore specific invalid keys, and trigger on any unknown keys)
2) Allows for the subparsing of lists into their own set of tokens.
What I would do if I wanted to use
librte_kvargs, would be to duplicate the input text, mangle it to respect the intended format, and feed it tolibrte_kvargsfor parsing. Then I would iterate over the pairs, and stop on the two I'm concerned about.
Quoted 7 lines
What I dislike here:
* I actually do the bulk of the parsing by hand (recognizing first a valid input, modifying it to respect the lib, and after iterating on the list of pairs and strcmp-ing the ones I want). This is approximately as complicated as the current helper function.
Or, just extend the kvargs string format to allow for nested lits (which I think is the main sticking point here) and adjust your input format accordingly.
Quoted 2 lines
* I have to move
librte_kvargsin the EAL.
Why? Theres no reason you can't make eal dependent on kvargs, I see no circular dependency there.
Quoted 14 lines
Quoted 14 lines
Quoted 14 lines
Quoted 9 lines
Quoted 4 lines
If that's really an issue, I'm better off simply removing
rte_parse_kvand writing the parsing by hand within my function. This would be ugly and tedious, but less than movinglibrte_kvargswithin EAL and changing it to my needs.I don't think thats necessecary, I just think if you can ennumerate the items that are non-performant for your needs we can make some changes to
librte_kvargsto optimize around them, or offer parsing options to avoid them, and in the process avoid some code duplicationI think it makes sense to have specialized functions for specialized use-cases, and forcing the code to be generic and work with all of them will make it more complicated.
Quoted 7 lines
Quoted 3 lines
This isn't specialized, its trivial. Its just a trivial case that libkvargs isn't built to handle at the moment. Lets get it there.
My use-case is trivial. Putting it within the
librte_kvargsmakes it more complicated to write. I hate this.
If librte_kvargs can't handle a trivial use case, then kvargs needs to be improved.
Quoted 10 lines
Quoted 7 lines
Quoted 5 lines
The genericity would only be worth it if people actually needed to parse the device strings the same way I do. No one has any business doing so. This genericity adds complexity and issues, without even being useful in the first place.
I really think you're trying to take a short cut here where none is needed, and I'm sorry, but I can't support that.
There are countably infinite solutions, we will probably reach one (and it might even do what we want).
I'm not really sure what you mean by this, but the bottom line for me is that there is no reason to invent a new wheel when you have a library who purpose is to do the kind of things you want.
Neil
Re: [PATCH v2 04/18] eal: add lightweight kvarg parsing utility
In reply to Gaëtan RivetQuoted 105 lines · Gaëtan Rivet
Quoted 27 lines · Neil Horman
Quoted 26 lines · Gaëtan Rivet
Quoted 24 lines · Neil Horman
Quoted 11 lines · Keith
Quoted 11 lines · Gaetan Rivet
This library offers a quick way to parse parameters passed with a key=value syntax.
A single function is needed and finds the relevant element within the text. No dynamic allocation is performed. It is possible to chain the parsing of each pairs for quickly scanning a list.
Quoted 7 lines
Quoted 2 lines
This utility is private to the EAL and should allow avoiding having to move around the more complete
librte_kvargs.What is the big advantage with this code and the
librte_kvargscode. Is it just no allocation,rte_kvargsneeds to be build before parts of EAL or what?My concern is we have now two flavors one in EAL and one in
librte_kvargs, would it not be more reasonable to improverte_kvargsto remove your objections? I am all for fast, better, stronger code :-)+1, this really doesn't make much sense to me. Two parsing routines seems like its just asking for us to have to fix parsing bugs in two places. If allocation is a concern, I don't see why you can't just change the malloc in
rte_kvargs_parseto an automatic allocation on the stack, or a preallocation set of kvargs that can be shared from init time.Quoted 8 lines
Quoted 3 lines
I think the existing allocation scheme is fine for other usages (in drivers and so on). Not for what I wanted to do.
Ok, but thats an adressable issue. you can bifurcate the parse function to an internal function that accepts any preallocated kvargs struct, and export two wrapper functions, one which allocates the struct from the heap, another which allocated automatically on the stack.
Sure, everything is possible.
Quoted 12 lines
Quoted 5 lines
Quoted 4 lines
librte_kvargsisn't necessecarily
the best parsing library ever, but its not bad, and it just seems wrong to go re-inventing the wheel.Quoted 7 lines
It serves a different purpose than the one I'm pursuing.
This helper is lightweight and private. If I wanted to integrate my needs with
librte_kvargs, I would be adding new functionalities, making it more complex, and for a use-case that is useless for the vast majority of users of the lib.Quoted 8 lines
Ok, to that end:
1) Privacy is not an issue (at least from my understanding of what your doing). If we start with the assumption that
librte_kvargsis capable of satisfying your needs (even if its not done in an optimal way), the fact that your version of the function is internal to the library doesn't seem overly relevant, unless theres something critical to that privacy that I'm missing.Privacy is only a point I brought up to say that the impact of this function is minimal. People looking to parse their kvargs should not have any ambiguity regarding how they should do so. Only
librte_kvargsis available.Quoted 6 lines
2) Lightweight function seems like something that can be integrated with
librte_kvargs. Looking at it, what may I ask inlibrte_kvargsis insufficiently non-performant for your needs, specifically? We talked about the heap allocation above, is there something else? The string duplication perhaps?Mostly the way to use it.
The filter strings are
bus=value,.../class=value,...where either bus= list or class= list can be omitted, but at least one must appear.
I want to read a single kvarg. I do not want to parse the whole string. the '/' signifies the end of the current layer.
librte_kvargsdoes not care about those points. I cannot ask it to only read either bus or class, as it would then throw an error for all the other keys (which the EAL has necessarily no knowledge of).So I would need to:
* Add a custom storage scheme
* Add a custom parsing mode stopping at the first kvarg
* Add an edge-case to ignore the '/', so as not to throw off the rest of the parsing (least it be considered part of the previous kvarg value field).Seeing this, does adding those really specifics functionality help
librte_kvargsto be more useful and usable? I do not think so.It would only serve to disrupt the library for a marginal use-case, with the introduction of edge-cases that will blur the specs of the lib's API, making it harder to avoid subtle bugs.
Quoted 5 lines
Only way to do so sanely would be to add
rte_parse_kvas part oflibrte_kvargs, as is. But then the whole thing does not make sense IMO:
no one would care to use it, the maintainance effort is the same, the likelyhood of bugs as well (but in the process we would disrupt the distribution oflibrte_kvargsby moving it within the EAL).
It seems to me you could layer the new functionality on top of rte_kvargs to provide the new layering you want and still provide the old API for current usage. The allocation of memory is internal to rte_kvargs and it really should not allocate memory or allocate on the stack. This change is something we should most likely do for rte_kvargs anyway. I do not like routines that allocate memory for me then expect me to free the memory later only because it needed some internal working space, but that is just me.
In my previous coding needs I had layered a structure and routine on top of rte_kvargs to provide something close to your needs, but in the long run I did not need the code as the design changed. I could look at the again and see if it would help here.
Quoted 13 lines
I see no benefit to either solution.
Quoted 9 lines
Quoted 4 lines
If that's really an issue, I'm better off simply removing
rte_parse_kvand writing the parsing by hand within my function. This would be ugly and tedious, but less than movinglibrte_kvargswithin EAL and changing it to my needs.I don't think thats necessecary, I just think if you can ennumerate the items that are non-performant for your needs we can make some changes to
librte_kvargsto optimize around them, or offer parsing options to avoid them, and in the process avoid some code duplication
Quoted 12 lines
I think it makes sense to have specialized functions for specialized use-cases, and forcing the code to be generic and work with all of them will make it more complicated.
The genericity would only be worth it if people actually needed to parse the device strings the same way I do. No one has any business doing so. This genericity adds complexity and issues, without even being useful in the first place.
Signature · 2 lines
Gaëtan Rivet 6WIND
Regards,
Keith
PATCH v2 5/18 eal/dev: add device iterator interface
In reply to Gaetan RivetA 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
@@ -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
PATCH v2 6/18 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
@@ -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
PATCH v2 7/18 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
@@ -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
PATCH v2 8/18 eal/dev: implement device iteration initialization
In reply to Gaetan RivetParse a device description.
Split this description in their relevant part for both abstraction layer.
No dynamic allocation is performed.
--- lib/librte_eal/common/eal_common_dev.c | 58 +++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++++++++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 82 insertions(+)
lib/librte_eal/common/eal_common_dev.c +58 -0
@@ -10,6 +10,7 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h>
@@ -245,3 +246,60 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str) +{ +struct rte_bus *bus =NULL ; +struct rte_class *cls =NULL ; +struct rte_kvarg kv; + +/* Having both busstr and clsstr NULL is illegal, +* marking this iterator as invalid unless +* everything goes well. +*/ + it->busstr =NULL ; + it->clsstr =NULL ; +/* Safety checks and prep-work */ +if (rte_parse_kv (str, &kv)) { +RTE_LOG (ERR ,EAL ,"Could not parse: %s\n" , str); +return -1 ; + } + it->device =NULL ; + it->class_device =NULL ; +if (strcmp (kv.key,"bus" ) ==0 ) { +char *slash; + + bus =rte_bus_find_by_name (kv.value); + it->busstr = str; + slash =strchr (str,'/' ); +if (slash !=NULL ) { +if (rte_parse_kv (slash +1 , &kv)) +return -1 ; + cls =rte_class_find_by_name (kv.value); + it->clsstr = slash +1 ; + } + }else if (strcmp (kv.key,"class" ) ==0 ) { + cls =rte_class_find_by_name (kv.value); + it->clsstr = str; + }else { + rte_errno =EINVAL ; +return -rte_errno; + } +/* The string should have at least +* one layer specified. +*/ +if (bus ==NULL && cls ==NULL ) { + rte_errno =EINVAL ; +return -rte_errno; + } +if ((bus !=NULL && bus->dev_iterate ==NULL ) || + (cls !=NULL && cls->dev_iterate ==NULL )) { + rte_errno =ENOTSUP ; +return -rte_errno; + } + it->devstr = str; + it->bus = bus; + it->cls = cls; +return 0 ; +}
lib/librte_eal/common/include/rte_dev.h +23 -0
@@ -310,6 +310,29 @@ typedef void *(*rte_dev_iterate_t)(const void *start,const char *devstr, const struct rte_dev_iterator *it); +/** +* Initializes a device iterator. +* +* This iterator allows accessing a list of devices matching a criteria. +* The device matching is made among all buses and classes currently registered, +* filtered by the device description given as parameter. +* +* This function will not allocate any memory. It is safe to stop the +* iteration at any moment and let the iterator go out of context. +* +* @param it +* Device iterator handle. +* +* @param str +* Device description string. +* +* @return +* 0 on successful initialization. +* <0 on error. +*/ +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); + #ifdef __cplusplus }#endif
lib/librte_eal/rte_eal_version.map +1 -0
@@ -228,6 +228,7 @@ EXPERIMENTAL { rte_mp_sendmsg; rte_mp_request; rte_mp_reply; + rte_dev_iterator_init; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
PATCH v2 9/18 eal/dev: implement device iteration
In reply to Gaetan RivetUse 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 | 159 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 25 +++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 185 insertions(+)
lib/librte_eal/common/eal_common_dev.c +159 -0
@@ -19,6 +19,28 @@#include "eal_private.h" +struct dev_next_ctx { +struct rte_dev_iterator *it; +const char *busstr; +const char *clsstr; +}; + +#define CTX (it, busstr, clsstr) \ + (&(const struct dev_next_ctx){ \ + .it = it, \ + .busstr = busstr, \ + .clsstr = clsstr, \ + }) + +#define ITCTX (ptr) \ + ((struct dev_next_ctx *)(intptr_t)ptr)->it + +#define BUSCTX (ptr) \ + ((struct dev_next_ctx *)(intptr_t)ptr)->busstr + +#define CLSCTX (ptr) \ + ((struct dev_next_ctx *)(intptr_t)ptr)->clsstr +/* EAL-private function. */ int rte_parse_kv (const char *str,struct rte_kvarg *kv)
@@ -303,3 +325,140 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, const char *str) it->cls = cls;return 0 ; } + +static char * +dev_str_sane_cpy (const char *str) +{ +struct rte_kvarg kv; +char *end; +char *cpy; + +if (rte_parse_kv (str, &kv)) { + rte_errno =EINVAL ; +return NULL ; + } +/* copying '\0' is valid. */ +if (kv.next !=NULL ) + cpy =strdup (kv.next); +else + cpy =strdup ("" ); +if (cpy ==NULL ) { + rte_errno =ENOMEM ; +return NULL ; + } + end =strchr (cpy,'/' ); +if (end !=NULL ) + end[0 ] ='\0' ; +return cpy; +} + +static int +class_next_dev_cmp (const struct rte_class *cls, +const void *ctx) +{ +struct rte_dev_iterator *it; +const char *clsstr =NULL ; +void *dev; + +if (cls->dev_iterate ==NULL ) +return 1 ; + it =ITCTX (ctx); + clsstr =CLSCTX (ctx); + dev = it->class_device; +/* it->clsstr != NULL means a class +* was specified in the devstr. +*/ +if (it->clsstr !=NULL && cls != it->cls) +return 1 ; + dev = cls->dev_iterate (dev, clsstr, it); + it->class_device = dev; +return dev ==NULL ; +} + +static int +bus_next_dev_cmp (const struct rte_bus *bus, +const void *ctx) +{ +struct rte_device *dev =NULL ; +struct rte_class *cls =NULL ; +struct rte_dev_iterator *it; +const char *busstr =NULL ; + +if (bus->dev_iterate ==NULL ) +return 1 ; + it =ITCTX (ctx); + busstr =BUSCTX (ctx); + dev = it->device; +/* it->busstr != NULL means a bus +* was specified in the devstr. +*/ +if (it->busstr !=NULL && bus != it->bus) +return 1 ; +if (it->clsstr ==NULL ) { + dev = bus->dev_iterate (dev, busstr, it); + goto end; + } +/* clsstr != NULL */ +if (dev ==NULL ) { +next_dev_on_bus: + dev = bus->dev_iterate (dev, busstr, it); + it->device = dev; + } +if (dev ==NULL ) +return 1 ; +if (it->cls !=NULL ) + cls =TAILQ_PREV (it->cls, rte_class_list, next); + cls =rte_class_find (cls, class_next_dev_cmp, ctx); +if (cls !=NULL ) { + it->cls = cls; + goto end; + } + goto next_dev_on_bus; +end: + it->device = dev; +return dev ==NULL ; +} +__rte_experimental +struct rte_device * +rte_dev_iterator_next (struct rte_dev_iterator *it) +{ +struct rte_bus *bus =NULL ; +int old_errno = rte_errno; +char *busstr =NULL ; +char *clsstr =NULL ; + + rte_errno =0 ; +if (it->busstr ==NULL && it->clsstr ==NULL ) { +/* Invalid iterator. */ + rte_errno =EINVAL ; +return NULL ; + } +if (it->bus !=NULL ) + bus =TAILQ_PREV (it->bus, rte_bus_list, next); +if (it->busstr !=NULL ) { + busstr =dev_str_sane_cpy (it->busstr); +if (busstr ==NULL ) + goto out; + } +if (it->clsstr !=NULL ) { + clsstr =dev_str_sane_cpy (it->clsstr); +if (clsstr ==NULL ) + goto out; + } +while ((bus =rte_bus_find (bus, bus_next_dev_cmp, +CTX (it, busstr, clsstr)))) { +if (it->device !=NULL ) { + it->bus = bus; + goto out; + } +if (it->busstr !=NULL || + rte_errno !=0 ) +break ; + } +if (rte_errno ==0 ) + rte_errno = old_errno; +out: +free (busstr); +free (clsstr); +return it->device; +}
lib/librte_eal/common/include/rte_dev.h +25 -0
@@ -333,6 +333,31 @@ typedef void *(*rte_dev_iterate_t)(const void *start, int __rte_experimentalrte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); +/** +* Iterates on a device iterator. +* +* Generates a new rte_device handle corresponding to the next element +* in the list described in comprehension by the iterator. +* +* The next object is returned, and the iterator is updated. +* +* @param it +* Device iterator handle. +* +* @return +* An rte_device handle if found. +* NULL if an error occurred (rte_errno is set). +* NULL if no device could be found (rte_errno is not set). +*/ +struct rte_device * __rte_experimental +rte_dev_iterator_next (struct rte_dev_iterator *it); + +#define RTE_DEV_FOREACH (dev, devstr, it) \ + for (rte_dev_iterator_init(it, devstr), \ + dev = rte_dev_iterator_next(it); \ + dev != NULL; \ + dev = rte_dev_iterator_next(it)) + #ifdef __cplusplus }#endif
lib/librte_eal/rte_eal_version.map +1 -0
@@ -229,6 +229,7 @@ EXPERIMENTAL { rte_mp_request; rte_mp_reply; rte_dev_iterator_init; + rte_dev_iterator_next; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
PATCH v2 10/18 bus/pci: fix find device implementation
In reply to Gaetan RivetIf start is set, and a device before it matches the data passed for comparison, then this first device is returned.
This produces potentially infinite loops.
--- 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
@@ -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
@@ -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
PATCH v2 11/18 bus/pci: implement device iteration and comparison
In reply to Gaetan Rivet--- drivers/bus/pci/Makefile | 2 +- drivers/bus/pci/pci_common.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-)
drivers/bus/pci/Makefile +1 -1
@@ -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 +34 -0
@@ -13,6 +13,7 @@#include <rte_errno.h> #include <rte_interrupts.h> +#include <rte_kvargs.h> #include <rte_log.h> #include <rte_bus.h> #include <rte_pci.h>
@@ -497,6 +498,38 @@ pci_unplug(struct rte_device *dev)return ret; } +static int +pci_dev_match (const struct rte_device *dev, +const void *_kvlist) +{ +const struct rte_kvargs *kvlist = _kvlist; + + (void ) dev; + (void ) kvlist; +return 0 ; +} + +static void * +pci_dev_iterate (const void *start, +const char *str, + const struct rte_dev_iterator *it __rte_unused) +{ +struct rte_device *dev; +struct rte_kvargs *kvargs =NULL ; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str,NULL ); +if (kvargs ==NULL ) { +RTE_LOG (ERR ,EAL ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } + dev =pci_find_device (start, pci_dev_match, kvargs); +rte_kvargs_free (kvargs); +return dev; +} +struct rte_pci_bus rte_pci_bus = { .bus = { .scan = rte_pci_scan,
@@ -506,6 +539,7 @@ struct rte_pci_bus rte_pci_bus = { .unplug = pci_unplug, .parse = pci_parse, .get_iommu_class = rte_pci_get_iommu_class, + .dev_iterate = pci_dev_iterate, }, .device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list), .driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
Signature · 1 line
2.11.0
PATCH v2 12/18 bus/pci: add device matching field id
In reply to Gaetan RivetThe 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 | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_common.c +24 -2
@@ -499,13 +499,35 @@ pci_unplug(struct rte_device *dev) }static int +pci_addr_kv_cmp(const char *key __rte_unused, +const char *value, +void *_addr2) +{ +struct rte_pci_addr _addr1; +struct rte_pci_addr *addr1 = &_addr1; +struct rte_pci_addr *addr2 = _addr2; + +if (rte_pci_addr_parse (value, addr1)) +return -1 ; +return rte_pci_addr_cmp (addr1, addr2); +} + +static int pci_dev_match (const struct rte_device *dev,const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_pci_device *pdev; - (void ) dev; - (void ) kvlist; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + pdev =RTE_DEV_TO_PCI_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"id" , + &pci_addr_kv_cmp, + (void *)(intptr_t )&pdev->addr)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v2 13/18 bus/vdev: fix find device implementation
In reply to Gaetan RivetIf start is set and a device before it matches the data, this device is returned.
This produces induces potentially infinite loops.
--- 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
@@ -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
@@ -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
PATCH v2 14/18 bus/vdev: implement device iteration
In reply to Gaetan Rivet--- drivers/bus/vdev/Makefile | 2 +- drivers/bus/vdev/vdev.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-)
drivers/bus/vdev/Makefile +1 -1
@@ -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 +34 -0
@@ -43,6 +43,7 @@#include <rte_bus.h> #include <rte_common.h> #include <rte_devargs.h> +#include <rte_kvargs.h> #include <rte_memory.h> #include <rte_tailq.h> #include <rte_spinlock.h>
@@ -415,6 +416,38 @@ vdev_unplug(struct rte_device *dev)return rte_vdev_uninit (dev->name); } +static int +vdev_dev_match (const struct rte_device *dev, +const void *_kvlist) +{ +const struct rte_kvargs *kvlist = _kvlist; + + (void ) kvlist; + (void ) dev; +return 0 ; +} + +static void * +vdev_dev_iterate (const void *start, +const char *str, + const struct rte_dev_iterator *it __rte_unused) +{ +struct rte_kvargs *kvargs =NULL ; +struct rte_device *dev; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str,NULL ); +if (kvargs ==NULL ) { +VDEV_LOG (ERR ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } + dev =vdev_find_device (start, vdev_dev_match, kvargs); +rte_kvargs_free (kvargs); +return dev; +} +static struct rte_bus rte_vdev_bus = { .scan = vdev_scan, .probe = vdev_probe,
@@ -422,6 +455,7 @@ static struct rte_bus rte_vdev_bus = { .plug = vdev_plug, .unplug = vdev_unplug, .parse = vdev_parse, + .dev_iterate = vdev_dev_iterate, };RTE_REGISTER_BUS (vdev, rte_vdev_bus);
Signature · 1 line
2.11.0
PATCH v2 15/18 bus/vdev: add device matching field driver
In reply to Gaetan RivetThe vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:
"bus=vdev,driver=xxxx"
--- drivers/bus/vdev/vdev.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
drivers/bus/vdev/vdev.c +20 -2
@@ -417,13 +417,31 @@ vdev_unplug(struct rte_device *dev) }static int +vdev_str_kv_cmp(const char *key __rte_unused, +const char *value, +void *_str) +{ +const char *str = _str; + +return strcmp (str, value); +} + +static int vdev_dev_match (const struct rte_device *dev,const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_vdev_device *vdev; - (void ) kvlist; - (void ) dev; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + vdev =RTE_DEV_TO_VDEV_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"driver" , + &vdev_str_kv_cmp, + (void *)(intptr_t )vdev->device.driver->name)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v2 16/18 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 | 65 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 lib/librte_ether/rte_class_eth.c
lib/Makefile +1 -1
@@ -20,7 +20,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline DEPDIRS-librte_cmdline := librte_eal DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring -DEPDIRS-librte_ether += librte_mbuf +DEPDIRS-librte_ether += librte_mbuf librte_kvargs DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
lib/librte_ether/Makefile +2 -1
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf +LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.c
lib/librte_ether/rte_class_eth.c new file +65 -0
65 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH v2 17/18 ethdev: add device matching field name
In reply to Gaetan RivetThe 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 | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
lib/librte_ether/rte_class_eth.c +16 -2
@@ -14,11 +14,25 @@#include "rte_ethdev_core.h" static int +eth_dev_str_cmp(const char *key __rte_unused, +const char *value, +void *_str) +{ +const char *str = _str; + +return strcmp (str, value); +} + +static int eth_dev_match (struct rte_eth_dev *edev,struct rte_kvargs *kvlist) { - (void ) kvlist; - (void ) edev; +struct rte_eth_dev_data *data; + + data = edev->data; +if (rte_kvargs_process (kvlist,"name" , + ð_dev_str_cmp, data->name)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v2 18/18 app/testpmd: add show device command
In reply to Gaetan RivetA 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
@@ -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
Quoted 91 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_busandrte_classnow offer a way to
list their devices and filter the result
using locally defined properties.* The
rte_devAPI now has anrte_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_ethare 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_iteratecallback to simplify
its implementation.Now
dev_iterateimplementation do not need to learn about the intricacies of therte_dev_iterator. Therte_dev_iteratoris managed purely by therte_dev_iterator_nextfunction. Buses and classes then do not have to care about settings things right.Additionally,
dev_iterateimplementations do not have to sanitize their dev string anymore, they are prepared by therte_devlayer prior, which also reduces the number of dynamic allocations.Gaetan Rivet (18):
eal: introduce dtor macros
eal: introduce device class abstraction eal/class: register destructor
eal: add lightweight kvarg parsing utility eal/dev: add device iterator interface eal/class: add device iteration
eal/bus: add device iteration
eal/dev: implement device iteration initialization eal/dev: implement device iteration bus/pci: fix find device implementation bus/pci: implement device iteration and comparison bus/pci: add device matching field id bus/vdev: fix find device implementation bus/vdev: implement device iteration bus/vdev: add device matching field driver
ethdev: register ether layer as a class
ethdev: add device matching field name app/testpmd: add show device commandapp/test-pmd/cmdline.c | 52 ++++++ drivers/bus/pci/Makefile | 2 +- drivers/bus/pci/pci_common.c | 77 ++++++++- drivers/bus/pci/rte_bus_pci.h | 3 + drivers/bus/vdev/Makefile | 2 +- drivers/bus/vdev/rte_bus_vdev.h | 3 + drivers/bus/vdev/vdev.c | 66 +++++++- lib/Makefile | 2 +- lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/Makefile | 2 +- lib/librte_eal/common/eal_common_class.c | 62 +++++++ lib/librte_eal/common/eal_common_dev.c | 255 +++++++++++++++++++++++++++++ lib/librte_eal/common/eal_private.h | 34 ++++ lib/librte_eal/common/include/rte_bus.h | 1 + lib/librte_eal/common/include/rte_class.h | 127 ++++++++++++++ lib/librte_eal/common/include/rte_common.h | 23 +++ lib/librte_eal/common/include/rte_dev.h | 95 +++++++++++
Quoted 9 lines
lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 4 + lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 79 +++++++++ 21 files changed, 875 insertions(+), 19 deletions(-) create mode 100644 lib/librte_eal/common/eal_common_class.c create mode 100644 lib/librte_eal/common/include/rte_class.h create mode 100644 lib/librte_ether/rte_class_eth.c
Not seeing any meson.build files in the list above, but plenty of makefiles. :-)
v3 cover Device querying
In reply to Gaetan RivetThis patchset introduces a new EAL API for querying devices, filtered by arbitrary properties.
The following elements are introduced to this end:
* A new object, "rte_class", is used to describe the device class abstraction layer (eth, crypto, ...).
* Both rte_bus and rte_class now offer a way to
list their devices and filter the result
using locally defined properties.
* The rte_dev API now has an rte_dev_iterator, which is the way for the user to define the device filter and iterate upon the resulting set.
As an example, the "eth" device class is implemented.
Additionally, the device filters for
+ rte_bus_pci
+ rte_bus_vdev
+ rte_class_eth
are implemented and can be used with some
properties each, to show how to extend those.
Some example of filters:
"bus=pci/class=eth"
"bus=pci"
"class=eth"
"class=eth,name=net_ring0"
"bus=pci,id=00:00.0"
"bus=vdev,driver=net_ring"
---
v2:
* Reworked the dev_iterate callback to simplify
its implementation.
Now dev_iterate implementation do not need to learn about the intricacies of the rte_dev_iterator. The rte_dev_iterator is managed purely by the rte_dev_iterator_next function. Buses and classes then do not have to care about settings things right.
Additionally, dev_iterate implementations do not have to sanitize their dev string anymore, they are prepared by the rte_dev layer prior, which also reduces the number of dynamic allocations.
v3:
* Introduced central constructor priority list.
* Removed lightweight kvarg parsing utility,
using librte_kvargs instead.
* Reversed dependencies of librte_kvargs and
librte_eal.
* Fixed a few bugs.
Cc: Bruce Richardson <[email protected]>
* @Bruce: I have noted the request for meson support.
I will install it and attempt it once the bulk of the work is done.
Gaetan Rivet (20):
kvargs: remove rte log dependency
kvargs: build before EAL
eal: list acceptable init priorities
eal: introduce dtor macros
eal: introduce device class abstraction eal/class: register destructor
eal/dev: add device iterator interface eal/class: add device iteration
eal/bus: add device iteration
eal/dev: implement device iteration initialization eal/dev: implement device iteration bus/pci: fix find device implementation bus/pci: implement device iteration and comparison bus/pci: add device matching field id bus/vdev: fix find device implementation bus/vdev: implement device iteration bus/vdev: add device matching field driver
ethdev: register ether layer as a class
ethdev: add device matching field name app/testpmd: add show device command
app/test-pmd/cmdline.c | 52 ++++
drivers/bus/pci/Makefile | 2 +-
drivers/bus/pci/pci_common.c | 77 ++++-
drivers/bus/pci/rte_bus_pci.h | 3 +
drivers/bus/vdev/Makefile | 2 +-
drivers/bus/vdev/rte_bus_vdev.h | 3 +
drivers/bus/vdev/vdev.c | 66 ++++-
lib/Makefile | 6 +-
lib/librte_eal/bsdapp/eal/Makefile | 2 +
lib/librte_eal/common/Makefile | 4 +-
lib/librte_eal/common/eal_common_class.c | 62 ++++
lib/librte_eal/common/eal_common_dev.c | 317 +++++++++++++++++++++
lib/librte_eal/common/eal_common_log.c | 2 +-
lib/librte_eal/common/include/rte_bus.h | 3 +-
lib/librte_eal/common/include/rte_class.h | 127 +++++++++
lib/librte_eal/common/include/rte_common.h | 32 ++-
lib/librte_eal/common/include/rte_dev.h | 95 ++++++
lib/librte_eal/linuxapp/eal/Makefile | 2 +
lib/librte_eal/rte_eal_version.map | 4 +
lib/librte_ether/Makefile | 3 +-
lib/librte_ether/rte_class_eth.c | 79 +++++
lib/librte_kvargs/Makefile | 2 +-
lib/librte_kvargs/rte_kvargs.c | 13 +-
.../include => librte_kvargs}/rte_string_fns.h | 0
24 files changed, 925 insertions(+), 33 deletions(-)
create mode 100644 lib/librte_eal/common/eal_common_class.c
create mode 100644 lib/librte_eal/common/include/rte_class.h
create mode 100644 lib/librte_ether/rte_class_eth.c
rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)Signature · 1 line
2.11.0
PATCH v3 1/20 kvargs: remove rte log dependency
--- lib/librte_kvargs/rte_kvargs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
lib/librte_kvargs/rte_kvargs.c +5 -5
@@ -3,10 +3,10 @@* Copyright(c) 2014 6WIND S.A. */ +#include <stdio.h> #include <string.h> #include <stdlib.h> -#include <rte_log.h> #include <rte_string_fns.h> #include "rte_kvargs.h"
@@ -29,7 +29,7 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)*/ kvlist->str =strdup (params);if (kvlist->str ==NULL ) { -RTE_LOG (ERR ,PMD ,"Cannot parse arguments: not enough memory\n" ); +fprintf (stderr,"Cannot parse arguments: not enough memory\n" );return -1 ; }
@@ -39,14 +39,14 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params) i = kvlist->count;if (i >=RTE_KVARGS_MAX ) { -RTE_LOG (ERR ,PMD ,"Cannot parse arguments: list full\n" ); +fprintf (stderr,"Cannot parse arguments: list full\n" );return -1 ; } kvlist->pairs[i].key =strtok_r (str,RTE_KVARGS_KV_DELIM , &ctx2); kvlist->pairs[i].value =strtok_r (NULL ,RTE_KVARGS_KV_DELIM , &ctx2);if (kvlist->pairs[i].key ==NULL || kvlist->pairs[i].value ==NULL ) { -RTE_LOG (ERR ,PMD , +fprintf (stderr,"Cannot parse arguments: wrong key or value\n" "params=<%s>\n" , params);return -1 ;
@@ -90,7 +90,7 @@ check_for_valid_keys(struct rte_kvargs *kvlist, pair = &kvlist->pairs[i]; ret =is_valid_key (valid, pair->key);if (!ret) { -RTE_LOG (ERR ,PMD , +fprintf (stderr,"Error parsing device, invalid key <%s>\n" , pair->key);return -1 ;
Signature · 1 line
2.11.0
Re: [PATCH v3 01/20] kvargs: remove rte log dependency
Quoted 22 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/librte_kvargs/rte_kvargs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)lib/librte_kvargs/rte_kvargs.c +1
-1@@ -3,10 +3,10 @@* Copyright(c) 2014 6WIND S.A. */ +#include <stdio.h> #include <string.h> #include <stdlib.h> -#include <rte_log.h> #include <rte_string_fns.h> #include "rte_kvargs.h"
lib/librte_kvargs/rte_kvargs.c rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params) · line 35
Quoted 8 lines
lib/librte_kvargs/rte_kvargs.c +1
-1@@ -29,7 +29,7 @@ rte_kvargs_tokenize(struct rte_kvargs *kvlist, const char *params)*/ kvlist->str =strdup (params);if (kvlist->str ==NULL ) { -RTE_LOG (ERR ,PMD ,"Cannot parse arguments: not enough memory\n" ); +fprintf (stderr,"Cannot parse arguments: not enough memory\n" );return -1 ; }
I'm not entirely sure why any of this is needed. RTE_LOG is basically a wrapper around rte_vlog, which has this block of code:
if (f == NULL) {
f = default_log_stream;
if (f == NULL) {
/*
* Grab the current value of stderr here, rather than
* just initializing default_log_stream to stderr. This
* ensures that we will always use the current value
* of stderr, even if the application closes and
* reopens it.
*/
f = stderr;
}
}
}It seems to me that if rte_log_openstream hasn't been called yet, we should just dump messages to stderr, just like Keith noted in his other email. If thats not working, thats definately a problem, but regardless, you should be able to use RTE_LOG in your code without issue.
Neil
PATCH v3 2/20 kvargs: build before EAL
In reply to Gaetan Rivet---
lib/Makefile | 3 +--
lib/librte_eal/common/Makefile | 2 +-
lib/librte_kvargs/Makefile | 2 +-
lib/librte_kvargs/rte_kvargs.c | 3 +--
lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0
5 files changed, 4 insertions(+), 6 deletions(-)
rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)lib/Makefile +1 -2
@@ -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
@@ -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 +1 -1
@@ -37,7 +37,6 @@ include $(RTE_SDK)/mk/rte.vars.mk LIB = librte_kvargs.a CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3 -LDLIBS += -lrte_eal EXPORT_MAP := rte_kvargs_version.map
@@ -48,6 +47,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_KVARGS) := rte_kvargs.c # install includes INCS := rte_kvargs.h +INCS += rte_string_fns.h SYMLINK-$(CONFIG_RTE_LIBRTE_KVARGS)-include := $(INCS) include $(RTE_SDK)/mk/rte.lib.mk
lib/librte_kvargs/rte_kvargs.c +1 -2
@@ -7,8 +7,7 @@#include <string.h> #include <stdlib.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
Signature · 1 line
2.11.0
Re: [PATCH v3 02/20] kvargs: build before EAL
Quoted 10 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/Makefile | 3 +-- lib/librte_eal/common/Makefile | 2 +- lib/librte_kvargs/Makefile | 2 +- lib/librte_kvargs/rte_kvargs.c | 3 +-- lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0 5 files changed, 4 insertions(+), 6 deletions(-) rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)
Don't forget to update the meson.build file. You need to move kvargs before EAL in the list of libraries, and modify the special case for default dependencies for non-EAL libs.
/Bruce
Re: [PATCH v3 02/20] kvargs: build before EAL
Quoted 11 lines · Bruce Richardson
Quoted 10 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/Makefile | 3 +-- lib/librte_eal/common/Makefile | 2 +- lib/librte_kvargs/Makefile | 2 +- lib/librte_kvargs/rte_kvargs.c | 3 +-- lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h | 0 5 files changed, 4 insertions(+), 6 deletions(-) rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)
Quoted 5 lines
Don't forget to update the meson.build file. You need to move kvargs before EAL in the list of libraries, and modify the special case for default dependencies for non-EAL libs.
/Bruce
Sure, I will tackle meson build once everything is a little more stable.
I'm not at all convinced by this librte_kvargs move, these two patches are verging on RFC.
Once I know where everything will be, I will complete the build support.
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH v3 3/20 eal: list acceptable init priorities
In reply to Gaetan RivetBuild 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
@@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = { };/* Logging should be first initializer (before drivers and bus) */ -RTE_INIT_PRIO (rte_log_init,101 ); +RTE_INIT_PRIO (rte_log_init,LOG );static void rte_log_init (void ) {
lib/librte_eal/common/include/rte_bus.h +1 -1
@@ -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
@@ -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
Re: [PATCH v3 03/20] eal: list acceptable init priorities
Quoted 8 lines
-----Original Message-----
From: dev [mailto:[email protected]] On Behalf Of Gaetan Rivet
Sent: Tuesday, March 27, 2018 4:48 AM
To: [email protected]
Cc: Gaetan Rivet <[email protected]>
Subject: [dpdk-dev] [PATCH v3 03/20] eal: list acceptable init priorities
Quoted 7 lines
Build a central list to quickly see each used priorities for constructors, allowing to verify that they are both above 100 and in the proper order.
Signed-off-by Gaetan Rivet <[email protected]>Acked-by Neil Horman <[email protected]>---
PATCH v3 4/20 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
@@ -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
PATCH v3 5/20 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -215,6 +215,8 @@ EXPERIMENTAL { global: rte_eal_cleanup; + rte_class_register; + rte_class_unregister; rte_eal_devargs_insert; rte_eal_devargs_parse; rte_eal_devargs_remove;
Signature · 1 line
2.11.0
Re: [PATCH v3 05/20] eal: introduce device class abstraction
Quoted 13 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- 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.ccreate mode 100644lib/librte_eal/common/include/rte_class.h
[...]
Quoted 12 lines
lib/librte_eal/common/include/rte_class.h new file +12
-0+ +/** +* Class iterator to find a particular class. +* +* This function compares each registered class to find one that matches +* the data passed as parameter. +* +* If the comparison function returns zero this function will stop iterating +* over any more classes. To continue a search the class of a previous search +* can be passed via the start parameter. +* +* @param start
lib/librte_eal/common/include/rte_class.h line 72
Quoted 10 lines
lib/librte_eal/common/include/rte_class.h new file +10
-0+* Starting point for the iteration. +* +* @param cmp +* Comparison function. +* +* @param data +* Data to pass to comparison function. +* +* @return +* A pointer to a rte_bus structure or NULL in case no class matches
Trivial: ^^^^^^^^
Should be rte_class
[...]
-
Shreyansh
Re: [PATCH v3 05/20] eal: introduce device class abstraction
Quoted 34 lines · Shreyansh Jain
Quoted 13 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- 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.ccreate mode 100644lib/librte_eal/common/include/rte_class.h[...]
Quoted 17 lines
lib/librte_eal/common/include/rte_class.h new file +17
-0+ +/** +* Class iterator to find a particular class. +* +* This function compares each registered class to find one that matches +* the data passed as parameter. +* +* If the comparison function returns zero this function will stop iterating +* over any more classes. To continue a search the class of a previous search +* can be passed via the start parameter. +* +* @param start +* Starting point for the iteration. +* +* @param cmp +* Comparison function. +*
Quoted 8 lines
Quoted 5 lines
+ * @param data
+ * Data to pass to comparison function.
+ *
+ * @return
+ * A pointer to arte_busstructure or NULL in case no class matchesTrivial: ^^^^^^^^
Should berte_class
Thanks, will fix.
Quoted 5 lines
[...]
-
Shreyansh
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH v3 6/20 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
@@ -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
Re: [PATCH v3 06/20] eal/class: register destructor
Quoted 12 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/librte_eal/common/include/rte_class.h | 5 +++++ 1 file changed, 5 insertions(+)lib/librte_eal/common/include/rte_class.h +0
-0@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \ {\
lib/librte_eal/common/include/rte_class.h static void classinitfn_ ##nm(void) \ · line 122
Quoted 10 lines
lib/librte_eal/common/include/rte_class.h +5
-0(cls).name =RTE_STR (nm);\rte_class_register (&cls); \ +} \ +RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \ +static void classfinifn_ ##nm(void) \ +{ \ + rte_class_unregister(&cls); \ }#ifdef __cplusplus
I think this can be merged with the Patch 05/20 - isn't it?
Re: [PATCH v3 06/20] eal/class: register destructor
Hi Shreyansh,
Quoted 16 lines · Shreyansh Jain
Quoted 15 lines · Gaetan Rivet
Signed-off-by Gaetan Rivet <[email protected]>--- lib/librte_eal/common/include/rte_class.h | 5 +++++ 1 file changed, 5 insertions(+)lib/librte_eal/common/include/rte_class.h +2
-0@@ -112,6 +112,11 @@ static void classinitfn_ ##nm(void) \ {\ (cls).name =RTE_STR (nm);\rte_class_register (&cls); \ +} \ +RTE_FINI_PRIO(classfinifn_ ##nm, CLASS); \
Quoted 8 lines
lib/librte_eal/common/include/rte_class.h static void classinitfn_ ##nm(void) \
Quoted 6 lines
lib/librte_eal/common/include/rte_class.h +3
-0+static void classfinifn_ ##nm(void) \ +{ \ + rte_class_unregister(&cls); \ }#ifdef __cplusplusI think this can be merged with the Patch 05/20 - isn't it?
Absolutely, I only separated it as I wasn't sure for the dtor patch itself.
If the dtors are accepted, this patch can be merged with the previous patch.
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH v3 7/20 eal/dev: add device iterator interface
In reply to Gaetan RivetA 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
@@ -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
PATCH v3 8/20 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
@@ -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
PATCH v3 9/20 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
@@ -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
PATCH v3 10/20 eal/dev: implement device iteration initialization
In reply to Gaetan RivetParse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.
---
This version uses librte_kvargs.
lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)
lib/Makefile +1 -0
@@ -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
@@ -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 +147 -0
159 lines not on this page · raw message
lib/librte_eal/common/include/rte_dev.h +23 -0
@@ -310,6 +310,29 @@ typedef void *(*rte_dev_iterate_t)(const void *start,const char *devstr, const struct rte_dev_iterator *it); +/** +* Initializes a device iterator. +* +* This iterator allows accessing a list of devices matching a criteria. +* The device matching is made among all buses and classes currently registered, +* filtered by the device description given as parameter. +* +* This function will not allocate any memory. It is safe to stop the +* iteration at any moment and let the iterator go out of context. +* +* @param it +* Device iterator handle. +* +* @param str +* Device description string. +* +* @return +* 0 on successful initialization. +* <0 on error. +*/ +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); + #ifdef __cplusplus }#endif
lib/librte_eal/linuxapp/eal/Makefile +1 -0
@@ -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
@@ -228,6 +228,7 @@ EXPERIMENTAL { rte_mp_sendmsg; rte_mp_request; rte_mp_reply; + rte_dev_iterator_init; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 67 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +1
-0@@ -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_ringlib/librte_eal/bsdapp/eal/Makefile +1
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3 LDLIBS += -lexecinfo LDLIBS += -lpthread LDLIBS += -lgcc_s +LDLIBS += -lrte_kvargs EXPORT_MAP := ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +6
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s)
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 10 lines
lib/librte_eal/common/eal_common_dev.c +10
-0+{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ; + s++; + } +return i; +} +
So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Otherwise, this looks pretty good to me
Neil
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 73 lines · Neil Horman
Quoted 72 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +1
-0@@ -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_ringlib/librte_eal/bsdapp/eal/Makefile +1
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3 LDLIBS += -lexecinfo LDLIBS += -lpthread LDLIBS += -lgcc_s +LDLIBS += -lrte_kvargs EXPORT_MAP := ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +11
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ;
Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c +5
-0+ s++; + } +return i; +} +So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Will do.
Quoted 2 lines
Otherwise, this looks pretty good to me
Please look into the librte_kvargs compatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer on rte_log with the proper loglevels and so on.
Ideally rte_log could be made independent (starting skimming EAL from all the fat), but this is much less trivial.
This implementation relies on librte_kvargs being available. If this is not the case, there isn't much point to it.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 83 lines · Gaëtan Rivet
Quoted 73 lines · Neil Horman
Quoted 72 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +1
-0@@ -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_ringlib/librte_eal/bsdapp/eal/Makefile +1
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3 LDLIBS += -lexecinfo LDLIBS += -lpthread LDLIBS += -lgcc_s +LDLIBS += -lrte_kvargs EXPORT_MAP := ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +11
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ;Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c +5
-0+ s++; + } +return i; +} +So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Quoted 2 lines
Will do.
Answered too quickly.
No, this function only counts the number of occurences of '/' in the text.
strtok could be used however in the main function. Will see for a simpler implementation using it.
Quoted 16 lines
Quoted 2 lines
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.This implementation relies on
librte_kvargsbeing available. If this is not the case, there isn't much point to it.Signature · 2 lines
Gaëtan Rivet 6WIND
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 87 lines · Gaëtan Rivet
Quoted 83 lines · Gaëtan Rivet
Quoted 73 lines · Neil Horman
Quoted 72 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +1
-0@@ -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_ringlib/librte_eal/bsdapp/eal/Makefile +1
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3 LDLIBS += -lexecinfo LDLIBS += -lpthread LDLIBS += -lgcc_s +LDLIBS += -lrte_kvargs EXPORT_MAP := ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +11
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ;Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c +5
-0+ s++; + } +return i; +} +So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Quoted 2 lines
Will do.
Quoted 7 lines
Answered too quickly.
No, this function only counts the number of occurences of '/' in the text.strtok could be used however in the main function. Will see for a simpler implementation using it.
After a few tries, I see no benefit in using strtok.
The original const text must still be tokenized, strtok would modify it.
Duplicating would force finding the references in the original text, which would make the code as complex as it is now.
Quoted 20 lines
Quoted 16 lines
Quoted 2 lines
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.This implementation relies on
librte_kvargsbeing available. If this is not the case, there isn't much point to it.Signature · 2 lines
Gaëtan Rivet 6WINDSignature · 2 lines
Gaëtan Rivet 6WIND
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 96 lines · Gaëtan Rivet
Quoted 87 lines · Gaëtan Rivet
Quoted 83 lines · Gaëtan Rivet
Quoted 73 lines · Neil Horman
Quoted 72 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +1
-0@@ -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_ringlib/librte_eal/bsdapp/eal/Makefile +1
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3 LDLIBS += -lexecinfo LDLIBS += -lpthread LDLIBS += -lgcc_s +LDLIBS += -lrte_kvargs EXPORT_MAP := ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +11
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ;Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c +5
-0+ s++; + } +return i; +} +So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Quoted 2 lines
Will do.
Quoted 7 lines
Answered too quickly.
No, this function only counts the number of occurences of '/' in the text.strtok could be used however in the main function. Will see for a simpler implementation using it.
Quoted 6 lines
After a few tries, I see no benefit in using strtok.
The original const text must still be tokenized, strtok would modify it.Duplicating would force finding the references in the original text, which would make the code as complex as it is now.
Oh, if you don't want to modify the string, then index() is what you want. see man 3 index, or man 3 rindex
Neil
Quoted 25 lines
Quoted 20 lines
Quoted 16 lines
Quoted 2 lines
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.This implementation relies on
librte_kvargsbeing available. If this is not the case, there isn't much point to it.Signature · 2 lines
Gaëtan Rivet 6WINDSignature · 2 lines
Gaëtan Rivet 6WINDSignature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 100 lines · Neil Horman
Quoted 99 lines · Gaëtan Rivet
Quoted 87 lines · Gaëtan Rivet
Quoted 83 lines · Gaëtan Rivet
Quoted 73 lines · Neil Horman
Quoted 72 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +1
-0@@ -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_ringlib/librte_eal/bsdapp/eal/Makefile +1
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3 LDLIBS += -lexecinfo LDLIBS += -lpthread LDLIBS += -lgcc_s +LDLIBS += -lrte_kvargs EXPORT_MAP := ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +11
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ;Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c +5
-0+ s++; + } +return i; +} +So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Quoted 2 lines
Will do.
Quoted 7 lines
Answered too quickly.
No, this function only counts the number of occurences of '/' in the text.strtok could be used however in the main function. Will see for a simpler implementation using it.
After a few tries, I see no benefit in using strtok.
The original const text must still be tokenized, strtok would modify it.
Quoted 8 lines
Quoted 3 lines
Duplicating would force finding the references in the original text, which would make the code as complex as it is now.
Oh, if you don't want to modify the string, then
index()is what you want. see man 3 index, or man 3 rindexNeil
strchr is already used when necessary, and index is removed since POSIX.1-2008.
Thanks for the suggestions, it was still helpful to go over the code and see if there were possible improvements.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
In reply to Gaëtan RivetQuoted 90 lines · Gaëtan Rivet
Quoted 73 lines · Neil Horman
Quoted 72 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +0
-0@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mkDIRS-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_ringlib/librte_eal/bsdapp/eal/Makefile +0
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3LDLIBS += -lexecinfo
LDLIBS += -lpthread
LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
EXPORT_MAP:= ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +11
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ;Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c +5
-0+ s++; + } +return i; +} +So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Will do.
Quoted 1 line
Quoted 8 lines
Quoted 1 line
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.
I thought RTE_LOG was setup correctly using defaults, some changes after I looked at must have changed that behavior I guess. That needs to be address at some point IMO, but not in this patch set.
Quoted 3 lines
This implementation relies on
librte_kvargsbeing available. If this is not the case, there isn't much point to it.
Looked at the kvargs change and does look correct, but the above needs to be addressed or it will not be logged for normal usage of kvargs. I would have expected RTE_LOG to be able to handle the case of being called before it is inited and just use stderr. It needs to be looked at.
Quoted 4 lines
Signature · 3 lines
-- Gaëtan Rivet 6WIND
Regards,
Keith
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
In reply to Gaëtan RivetQuoted 86 lines · Gaëtan Rivet
Quoted 73 lines · Neil Horman
Quoted 72 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +1
-0@@ -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_ringlib/librte_eal/bsdapp/eal/Makefile +1
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3 LDLIBS += -lexecinfo LDLIBS += -lpthread LDLIBS += -lgcc_s +LDLIBS += -lrte_kvargs EXPORT_MAP := ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +11
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ;Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 225
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c +5
-0+ s++; + } +return i; +} +So the above code really just counts the number characters in the string, omitting the delimiter character '/', right? If thats all you want to do, you can just use strtok and strnlen for that, cant you?
Will do.
Quoted 1 line
Quoted 9 lines
Quoted 1 line
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.
just posted about that. I agree with Keith, I don't think you should need that patch. RTE_LOG just calls rte_vlog which contains this code:
if (f == NULL) {
f = default_log_stream;
if (f == NULL) {
/*
* Grab the current value of stderr here, rather than
* just initializing default_log_stream to stderr. This
* ensures that we will always use the current value
* of stderr, even if the application closes and
* reopens it.
*/
f = stderr;
}
}
}Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library. Can you elaborate on what you ran into here?
Neil
Quoted 7 lines
This implementation relies on
librte_kvargsbeing available. If this is not the case, there isn't much point to it.Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 42 lines · Neil Horman
Quoted 14 lines · Gaëtan Rivet
Quoted 13 lines · Neil Horman
Quoted 11 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.Quoted 9 lines
Quoted 1 line
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.just posted about that. I agree with Keith, I don't think you should need that patch.
RTE_LOGjust callsrte_vlogwhich contains this code:if (f == NULL) { f = default_log_stream; if (f == NULL) { /* * Grab the current value of stderr here, rather than * just initializing default_log_stream to stderr. This * ensures that we will always use the current value * of stderr, even if the application closes and * reopens it. */ f = stderr; } } }
Quoted 6 lines
Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library. Can you elaborate on what you ran into here?
Neil
Neat. The issue is that rte_log.h is not symlink-ed until librte_eal is processed. rte_log cannot be included.
I know Keith and Bruce discussed a few months back the possibility of having an initial linking pass. Personally I am still against this kind of solution, hiding design issues under the rug.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 48 lines · Gaëtan Rivet
Quoted 47 lines · Neil Horman
Quoted 14 lines · Gaëtan Rivet
Quoted 13 lines · Neil Horman
Quoted 11 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.Quoted 9 lines
Quoted 1 line
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.just posted about that. I agree with Keith, I don't think you should need that patch.
RTE_LOGjust callsrte_vlogwhich contains this code:if (f == NULL) { f = default_log_stream; if (f == NULL) { /* * Grab the current value of stderr here, rather than * just initializing default_log_stream to stderr. This * ensures that we will always use the current value * of stderr, even if the application closes and * reopens it. */ f = stderr; } } }Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library. Can you elaborate on what you ran into here?
Quoted 5 lines
Quoted 1 line
Neil
Neat. The issue is that
rte_log.his not symlink-ed untillibrte_ealis processed.rte_logcannot be included.
Sure it can - just pass -I/path/to/eal as a cflag.
/Bruce
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 49 lines · Bruce Richardson
Quoted 48 lines · Gaëtan Rivet
Quoted 47 lines · Neil Horman
Quoted 14 lines · Gaëtan Rivet
Quoted 13 lines · Neil Horman
Quoted 11 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
This version uses
librte_kvargs.Quoted 9 lines
Quoted 1 line
Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack.
There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.just posted about that. I agree with Keith, I don't think you should need that patch.
RTE_LOGjust callsrte_vlogwhich contains this code:if (f == NULL) { f = default_log_stream; if (f == NULL) { /* * Grab the current value of stderr here, rather than * just initializing default_log_stream to stderr. This * ensures that we will always use the current value * of stderr, even if the application closes and * reopens it. */ f = stderr; } } }Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library. Can you elaborate on what you ran into here?
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Neil
Neat. The issue is that
rte_log.his not symlink-ed untillibrte_ealis processed.rte_logcannot be included.Sure it can - just pass -I/path/to/eal as a cflag.
/Bruce
When you put it this way... :)
Sure, this is a solution, of which early symlink was a genericization. I'm just not a fan of having co-dependent libraries.
But this will probably come to that.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 74 lines
-----Original Message-----
From: Gaëtan Rivet [mailto:[email protected]]
Sent: Tuesday, March 27, 2018 9:35 PM
To: Richardson, Bruce <[email protected]>
Cc: Neil Horman <[email protected]>; [email protected]; Wiles, Keith <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initializationQuoted 26 lines · Bruce Richardson
Quoted 25 lines · Gaëtan Rivet
Quoted 24 lines · Neil Horman
Quoted 23 lines · Gaëtan Rivet
Quoted 10 lines · Neil Horman
Quoted 9 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
Quoted 4 lines
Quoted 2 lines
This version uses
librte_kvargs.Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack. There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
just posted about that. I agree with Keith, I don't think you should need that patch.
RTE_LOGjust callsrte_vlogwhich containsthis code:
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
if (f == NULL) { f = default_log_stream; if (f == NULL) { /* * Grab the current value of stderr here,rather than
Quoted 1 line
Quoted 1 line
Quoted 1 line
* just initializing
default_log_streamtostderr. This
Quoted 1 line
Quoted 1 line
Quoted 1 line
* ensures that we will always use the
current value
Quoted 1 line
Quoted 1 line
Quoted 1 line
* of stderr, even if the application closes
and
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
* reopens it. */ f = stderr; } } }Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library.
Can you elaborate on what you ran into here?
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
Neil
Neat. The issue is that
rte_log.his not symlink-ed untillibrte_ealis processed.rte_logcannot be included.Sure it can - just pass -I/path/to/eal as a cflag.
Quoted 9 lines
Quoted 1 line
/Bruce
When you put it this way... :)
Sure, this is a solution, of which early symlink was a genericization. I'm just not a fan of having co-dependent libraries.
But this will probably come to that.
The other alternative is what was done with rte_compat.h - create a new lib just with a single header file in it. Works ok too, and may seem less hacky to some folks.
/Bruce
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 81 lines · Bruce
Quoted 81 lines
-----Original Message-----
From: Gaëtan Rivet [mailto:[email protected]]
Sent: Tuesday, March 27, 2018 9:35 PM
To: Richardson, Bruce <[email protected]>
Cc: Neil Horman <[email protected]>; [email protected]; Wiles, Keith <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initializationQuoted 26 lines · Bruce Richardson
Quoted 25 lines · Gaëtan Rivet
Quoted 24 lines · Neil Horman
Quoted 23 lines · Gaëtan Rivet
Quoted 10 lines · Neil Horman
Quoted 9 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
Quoted 4 lines
Quoted 2 lines
This version uses
librte_kvargs.Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack. There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
just posted about that. I agree with Keith, I don't think you should need that patch.
RTE_LOGjust callsrte_vlogwhich containsthis code:
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
if (f == NULL) { f = default_log_stream; if (f == NULL) { /* * Grab the current value of stderr here,rather than
Quoted 1 line
Quoted 1 line
Quoted 1 line
* just initializing
default_log_streamtostderr. This
Quoted 1 line
Quoted 1 line
Quoted 1 line
* ensures that we will always use the
current value
Quoted 1 line
Quoted 1 line
Quoted 1 line
* of stderr, even if the application closes
and
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
* reopens it. */ f = stderr; } } }Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library.
Can you elaborate on what you ran into here?
Quoted 9 lines
Quoted 6 lines
Quoted 2 lines
Neil
Neat. The issue is that
rte_log.his not symlink-ed untillibrte_ealis processed.rte_logcannot be included.Sure it can - just pass -I/path/to/eal as a cflag.
/Bruce
When you put it this way... :)
Sure, this is a solution, of which early symlink was a genericization. I'm just not a fan of having co-dependent libraries.
Quoted 9 lines
Quoted 2 lines
But this will probably come to that.
The other alternative is what was done with
rte_compat.h- create a new lib just with a single header file in it. Works ok too, and may seem less hacky to some folks./Bruce
This seems like a good alternative to me. I'm not entirely sure why the logging functions are integrated to EAL anyway.
Neil
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 89 lines · Neil Horman
Quoted 88 lines · Bruce
Quoted 74 lines
-----Original Message-----
From: Gaëtan Rivet [mailto:[email protected]]
Sent: Tuesday, March 27, 2018 9:35 PM
To: Richardson, Bruce <[email protected]>
Cc: Neil Horman <[email protected]>; [email protected]; Wiles, Keith <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initializationQuoted 26 lines · Bruce Richardson
Quoted 25 lines · Gaëtan Rivet
Quoted 24 lines · Neil Horman
Quoted 23 lines · Gaëtan Rivet
Quoted 10 lines · Neil Horman
Quoted 9 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
Quoted 4 lines
Quoted 2 lines
This version uses
librte_kvargs.Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack. There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
just posted about that. I agree with Keith, I don't think you should need that patch.
RTE_LOGjust callsrte_vlogwhich containsthis code:
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
if (f == NULL) { f = default_log_stream; if (f == NULL) { /* * Grab the current value of stderr here,rather than
Quoted 1 line
Quoted 1 line
Quoted 1 line
* just initializing
default_log_streamtostderr. This
Quoted 1 line
Quoted 1 line
Quoted 1 line
* ensures that we will always use the
current value
Quoted 1 line
Quoted 1 line
Quoted 1 line
* of stderr, even if the application closes
and
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
* reopens it. */ f = stderr; } } }Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library.
Can you elaborate on what you ran into here?
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
Neil
Neat. The issue is that
rte_log.his not symlink-ed untillibrte_ealis processed.rte_logcannot be included.Sure it can - just pass -I/path/to/eal as a cflag.
Quoted 9 lines
Quoted 1 line
/Bruce
When you put it this way... :)
Sure, this is a solution, of which early symlink was a genericization. I'm just not a fan of having co-dependent libraries.
But this will probably come to that.
The other alternative is what was done with
rte_compat.h- create a new lib just with a single header file in it. Works ok too, and may seem less hacky to some folks.
Quoted 7 lines
Quoted 2 lines
/Bruce
This seems like a good alternative to me. I'm not entirely sure why the logging functions are integrated to EAL anyway.
Neil
As I said earlier:
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Ideally
rte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.
rte_log could certainly stand on its own. I quickly attempted to make it a library, but this is too much work at this point. I think the EAL should be broken down, it is too monolithic. Problem is that many other libraries / applications, now relies on parts of the EAL that would need to be moved.
So any effort in this direction will be difficult to undertake (and badly received by the community, with good reasons), especially when the workaround is an additional -I cflag.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
Quoted 109 lines · Gaëtan Rivet
Quoted 89 lines · Neil Horman
Quoted 88 lines · Bruce
Quoted 74 lines
-----Original Message-----
From: Gaëtan Rivet [mailto:[email protected]]
Sent: Tuesday, March 27, 2018 9:35 PM
To: Richardson, Bruce <[email protected]>
Cc: Neil Horman <[email protected]>; [email protected]; Wiles, Keith <[email protected]>
Subject: Re: [dpdk-dev] [PATCH v3 10/20] eal/dev: implement device iteration initializationQuoted 26 lines · Bruce Richardson
Quoted 25 lines · Gaëtan Rivet
Quoted 24 lines · Neil Horman
Quoted 23 lines · Gaëtan Rivet
Quoted 10 lines · Neil Horman
Quoted 9 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Cc Neil Horman <[email protected]>Cc "Wiles, Keith" <[email protected]>Signed-off-by Gaetan Rivet <[email protected]>---
Quoted 4 lines
Quoted 2 lines
This version uses
librte_kvargs.Otherwise, this looks pretty good to me
Please look into the
librte_kvargscompatibility patch as well (quite short). I'm very unhappy about the logging hack. There is always the solution of setting a function pointer onrte_logwith the proper loglevels and so on.
Ideallyrte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
just posted about that. I agree with Keith, I don't think you should need that patch.
RTE_LOGjust callsrte_vlogwhich containsthis code:
Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
if (f == NULL) { f = default_log_stream; if (f == NULL) { /* * Grab the current value of stderr here,rather than
Quoted 1 line
Quoted 1 line
Quoted 1 line
* just initializing
default_log_streamtostderr. This
Quoted 1 line
Quoted 1 line
Quoted 1 line
* ensures that we will always use the
current value
Quoted 1 line
Quoted 1 line
Quoted 1 line
* of stderr, even if the application closes
and
Quoted 11 lines
Quoted 11 lines
Quoted 11 lines
* reopens it. */ f = stderr; } } }Which I read as saying that the logging library should back off to stderr if its not initialized yet. If you've encountered a problem that made you need that logging patch, it seems like you should be able to drop it, and we need to fix the logging library.
Can you elaborate on what you ran into here?
Quoted 8 lines
Quoted 6 lines
Quoted 2 lines
Neil
Neat. The issue is that
rte_log.his not symlink-ed untillibrte_ealis processed.rte_logcannot be included.Sure it can - just pass -I/path/to/eal as a cflag.
Quoted 9 lines
Quoted 1 line
/Bruce
When you put it this way... :)
Sure, this is a solution, of which early symlink was a genericization. I'm just not a fan of having co-dependent libraries.
But this will probably come to that.
The other alternative is what was done with
rte_compat.h- create a new lib just with a single header file in it. Works ok too, and may seem less hacky to some folks.Quoted 7 lines
Quoted 2 lines
/Bruce
This seems like a good alternative to me. I'm not entirely sure why the logging functions are integrated to EAL anyway.
Neil
As I said earlier:
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Ideally
rte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.
rte_logcould certainly stand on its own. I quickly attempted to make it a library, but this is too much work at this point. I think the EAL should be broken down, it is too monolithic. Problem is that many other libraries / applications, now relies on parts of the EAL that would need to be moved.
Quoted 4 lines
So any effort in this direction will be difficult to undertake (and badly received by the community, with good reasons), especially when the workaround is an additional -I cflag.
I'm fine with just adding another include path to the CFLAGS for this purpose in the short term, just saying I'm not sure why the log library got integrated into EAL in the first place.
Neil
Quoted 4 lines
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v3 10/20] eal/dev: implement device iteration initialization
28/03/2018 13:17, Neil Horman:
Quoted 48 lines · Gaëtan Rivet
Quoted 43 lines · Neil Horman
Quoted 23 lines · Bruce
Quoted 22 lines
From: Gaëtan Rivet [mailto:[email protected]]
Quoted 7 lines · Bruce Richardson
Quoted 6 lines · Gaëtan Rivet
Quoted 3 lines
Neat. The issue is that
rte_log.his not symlink-ed untillibrte_ealis processed.rte_logcannot be included.Sure it can - just pass -I/path/to/eal as a cflag.
Quoted 9 lines
Quoted 1 line
/Bruce
When you put it this way... :)
Sure, this is a solution, of which early symlink was a genericization. I'm just not a fan of having co-dependent libraries.
But this will probably come to that.
The other alternative is what was done with
rte_compat.h- create a new lib just with a single header file in it. Works ok too, and may seem less hacky to some folks.Quoted 7 lines
Quoted 2 lines
/Bruce
This seems like a good alternative to me. I'm not entirely sure why the logging functions are integrated to EAL anyway.
Neil
As I said earlier:
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Quoted 2 lines
Ideally
rte_logcould be made independent (starting skimming EAL from all the fat), but this is much less trivial.
rte_logcould certainly stand on its own. I quickly attempted to make it a library, but this is too much work at this point. I think the EAL should be broken down, it is too monolithic. Problem is that many other libraries / applications, now relies on parts of the EAL that would need to be moved.Quoted 4 lines
So any effort in this direction will be difficult to undertake (and badly received by the community, with good reasons), especially when the workaround is an additional -I cflag.
Quoted 5 lines
I'm fine with just adding another include path to the CFLAGS for this purpose in the short term, just saying I'm not sure why the log library got integrated into EAL in the first place.
Neil
The log functions must be in EAL because they are different per-environment. The basic functions are the reason of EAL.
I think the problem is somewhere else: we are trying to implemement the complex device logic in EAL.
We should move all the bus and device logics outside of EAL, in my opinion. We should also move all the options parsing outside of EAL, and make it optional.
Anyway, these are considerations for the long run.
PATCH v3 11/20 eal/dev: implement device iteration
In reply to Gaetan RivetUse 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 | 170 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 25 +++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 196 insertions(+)
lib/librte_eal/common/eal_common_dev.c +170 -0
@@ -20,6 +20,28 @@#include "eal_private.h" +struct dev_next_ctx { +struct rte_dev_iterator *it; +const char *busstr; +const char *clsstr; +}; + +#define CTX (it, busstr, clsstr) \ + (&(const struct dev_next_ctx){ \ + .it = it, \ + .busstr = busstr, \ + .clsstr = clsstr, \ + }) + +#define ITCTX (ptr) \ + (((struct dev_next_ctx *)(intptr_t)ptr)->it) + +#define BUSCTX (ptr) \ + (((struct dev_next_ctx *)(intptr_t)ptr)->busstr) + +#define CLSCTX (ptr) \ + (((struct dev_next_ctx *)(intptr_t)ptr)->clsstr) +static int cmp_detached_dev_name (const struct rte_device *dev,const void *_name) {
@@ -354,3 +376,151 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, }return -rte_errno; } + +/* '\0' forbidden in sym */ +static const char * +strfirstof (const char *str, +const char *sym) +{ +const char *s; + +for (s = str; s[0 ] !='\0' ; s++) { +const char *c; + +for (c = sym; c[0 ] !='\0' ; c++) { +if (c[0 ] == s[0 ]) +return s; + } + } +return NULL ; +} + +static char * +dev_str_sane_cpy (const char *str) +{ +const char *end; +char *copy; + + end =strfirstof (str,",/" ); +if (end !=NULL && + end[0 ] ==',' ) { + copy =strdup (end +1 ); + }else { +/* '/' or '\0' */ + copy =strdup ("" ); + } +if (copy ==NULL ) + rte_errno =ENOMEM ; +return copy; +} + +static int +class_next_dev_cmp (const struct rte_class *cls, +const void *ctx) +{ +struct rte_dev_iterator *it; +const char *clsstr =NULL ; +void *dev; + +if (cls->dev_iterate ==NULL ) +return 1 ; + it =ITCTX (ctx); + clsstr =CLSCTX (ctx); + dev = it->class_device; +/* it->clsstr != NULL means a class +* was specified in the devstr. +*/ +if (it->clsstr !=NULL && cls != it->cls) +return 1 ; + dev = cls->dev_iterate (dev, clsstr, it); + it->class_device = dev; +return dev ==NULL ; +} + +static int +bus_next_dev_cmp (const struct rte_bus *bus, +const void *ctx) +{ +struct rte_device *dev =NULL ; +struct rte_class *cls =NULL ; +struct rte_dev_iterator *it; +const char *busstr =NULL ; + +if (bus->dev_iterate ==NULL ) +return 1 ; + it =ITCTX (ctx); + busstr =BUSCTX (ctx); + dev = it->device; +/* it->busstr != NULL means a bus +* was specified in the devstr. +*/ +if (it->busstr !=NULL && bus != it->bus) +return 1 ; +if (it->clsstr ==NULL ) { + dev = bus->dev_iterate (dev, busstr, it); + goto end; + } +/* clsstr != NULL */ +if (dev ==NULL ) { +next_dev_on_bus: + dev = bus->dev_iterate (dev, busstr, it); + it->device = dev; + } +if (dev ==NULL ) +return 1 ; +if (it->cls !=NULL ) + cls =TAILQ_PREV (it->cls, rte_class_list, next); + cls =rte_class_find (cls, class_next_dev_cmp, ctx); +if (cls !=NULL ) { + it->cls = cls; + goto end; + } + goto next_dev_on_bus; +end: + it->device = dev; +return dev ==NULL ; +} +__rte_experimental +struct rte_device * +rte_dev_iterator_next (struct rte_dev_iterator *it) +{ +struct rte_bus *bus =NULL ; +int old_errno = rte_errno; +char *busstr =NULL ; +char *clsstr =NULL ; + + rte_errno =0 ; +if (it->busstr ==NULL && it->clsstr ==NULL ) { +/* Invalid iterator. */ + rte_errno =EINVAL ; +return NULL ; + } +if (it->bus !=NULL ) + bus =TAILQ_PREV (it->bus, rte_bus_list, next); +if (it->busstr !=NULL ) { + busstr =dev_str_sane_cpy (it->busstr); +if (busstr ==NULL ) + goto out; + } +if (it->clsstr !=NULL ) { + clsstr =dev_str_sane_cpy (it->clsstr); +if (clsstr ==NULL ) + goto out; + } +while ((bus =rte_bus_find (bus, bus_next_dev_cmp, +CTX (it, busstr, clsstr)))) { +if (it->device !=NULL ) { + it->bus = bus; + goto out; + } +if (it->busstr !=NULL || + rte_errno !=0 ) +break ; + } +if (rte_errno ==0 ) + rte_errno = old_errno; +out: +free (busstr); +free (clsstr); +return it->device; +}
lib/librte_eal/common/include/rte_dev.h +25 -0
@@ -333,6 +333,31 @@ typedef void *(*rte_dev_iterate_t)(const void *start, int __rte_experimentalrte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); +/** +* Iterates on a device iterator. +* +* Generates a new rte_device handle corresponding to the next element +* in the list described in comprehension by the iterator. +* +* The next object is returned, and the iterator is updated. +* +* @param it +* Device iterator handle. +* +* @return +* An rte_device handle if found. +* NULL if an error occurred (rte_errno is set). +* NULL if no device could be found (rte_errno is not set). +*/ +struct rte_device * __rte_experimental +rte_dev_iterator_next (struct rte_dev_iterator *it); + +#define RTE_DEV_FOREACH (dev, devstr, it) \ + for (rte_dev_iterator_init(it, devstr), \ + dev = rte_dev_iterator_next(it); \ + dev != NULL; \ + dev = rte_dev_iterator_next(it)) + #ifdef __cplusplus }#endif
lib/librte_eal/rte_eal_version.map +1 -0
@@ -229,6 +229,7 @@ EXPERIMENTAL { rte_mp_request; rte_mp_reply; rte_dev_iterator_init; + rte_dev_iterator_next; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
PATCH v3 12/20 bus/pci: fix find device implementation
In reply to Gaetan RivetIf 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.
--- 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
@@ -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
@@ -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
PATCH v3 13/20 bus/pci: implement device iteration and comparison
In reply to Gaetan Rivet--- drivers/bus/pci/Makefile | 2 +- drivers/bus/pci/pci_common.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-)
drivers/bus/pci/Makefile +1 -1
@@ -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 +34 -0
@@ -13,6 +13,7 @@#include <rte_errno.h> #include <rte_interrupts.h> +#include <rte_kvargs.h> #include <rte_log.h> #include <rte_bus.h> #include <rte_pci.h>
@@ -497,6 +498,38 @@ pci_unplug(struct rte_device *dev)return ret; } +static int +pci_dev_match (const struct rte_device *dev, +const void *_kvlist) +{ +const struct rte_kvargs *kvlist = _kvlist; + + (void ) dev; + (void ) kvlist; +return 0 ; +} + +static void * +pci_dev_iterate (const void *start, +const char *str, + const struct rte_dev_iterator *it __rte_unused) +{ +struct rte_device *dev; +struct rte_kvargs *kvargs =NULL ; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str,NULL ); +if (kvargs ==NULL ) { +RTE_LOG (ERR ,EAL ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } + dev =pci_find_device (start, pci_dev_match, kvargs); +rte_kvargs_free (kvargs); +return dev; +} +struct rte_pci_bus rte_pci_bus = { .bus = { .scan = rte_pci_scan,
@@ -506,6 +539,7 @@ struct rte_pci_bus rte_pci_bus = { .unplug = pci_unplug, .parse = pci_parse, .get_iommu_class = rte_pci_get_iommu_class, + .dev_iterate = pci_dev_iterate, }, .device_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.device_list), .driver_list = TAILQ_HEAD_INITIALIZER(rte_pci_bus.driver_list),
Signature · 1 line
2.11.0
PATCH v3 14/20 bus/pci: add device matching field id
In reply to Gaetan RivetThe 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 | 26 ++++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-)
drivers/bus/pci/pci_common.c +24 -2
@@ -499,13 +499,35 @@ pci_unplug(struct rte_device *dev) }static int +pci_addr_kv_cmp(const char *key __rte_unused, +const char *value, +void *_addr2) +{ +struct rte_pci_addr _addr1; +struct rte_pci_addr *addr1 = &_addr1; +struct rte_pci_addr *addr2 = _addr2; + +if (rte_pci_addr_parse (value, addr1)) +return -1 ; +return rte_pci_addr_cmp (addr1, addr2); +} + +static int pci_dev_match (const struct rte_device *dev,const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_pci_device *pdev; - (void ) dev; - (void ) kvlist; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + pdev =RTE_DEV_TO_PCI_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"id" , + &pci_addr_kv_cmp, + (void *)(intptr_t )&pdev->addr)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v3 15/20 bus/vdev: fix find device implementation
In reply to Gaetan RivetIf start is set and a device before it matches the data, this device is returned.
This induces potentially infinite loops.
--- 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
@@ -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
@@ -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
PATCH v3 16/20 bus/vdev: implement device iteration
In reply to Gaetan Rivet--- drivers/bus/vdev/Makefile | 2 +- drivers/bus/vdev/vdev.c | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-)
drivers/bus/vdev/Makefile +1 -1
@@ -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 +34 -0
@@ -43,6 +43,7 @@#include <rte_bus.h> #include <rte_common.h> #include <rte_devargs.h> +#include <rte_kvargs.h> #include <rte_memory.h> #include <rte_tailq.h> #include <rte_spinlock.h>
@@ -415,6 +416,38 @@ vdev_unplug(struct rte_device *dev)return rte_vdev_uninit (dev->name); } +static int +vdev_dev_match (const struct rte_device *dev, +const void *_kvlist) +{ +const struct rte_kvargs *kvlist = _kvlist; + + (void ) kvlist; + (void ) dev; +return 0 ; +} + +static void * +vdev_dev_iterate (const void *start, +const char *str, + const struct rte_dev_iterator *it __rte_unused) +{ +struct rte_kvargs *kvargs =NULL ; +struct rte_device *dev; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str,NULL ); +if (kvargs ==NULL ) { +VDEV_LOG (ERR ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } + dev =vdev_find_device (start, vdev_dev_match, kvargs); +rte_kvargs_free (kvargs); +return dev; +} +static struct rte_bus rte_vdev_bus = { .scan = vdev_scan, .probe = vdev_probe,
@@ -422,6 +455,7 @@ static struct rte_bus rte_vdev_bus = { .plug = vdev_plug, .unplug = vdev_unplug, .parse = vdev_parse, + .dev_iterate = vdev_dev_iterate, };RTE_REGISTER_BUS (vdev, rte_vdev_bus);
Signature · 1 line
2.11.0
PATCH v3 17/20 bus/vdev: add device matching field driver
In reply to Gaetan RivetThe vdev bus parses a field "driver", matching
a vdev driver name with one passed as follows:
"bus=vdev,driver=xxxx"
--- drivers/bus/vdev/vdev.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
drivers/bus/vdev/vdev.c +20 -2
@@ -417,13 +417,31 @@ vdev_unplug(struct rte_device *dev) }static int +vdev_str_kv_cmp(const char *key __rte_unused, +const char *value, +void *_str) +{ +const char *str = _str; + +return strcmp (str, value); +} + +static int vdev_dev_match (const struct rte_device *dev,const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_vdev_device *vdev; - (void ) kvlist; - (void ) dev; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + vdev =RTE_DEV_TO_VDEV_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"driver" , + &vdev_str_kv_cmp, + (void *)(intptr_t )vdev->device.driver->name)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v3 18/20 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 | 65 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 lib/librte_ether/rte_class_eth.c
lib/Makefile +1 -1
@@ -22,7 +22,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) += librte_cmdline DEPDIRS-librte_cmdline := librte_eal DIRS-$(CONFIG_RTE_LIBRTE_ETHER) += librte_ether DEPDIRS-librte_ether := librte_net librte_eal librte_mempool librte_ring -DEPDIRS-librte_ether += librte_mbuf +DEPDIRS-librte_ether += librte_mbuf librte_kvargs DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) += librte_bbdev DEPDIRS-librte_bbdev := librte_eal librte_mempool librte_mbuf DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) += librte_cryptodev
lib/librte_ether/Makefile +2 -1
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf +LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.c
lib/librte_ether/rte_class_eth.c new file +65 -0
65 lines not on this page · raw message
Signature · 1 line
2.11.0
PATCH v3 19/20 ethdev: add device matching field name
In reply to Gaetan RivetThe 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 | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
lib/librte_ether/rte_class_eth.c +16 -2
@@ -14,11 +14,25 @@#include "rte_ethdev_core.h" static int +eth_dev_str_cmp(const char *key __rte_unused, +const char *value, +void *_str) +{ +const char *str = _str; + +return strcmp (str, value); +} + +static int eth_dev_match (struct rte_eth_dev *edev,struct rte_kvargs *kvlist) { - (void ) kvlist; - (void ) edev; +struct rte_eth_dev_data *data; + + data = edev->data; +if (rte_kvargs_process (kvlist,"name" , + ð_dev_str_cmp, data->name)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v3 20/20 app/testpmd: add show device command
In reply to Gaetan RivetA 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
@@ -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
v4 cover Device querying
In reply to Gaetan RivetThis patchset introduces a new EAL API for querying devices, filtered by arbitrary properties.
The following elements are introduced to this end:
* A new object, "rte_class", is used to describe the device class abstraction layer (eth, crypto, ...).
* Both rte_bus and rte_class now offer a way to
list their devices and filter the result
using locally defined properties.
* The rte_dev API now has an rte_dev_iterator, which is the way for the user to define the device filter and iterate upon the resulting set.
As an example, the "eth" device class is implemented.
Additionally, the device filters for
+ rte_bus_pci
+ rte_bus_vdev
+ rte_class_eth
are implemented and can be used with some
properties each, to show how to extend those.
Some example of filters:
"bus=pci/class=eth"
"bus=pci"
"class=eth"
"class=eth,name=net_ring0"
"bus=pci,id=00:00.0"
"bus=vdev,driver=net_ring"
---
v2:
* Reworked the dev_iterate callback to simplify
its implementation.
Now dev_iterate implementation do not need to learn about the intricacies of the rte_dev_iterator. The rte_dev_iterator is managed purely by the rte_dev_iterator_next function. Buses and classes then do not have to care about settings things right.
Additionally, dev_iterate implementations do not have to sanitize their dev string anymore, they are prepared by the rte_dev layer prior, which also reduces the number of dynamic allocations.
v3:
* Introduced central constructor priority list.
* Removed lightweight kvarg parsing utility,
using librte_kvargs instead.
* Reversed dependencies of librte_kvargs and
librte_eal.
* Fixed a few bugs.
* @Bruce: I have noted the request for meson support.
I will install it and attempt it once the bulk of the work is done.
v4:
* Fixed a few bugs, added relevant acks,
fixed some typos.
* Made each matching functions actually check for a proper list of accepted properties.
* rte_kvargs now includes rte_eal directly and keeps rte_log.
* added generic string comparison function to rte_kvargs, as some kind of comparison should probably be shared by many layers.
Gaetan Rivet (20):
kvargs: build before EAL
eal: list acceptable init priorities
eal: introduce dtor macros
eal: introduce device class abstraction eal/class: register destructor
eal/dev: add device iterator interface eal/class: add device iteration
eal/bus: add device iteration
eal/dev: implement device iteration initialization eal/dev: implement device iteration
kvargs: add generic string matching callback bus/pci: fix find device implementation bus/pci: implement device iteration and comparison bus/pci: add device matching field id bus/vdev: fix find device implementation bus/vdev: implement device iteration bus/vdev: add device matching field driver
ethdev: register ether layer as a class
ethdev: add device matching field name app/testpmd: add show device command
app/test-pmd/cmdline.c | 52 ++++
drivers/bus/pci/Makefile | 2 +-
drivers/bus/pci/pci_common.c | 87 +++++-
drivers/bus/pci/rte_bus_pci.h | 3 +
drivers/bus/vdev/Makefile | 3 +-
drivers/bus/vdev/rte_bus_vdev.h | 3 +
drivers/bus/vdev/vdev.c | 66 +++-
lib/Makefile | 7 +-
lib/librte_eal/bsdapp/eal/Makefile | 2 +
lib/librte_eal/common/Makefile | 4 +-
lib/librte_eal/common/eal_common_class.c | 62 ++++
lib/librte_eal/common/eal_common_dev.c | 334 +++++++++++++++++++++
lib/librte_eal/common/eal_common_log.c | 2 +-
lib/librte_eal/common/include/rte_bus.h | 3 +-
lib/librte_eal/common/include/rte_class.h | 127 ++++++++
lib/librte_eal/common/include/rte_common.h | 32 +-
lib/librte_eal/common/include/rte_dev.h | 95 ++++++
lib/librte_eal/linuxapp/eal/Makefile | 2 +
lib/librte_eal/rte_eal_version.map | 4 +
lib/librte_ether/Makefile | 3 +-
lib/librte_ether/rte_class_eth.c | 79 +++++
lib/librte_kvargs/Makefile | 3 +-
lib/librte_kvargs/rte_kvargs.c | 12 +-
lib/librte_kvargs/rte_kvargs.h | 28 ++
lib/librte_kvargs/rte_kvargs_version.map | 7 +
.../include => librte_kvargs}/rte_string_fns.h | 0
26 files changed, 995 insertions(+), 27 deletions(-)
create mode 100644 lib/librte_eal/common/eal_common_class.c
create mode 100644 lib/librte_eal/common/include/rte_class.h
create mode 100644 lib/librte_ether/rte_class_eth.c
rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)Signature · 1 line
2.11.0
PATCH v4 1/20 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
@@ -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
@@ -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
@@ -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
@@ -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
Signature · 1 line
2.11.0
PATCH v4 2/20 eal: list acceptable init priorities
In reply to Gaetan RivetBuild 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
@@ -224,7 +224,7 @@ static const struct logtype logtype_strings[] = { };/* Logging should be first initializer (before drivers and bus) */ -RTE_INIT_PRIO (rte_log_init,101 ); +RTE_INIT_PRIO (rte_log_init,LOG );static void rte_log_init (void ) {
lib/librte_eal/common/include/rte_bus.h +1 -1
@@ -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
@@ -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
PATCH v4 3/20 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
@@ -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
PATCH v4 4/20 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -215,6 +215,8 @@ EXPERIMENTAL { global: rte_eal_cleanup; + rte_class_register; + rte_class_unregister; rte_eal_devargs_insert; rte_eal_devargs_parse; rte_eal_devargs_remove;
Signature · 1 line
2.11.0
PATCH v4 5/20 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
@@ -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
PATCH v4 6/20 eal/dev: add device iterator interface
In reply to Gaetan RivetA 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
@@ -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
PATCH v4 7/20 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
@@ -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
PATCH v4 8/20 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
@@ -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
PATCH v4 9/20 eal/dev: implement device iteration initialization
In reply to Gaetan RivetParse 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 | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)
lib/Makefile +1 -0
@@ -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
@@ -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 +147 -0
159 lines not on this page · raw message
lib/librte_eal/common/include/rte_dev.h +23 -0
@@ -310,6 +310,29 @@ typedef void *(*rte_dev_iterate_t)(const void *start,const char *devstr, const struct rte_dev_iterator *it); +/** +* Initializes a device iterator. +* +* This iterator allows accessing a list of devices matching a criteria. +* The device matching is made among all buses and classes currently registered, +* filtered by the device description given as parameter. +* +* This function will not allocate any memory. It is safe to stop the +* iteration at any moment and let the iterator go out of context. +* +* @param it +* Device iterator handle. +* +* @param str +* Device description string. +* +* @return +* 0 on successful initialization. +* <0 on error. +*/ +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); + #ifdef __cplusplus }#endif
lib/librte_eal/linuxapp/eal/Makefile +1 -0
@@ -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
@@ -228,6 +228,7 @@ EXPERIMENTAL { rte_mp_sendmsg; rte_mp_request; rte_mp_reply; + rte_dev_iterator_init; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
Re: [PATCH v4 09/20] eal/dev: implement device iteration initialization
Quoted 99 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Signed-off-by Gaetan Rivet <[email protected]>---
lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +0
-0@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mkDIRS-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_ringlib/librte_eal/bsdapp/eal/Makefile +0
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3LDLIBS += -lexecinfo
LDLIBS += -lpthread
LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
EXPORT_MAP:= ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +39
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ; + s++; + } +return i; +} + +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it, +const char *devstr) +{ +struct { +const char *key; +const char *str; +struct rte_kvargs *kvlist; + } layers[] = { + {"bus=" ,NULL ,NULL , }, + {"class=" ,NULL ,NULL , }, + {"driver=" ,NULL ,NULL , }, + }; +struct rte_kvargs_pair *kv =NULL ; +struct rte_class *cls =NULL ; +struct rte_bus *bus =NULL ; +const char *s = devstr; +size_t nblayer; +size_t i =0 ; + +/* Having both busstr and clsstr NULL is illegal, +* marking this iterator as invalid unless +* everything goes well.
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 258
Quoted 10 lines
lib/librte_eal/common/eal_common_dev.c +10
-0+*/ + it->busstr =NULL ; + it->clsstr =NULL ; +/* Split each sub-lists. */ + nblayer =dev_layer_count (devstr); +if (nblayer >RTE_DIM (layers)) { +RTE_LOG (ERR ,EAL ,"Invalid query: too many layers (%zu)\n" , + nblayer); + rte_errno =EINVAL ; + goto get_out;
This one could just return -EINVAL; instead of calling get_out.
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname)
Quoted 12 lines
lib/librte_eal/common/eal_common_dev.c +12
-0+ } +while (s !=NULL ) { +char *copy; +char *end; + +if (strncmp (layers[i].key, s, +strlen (layers[i].key))) + goto next_layer; + layers[i].str = s; + copy =strdup (s); +if (copy ==NULL ) { + RTE_LOG(ERR, EAL, "OOM\n”);
Maybe spell it out in the log ‘Out of Memory’.
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 278
Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c +8
-0+ rte_errno =ENOMEM ; + goto get_out; + } + end =strchr (copy,'/' ); + end = end ? end :strchr (copy,'\0' ); + end[0 ] ='\0' ; + layers[i].kvlist =rte_kvargs_parse (copy,NULL ); +free (copy);
I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.
Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.
I stopped reviewing the code as it became difficult to read IMO and just causing me a headache.
This problem needs to be addressed by the TSC IMO.
Quoted 139 lines
lib/librte_eal/common/eal_common_dev.c +78
-0+if (layers[i].kvlist ==NULL ) { +RTE_LOG (ERR ,EAL ,"Could not parse %s\n" , s); + rte_errno =EINVAL ; + goto get_out; + } + s =strchr (s,'/' ); +if (s !=NULL ) + s++; +next_layer: +if (i >=RTE_DIM (layers)) { +RTE_LOG (ERR ,EAL ,"Unrecognized layer %s\n" , s); + rte_errno =EINVAL ; + goto get_out; + } + i++; + } +/* Parse each sub-list. */ +for (i =0 ; i <RTE_DIM (layers); i++) { +if (layers[i].kvlist ==NULL ) +continue ; + kv = &layers[i].kvlist->pairs[0 ]; +if (strcmp (kv->key,"bus" ) ==0 ) { + bus =rte_bus_find_by_name (kv->value); +if (bus ==NULL ) { +RTE_LOG (ERR ,EAL ,"Could not find bus \"%s\"\n" , + kv->value); + rte_errno =EFAULT ; + goto get_out; + } + }else if (strcmp (kv->key,"class" ) ==0 ) { + cls =rte_class_find_by_name (kv->value); +if (cls ==NULL ) { +RTE_LOG (ERR ,EAL ,"Could not find class \"%s\"\n" , + kv->value); + rte_errno =EFAULT ; + goto get_out; + } + }else if (strcmp (kv->key,"driver" ) ==0 ) { +/* Ignore */ +continue ; + } + } +/* The string should have at least +* one layer specified. +*/ +if (bus ==NULL && cls ==NULL ) { +RTE_LOG (ERR ,EAL , +"Either bus or class must be specified.\n" ); + rte_errno =EINVAL ; + goto get_out; + } +if (bus !=NULL && bus->dev_iterate ==NULL ) { +RTE_LOG (ERR ,EAL ,"Bus %s not supported\n" , bus->name); + rte_errno =ENOTSUP ; + goto get_out; + } +if (cls !=NULL && cls->dev_iterate ==NULL ) { +RTE_LOG (ERR ,EAL ,"Class %s not supported\n" , cls->name); + rte_errno =ENOTSUP ; + goto get_out; + } +/* Fill iterator fields. */ +if (bus !=NULL ) + it->busstr = layers[0 ].str; +if (cls !=NULL ) + it->clsstr = layers[1 ].str; + it->devstr = devstr; + it->bus = bus; + it->cls = cls; + it->device =NULL ; + it->class_device =NULL ; +get_out: +for (i =0 ; i <RTE_DIM (layers); i++) { +if (layers[i].kvlist) +rte_kvargs_free (layers[i].kvlist); + } +return -rte_errno; +}lib/librte_eal/common/include/rte_dev.h +23
-0@@ -310,6 +310,29 @@ typedef void *(*rte_dev_iterate_t)(const void *start,const char *devstr, const struct rte_dev_iterator *it); +/** +* Initializes a device iterator. +* +* This iterator allows accessing a list of devices matching a criteria. +* The device matching is made among all buses and classes currently registered, +* filtered by the device description given as parameter. +* +* This function will not allocate any memory. It is safe to stop the +* iteration at any moment and let the iterator go out of context. +* +* @param it +* Device iterator handle. +* +* @param str +* Device description string. +* +* @return +* 0 on successful initialization. +* <0 on error. +*/ +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); + #ifdef __cplusplus }#endif lib/librte_eal/linuxapp/eal/Makefile +0
-0@@ -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.clib/librte_eal/rte_eal_version.map +1
-0@@ -228,6 +228,7 @@ EXPERIMENTAL { rte_mp_sendmsg; rte_mp_request; rte_mp_reply; + rte_dev_iterator_init; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;Signature · 1 line
2.11.0
Regards,
Keith
Re: [PATCH v4 09/20] eal/dev: implement device iteration initialization
Hello Keith,
Quoted 111 lines · Keith
Quoted 99 lines · Gaetan Rivet
Parse a device description.
Split this description in their relevant part for each layers. No dynamic allocation is performed.Signed-off-by Gaetan Rivet <[email protected]>---
lib/Makefile | 1 + lib/librte_eal/bsdapp/eal/Makefile | 1 + lib/librte_eal/common/eal_common_dev.c | 147 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 23 +++++ lib/librte_eal/linuxapp/eal/Makefile | 1 + lib/librte_eal/rte_eal_version.map | 1 + 6 files changed, 174 insertions(+)lib/Makefile +0
-0@@ -6,6 +6,7 @@ include $(RTE_SDK)/mk/rte.vars.mkDIRS-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_ringlib/librte_eal/bsdapp/eal/Makefile +0
-0@@ -18,6 +18,7 @@ CFLAGS += $(WERROR_FLAGS) -O3LDLIBS += -lexecinfo
LDLIBS += -lpthread
LDLIBS += -lgcc_s
+LDLIBS += -lrte_kvargs
EXPORT_MAP:= ../../rte_eal_version.maplib/librte_eal/common/eal_common_dev.c +39
-0@@ -10,9 +10,12 @@#include <rte_compat.h> #include <rte_bus.h> +#include <rte_class.h> #include <rte_dev.h> #include <rte_devargs.h> #include <rte_debug.h> +#include <rte_errno.h> +#include <rte_kvargs.h> #include <rte_log.h> #include "eal_private.h" @@ -207,3 +210,147 @@ rte_eal_hotplug_remove(const char *busname, const char *devname)rte_eal_devargs_remove (busname, devname);return ret; } + +static size_t +dev_layer_count (const char *s) +{ +size_t i = s ?1 :0 ; + +while (s !=NULL && s[0 ] !='\0' ) { + i += s[0 ] =='/' ; + s++; + } +return i; +} + +int __rte_experimental +rte_dev_iterator_init (struct rte_dev_iterator *it, +const char *devstr) +{ +struct { +const char *key; +const char *str; +struct rte_kvargs *kvlist; + } layers[] = { + {"bus=" ,NULL ,NULL , }, + {"class=" ,NULL ,NULL , }, + {"driver=" ,NULL ,NULL , }, + }; +struct rte_kvargs_pair *kv =NULL ; +struct rte_class *cls =NULL ; +struct rte_bus *bus =NULL ; +const char *s = devstr; +size_t nblayer; +size_t i =0 ; + +/* Having both busstr and clsstr NULL is illegal, +* marking this iterator as invalid unless +* everything goes well. lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 258
Quoted 10 lines
lib/librte_eal/common/eal_common_dev.c +10
-0+*/ + it->busstr =NULL ; + it->clsstr =NULL ; +/* Split each sub-lists. */ + nblayer =dev_layer_count (devstr); +if (nblayer >RTE_DIM (layers)) { +RTE_LOG (ERR ,EAL ,"Invalid query: too many layers (%zu)\n" , + nblayer); + rte_errno =EINVAL ; + goto get_out;This one could just return
-EINVAL; instead of callingget_out.
Quoted 14 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname)
Quoted 12 lines
lib/librte_eal/common/eal_common_dev.c +12
-0+ } +while (s !=NULL ) { +char *copy; +char *end; + +if (strncmp (layers[i].key, s, +strlen (layers[i].key))) + goto next_layer; + layers[i].str = s; + copy =strdup (s); +if (copy ==NULL ) { + RTE_LOG(ERR, EAL, "OOM\n”);Maybe spell it out in the log ‘Out of Memory’.
Will do.
Quoted 11 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 278
Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c +8
-0+ rte_errno =ENOMEM ; + goto get_out; + } + end =strchr (copy,'/' ); + end = end ? end :strchr (copy,'\0' ); + end[0 ] ='\0' ; + layers[i].kvlist =rte_kvargs_parse (copy,NULL ); +free (copy);I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.
Quoted 2 lines
Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.
I understand. What I dislike is having inconsistencies in the layout of the code.
"Paragraphs", for lack of a better word, are high subjective and a matter of taste.
Given that subjectivity is not helpful in review and taste is hard to debate, I prefer to have a single terse rule, that is to avoid any additional bytes beside the bare minimum to respect checkpatch.
When I feel the need to have a new "conceptual group", then I am forced to add a comment to explain what is happening. By not allowing blank lines, I thus feel the pressure for space and explanation more acutely.
Also, this makes a patch context as information-rich as possible.
Quoted 3 lines
I stopped reviewing the code as it became difficult to read IMO and just causing me a headache.
This problem needs to be addressed by the TSC IMO.
Sorry that it made it more difficult than necessary.
It would be interesting if an addendum to the kernel coding style was made regarding blank lines.
Regards,
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v4 09/20] eal/dev: implement device iteration initialization
Quoted 5 lines · Gaëtan Rivet
Hello Keith,
Hello Gaëtan,
Quoted 5 lines
Quoted 5 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 278
Quoted 2 lines
lib/librte_eal/common/eal_common_dev.c +2
-0+ layers[i].kvlist =rte_kvargs_parse (copy,NULL ); +free (copy);I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.
Quoted 8 lines
Quoted 2 lines
Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.
I understand. What I dislike is having inconsistencies in the layout of the code.
"Paragraphs", for lack of a better word, are high subjective and a matter of taste.
I bet your teacher(s) would disagree with that statement with one single paragraph in your book reports :-)
Quoted 4 lines
Given that subjectivity is not helpful in review and taste is hard to debate, I prefer to have a single terse rule, that is to avoid any additional bytes beside the bare minimum to respect checkpatch.
Taste is hard to debate, but you have gone the extreme route with only the bare minimum blank lines and that is not good as well. A silly script does not read code or understand code we the humans have to make the code readable.
Quoted 4 lines
When I feel the need to have a new "conceptual group", then I am forced to add a comment to explain what is happening. By not allowing blank lines, I thus feel the pressure for space and explanation more acutely.
A blank can give somewhat convey the same information without a comment, but not in all cases. Even a blank before a group of lines can convey this is a new logic section. I do not buy the point for needing the same terse rule here as most of the coding style is free form and allows for reading between the lines a bit.
We can make a rule here, but no blank lines in a function this size and the patch of this size is making DPDK not as professional looking as it could be.
I am not asking for a blank line after every statement, but when I see functions of this size without a blank lines it means we are not addressing readability for future developers to read this code. If you have to put a comment before a section of code then normally a blank line before the comment is reasonable.
Look at the rest of DPDK code and tell me that we do not use blank lines wisely or no blank lines other then what the silly checkpatch script flags.
Below I added a few blank lines not many, but just few to help the reader detect sections and breaks in the code. Even if you added a few lines or removed a few lines I would think this is much more readable in the long run.
(Wish I could remove the ‘+’ it would help to make my point clearer, but afraid email will left justify the code).
+int __rte_experimental +rte_dev_iterator_init(struct rte_dev_iterator *it,
+ const char *devstr)
+{
+ struct {
+ const char *key;
+ const char *str;
+ struct rte_kvargs *kvlist;
+ } layers[] = {
+ { "bus=", NULL, NULL, },
+ { "class=", NULL, NULL, },
+ { "driver=", NULL, NULL, },
+ };
+ struct rte_kvargs_pair *kv = NULL;
+ struct rte_class *cls = NULL;
+ struct rte_bus *bus = NULL;
+ const char *s = devstr;
+ size_t nblayer;
+ size_t i = 0;
+
+ /* Having both busstr and clsstr NULL is illegal,
+ * marking this iterator as invalid unless
+ * everything goes well.
+ */
+ it->busstr = NULL;
+ it->clsstr = NULL;
+
+ /* Split each sub-lists. */
+ nblayer = dev_layer_count(devstr);
+ if (nblayer > RTE_DIM(layers)) {
+ RTE_LOG(ERR, EAL, "Invalid query: too many layers (%zu)\n",
+ nblayer);
+ rte_errno = EINVAL;
+ goto get_out;
+ }
+
+ while (s != NULL) {
+ char *copy;
+ char *end;
+
+ if (strncmp(layers[i].key, s,
+ strlen(layers[i].key)))
+ goto next_layer;
+
+ layers[i].str = s;
+ copy = strdup(s);
+ if (copy == NULL) {
+ RTE_LOG(ERR, EAL, "OOM\n");
+ rte_errno = ENOMEM;
+ goto get_out;
+ }
+
+ end = strchr(copy, '/');
+ end = end ? end : strchr(copy, '\0');
+ end[0] = '\0';
+ layers[i].kvlist = rte_kvargs_parse(copy, NULL);
+ free(copy);
+
+ if (layers[i].kvlist == NULL) {
+ RTE_LOG(ERR, EAL, "Could not parse %s\n", s);
+ rte_errno = EINVAL;
+ goto get_out;
+ }
+
+ s = strchr(s, '/');
+ if (s != NULL)
+ s++;
+
+next_layer:
+ if (i >= RTE_DIM(layers)) {
+ RTE_LOG(ERR, EAL, "Unrecognized layer %s\n", s);
+ rte_errno = EINVAL;
+ goto get_out;
+ }
+ i++;
+ }
+
+ /* Parse each sub-list. */
+ for (i = 0; i < RTE_DIM(layers); i++) {
+ if (layers[i].kvlist == NULL)
+ continue;
+
+ kv = &layers[i].kvlist->pairs[0];
+ if (strcmp(kv->key, "bus") == 0) {
+ bus = rte_bus_find_by_name(kv->value);
+ if (bus == NULL) {
+ RTE_LOG(ERR, EAL, "Could not find bus \"%s\"\n",
+ kv->value);
+ rte_errno = EFAULT;
+ goto get_out;
+ }
+ } else if (strcmp(kv->key, "class") == 0) {
+ cls = rte_class_find_by_name(kv->value);
+ if (cls == NULL) {
+ RTE_LOG(ERR, EAL, "Could not find class \"%s\"\n",
+ kv->value);
+ rte_errno = EFAULT;
+ goto get_out;
+ }
+ } else if (strcmp(kv->key, "driver") == 0) {
+ /* Ignore */
+ continue;
+ }
+ }
+
+ /* The string should have at least
+ * one layer specified.
+ */
+ if (bus == NULL && cls == NULL) {
+ RTE_LOG(ERR, EAL,
+ "Either bus or class must be specified.\n");
+ rte_errno = EINVAL;
+ goto get_out;
+ }
+
+ if (bus != NULL && bus->dev_iterate == NULL) {
+ RTE_LOG(ERR, EAL, "Bus %s not supported\n", bus->name);
+ rte_errno = ENOTSUP;
+ goto get_out;
+ }
+
+ if (cls != NULL && cls->dev_iterate == NULL) {
+ RTE_LOG(ERR, EAL, "Class %s not supported\n", cls->name);
+ rte_errno = ENOTSUP;
+ goto get_out;
+ }
+
+ /* Fill iterator fields. */
+ if (bus != NULL)
+ it->busstr = layers[0].str;
+ if (cls != NULL)
+ it->clsstr = layers[1].str;
+
+ it->devstr = devstr;
+ it->bus = bus;
+ it->cls = cls;
+ it->device = NULL;
+ it->class_device = NULL;
+
+get_out:
+ for (i = 0; i < RTE_DIM(layers); i++) {
+ if (layers[i].kvlist)
+ rte_kvargs_free(layers[i].kvlist);
+ }
+
+ return -rte_errno;
+}
Quoted 5 lines
Also, this makes a patch context as information-rich as possible.
Quoted 2 lines
I stopped reviewing the code as it became difficult to read IMO and just causing me a headache.
Quoted 10 lines
Quoted 1 line
This problem needs to be addressed by the TSC IMO.
Sorry that it made it more difficult than necessary.
It would be interesting if an addendum to the kernel coding style was made regarding blank lines.Regards,
Signature · 2 lines
Gaëtan Rivet 6WIND
Regards,
Keith
Re: [PATCH v4 09/20] eal/dev: implement device iteration initialization
Quoted 16 lines · Keith
Quoted 5 lines · Gaëtan Rivet
Hello Keith,
Hello Gaëtan,
Quoted 8 lines
Quoted 7 lines
lib/librte_eal/common/eal_common_dev.c rte_eal_hotplug_remove(const char *busname, const char *devname) · line 278
Quoted 2 lines
lib/librte_eal/common/eal_common_dev.c +2
-0+ layers[i].kvlist =rte_kvargs_parse (copy,NULL ); +free (copy);I am sorry this method of not adding blank lines is a bit silly and we need to rethink at least adding a few blank lines to help with grouping the code. This style will cause problems for new readers (old readers) to understand the code. This to me is a maintenance problem for the future and we need to fix this now.
Blank lines after if statements (with possible more comments) can help along with adding blank lines to group code is really the minimum amount of lines required. I have never seen someone state you have to many blanks lines in the code except two or more blank lines in a row. This is akin to having a single paragraph in a novel or letter and it makes it very hard to read. It is not hard to add some blank lines to the code for readability.
Quoted 7 lines
Quoted 5 lines
I understand. What I dislike is having inconsistencies in the layout of the code.
"Paragraphs", for lack of a better word, are high subjective and a matter of taste.
I bet your teacher(s) would disagree with that statement with one single paragraph in your book reports :-)
The utility of using paragraph is not a matter of subjectivity. How to use them and how to structure information is what I deemed subjective.
Quoted 7 lines
Quoted 4 lines
Given that subjectivity is not helpful in review and taste is hard to debate, I prefer to have a single terse rule, that is to avoid any additional bytes beside the bare minimum to respect checkpatch.
Taste is hard to debate, but you have gone the extreme route with only the bare minimum blank lines and that is not good as well. A silly script does not read code or understand code we the humans have to make the code readable.
Quoted 1 line
Quoted 8 lines
Quoted 3 lines
When I feel the need to have a new "conceptual group", then I am forced to add a comment to explain what is happening. By not allowing blank lines, I thus feel the pressure for space and explanation more acutely.
A blank can give somewhat convey the same information without a comment, but not in all cases. Even a blank before a group of lines can convey this is a new logic section. I do not buy the point for needing the same terse rule here as most of the coding style is free form and allows for reading between the lines a bit.
We can make a rule here, but no blank lines in a function this size and the patch of this size is making DPDK not as professional looking as it could be.
I think one of the main issue anyway is that this function is simply too large as it is.
As it turns out, I am working on the second side of this work, which is revamping the device declaration path.
This function will be split in different parts, that will be shorter and more palatable.
This is a big work, still in progress (the device declaration, not the split of this function).
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH v4 10/20 eal/dev: implement device iteration
In reply to Gaetan RivetUse 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 | 187 ++++++++++++++++++++++++++++++++ lib/librte_eal/common/include/rte_dev.h | 25 +++++ lib/librte_eal/rte_eal_version.map | 1 + 3 files changed, 213 insertions(+)
lib/librte_eal/common/eal_common_dev.c +187 -0
@@ -20,6 +20,28 @@#include "eal_private.h" +struct dev_next_ctx { +struct rte_dev_iterator *it; +const char *busstr; +const char *clsstr; +}; + +#define CTX (it, busstr, clsstr) \ + (&(const struct dev_next_ctx){ \ + .it = it, \ + .busstr = busstr, \ + .clsstr = clsstr, \ + }) + +#define ITCTX (ptr) \ + (((struct dev_next_ctx *)(intptr_t)ptr)->it) + +#define BUSCTX (ptr) \ + (((struct dev_next_ctx *)(intptr_t)ptr)->busstr) + +#define CLSCTX (ptr) \ + (((struct dev_next_ctx *)(intptr_t)ptr)->clsstr) +static int cmp_detached_dev_name (const struct rte_device *dev,const void *_name) {
@@ -354,3 +376,168 @@ rte_dev_iterator_init(struct rte_dev_iterator *it, }return -rte_errno; } + +/* '\0' forbidden in sym */ +static const char * +strfirstof (const char *str, +const char *sym) +{ +const char *s; + +for (s = str; s[0 ] !='\0' ; s++) { +const char *c; + +for (c = sym; c[0 ] !='\0' ; c++) { +if (c[0 ] == s[0 ]) +return s; + } + } +return NULL ; +} + +static char * +dev_str_sane_copy (const char *str) +{ +const char *end; +char *copy; + + end =strfirstof (str,",/" ); +if (end !=NULL && + end[0 ] ==',' ) { + copy =strdup (end +1 ); + }else { +/* '/' or '\0' */ + copy =strdup ("" ); + } +if (copy ==NULL ) { + rte_errno =ENOMEM ; + }else { +char *slash; + + slash =strchr (copy,'/' ); +if (slash !=NULL ) + slash[0 ] ='\0' ; + } +return copy; +} + +static int +class_next_dev_cmp (const struct rte_class *cls, +const void *ctx) +{ +struct rte_dev_iterator *it; +const char *clsstr =NULL ; +void *dev; + +if (cls->dev_iterate ==NULL ) +return 1 ; + it =ITCTX (ctx); + clsstr =CLSCTX (ctx); + dev = it->class_device; +/* it->clsstr != NULL means a class +* was specified in the devstr. +*/ +if (it->clsstr !=NULL && cls != it->cls) +return 1 ; +/* If an error occured previously, +* no need to test further. +*/ +if (rte_errno !=0 ) +return -1 ; + dev = cls->dev_iterate (dev, clsstr, it); + it->class_device = dev; +return dev ==NULL ; +} + +static int +bus_next_dev_cmp (const struct rte_bus *bus, +const void *ctx) +{ +struct rte_device *dev =NULL ; +struct rte_class *cls =NULL ; +struct rte_dev_iterator *it; +const char *busstr =NULL ; + +if (bus->dev_iterate ==NULL ) +return 1 ; + it =ITCTX (ctx); + busstr =BUSCTX (ctx); + dev = it->device; +/* it->busstr != NULL means a bus +* was specified in the devstr. +*/ +if (it->busstr !=NULL && bus != it->bus) +return 1 ; +/* If an error occured previously, +* no need to test further. +*/ +if (rte_errno !=0 ) +return -1 ; +if (it->clsstr ==NULL ) { + dev = bus->dev_iterate (dev, busstr, it); + goto end; + } +/* clsstr != NULL */ +if (dev ==NULL ) { +next_dev_on_bus: + dev = bus->dev_iterate (dev, busstr, it); + it->device = dev; + } +if (dev ==NULL ) +return 1 ; +if (it->cls !=NULL ) + cls =TAILQ_PREV (it->cls, rte_class_list, next); + cls =rte_class_find (cls, class_next_dev_cmp, ctx); +if (cls !=NULL ) { + it->cls = cls; + goto end; + } + goto next_dev_on_bus; +end: + it->device = dev; +return dev ==NULL ; +} +__rte_experimental +struct rte_device * +rte_dev_iterator_next (struct rte_dev_iterator *it) +{ +struct rte_bus *bus =NULL ; +int old_errno = rte_errno; +char *busstr =NULL ; +char *clsstr =NULL ; + + rte_errno =0 ; +if (it->busstr ==NULL && it->clsstr ==NULL ) { +/* Invalid iterator. */ + rte_errno =EINVAL ; +return NULL ; + } +if (it->bus !=NULL ) + bus =TAILQ_PREV (it->bus, rte_bus_list, next); +if (it->busstr !=NULL ) { + busstr =dev_str_sane_copy (it->busstr); +if (busstr ==NULL ) + goto out; + } +if (it->clsstr !=NULL ) { + clsstr =dev_str_sane_copy (it->clsstr); +if (clsstr ==NULL ) + goto out; + } +while ((bus =rte_bus_find (bus, bus_next_dev_cmp, +CTX (it, busstr, clsstr)))) { +if (it->device !=NULL ) { + it->bus = bus; + goto out; + } +if (it->busstr !=NULL || + rte_errno !=0 ) +break ; + } +if (rte_errno ==0 ) + rte_errno = old_errno; +out: +free (busstr); +free (clsstr); +return it->device; +}
lib/librte_eal/common/include/rte_dev.h +25 -0
@@ -333,6 +333,31 @@ typedef void *(*rte_dev_iterate_t)(const void *start, int __rte_experimentalrte_dev_iterator_init (struct rte_dev_iterator *it,const char *str); +/** +* Iterates on a device iterator. +* +* Generates a new rte_device handle corresponding to the next element +* in the list described in comprehension by the iterator. +* +* The next object is returned, and the iterator is updated. +* +* @param it +* Device iterator handle. +* +* @return +* An rte_device handle if found. +* NULL if an error occurred (rte_errno is set). +* NULL if no device could be found (rte_errno is not set). +*/ +struct rte_device * __rte_experimental +rte_dev_iterator_next (struct rte_dev_iterator *it); + +#define RTE_DEV_FOREACH (dev, devstr, it) \ + for (rte_dev_iterator_init(it, devstr), \ + dev = rte_dev_iterator_next(it); \ + dev != NULL; \ + dev = rte_dev_iterator_next(it)) + #ifdef __cplusplus }#endif
lib/librte_eal/rte_eal_version.map +1 -0
@@ -229,6 +229,7 @@ EXPERIMENTAL { rte_mp_request; rte_mp_reply; rte_dev_iterator_init; + rte_dev_iterator_next; rte_service_attr_get; rte_service_attr_reset_all; rte_service_component_register;
Signature · 1 line
2.11.0
Re: [PATCH v4 10/20] eal/dev: implement device iteration
HI Gaetan
From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
Quoted 8 lines
lib/librte_eal/common/eal_common_dev.c +8
-0+/* '\0' forbidden in sym */ +static const char * +strfirstof (const char *str, +const char *sym) +{ +const char *s; + +for (s = str; s[0 ] !='\0' ; s++) {
lib/librte_eal/common/eal_common_dev.c rte_dev_iterator_init(struct rte_dev_iterator *it, · line 397
Quoted 10 lines
lib/librte_eal/common/eal_common_dev.c +10
-0+const char *c; + +for (c = sym; c[0 ] !='\0' ; c++) { +if (c[0 ] == s[0 ]) +return s; + } + } +return NULL ; +} +
I think you can use strcspn() instead...
Re: [PATCH v4 10/20] eal/dev: implement device iteration
Quoted 15 lines · Matan Azrad
HI Gaetan
From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
Quoted 12 lines
lib/librte_eal/common/eal_common_dev.c +12
-0+/* '\0' forbidden in sym */ +static const char * +strfirstof (const char *str, +const char *sym) +{ +const char *s; + +for (s = str; s[0 ] !='\0' ; s++) { +const char *c; + +for (c = sym; c[0 ] !='\0' ; c++) { +if (c[0 ] == s[0 ])
Quoted 9 lines
lib/librte_eal/common/eal_common_dev.c rte_dev_iterator_init(struct rte_dev_iterator *it, · line 397
Quoted 6 lines
lib/librte_eal/common/eal_common_dev.c +6
-0+return s; + } + } +return NULL ; +} +I think you can use
strcspn()instead...
Indeed, didn't know about it, I will change it.
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH v4 11/20 kvargs: add generic string matching callback
In reply to Gaetan RivetThis function can be used as a callback torte_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
@@ -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
@@ -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
@@ -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
@@ -8,3 +8,10 @@ DPDK_2.0 { local: *; }; + +EXPERIMENTAL { + global: + + rte_kvargs_strcmp; + +} DPDK_2.0;
Signature · 1 line
2.11.0
PATCH v4 12/20 bus/pci: fix find device implementation
In reply to Gaetan RivetIf 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.
--- 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
@@ -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
@@ -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
PATCH v4 13/20 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
@@ -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
PATCH v4 14/20 bus/pci: add device matching field id
In reply to Gaetan RivetThe 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
@@ -499,21 +499,45 @@ pci_unplug(struct rte_device *dev) }enum pci_params { +RTE_PCI_PARAMS_ID ,RTE_PCI_PARAMS_MAX , };static const char *pci_params_keys[] = { + [RTE_PCI_PARAMS_ID ] ="id" , [RTE_PCI_PARAMS_MAX ] =NULL , };static int +pci_addr_kv_cmp(const char *key __rte_unused, +const char *value, +void *_addr2) +{ +struct rte_pci_addr _addr1; +struct rte_pci_addr *addr1 = &_addr1; +struct rte_pci_addr *addr2 = _addr2; + +if (rte_pci_addr_parse (value, addr1)) +return -1 ; +return rte_pci_addr_cmp (addr1, addr2); +} + +static int pci_dev_match (const struct rte_device *dev,const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_pci_device *pdev; - (void ) dev; - (void ) kvlist; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + pdev =RTE_DEV_TO_PCI_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"id" , + &pci_addr_kv_cmp, + (void *)(intptr_t )&pdev->addr)) +return 1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v4 15/20 bus/vdev: fix find device implementation
In reply to Gaetan RivetIf start is set and a device before it matches the data, this device is returned.
This induces potentially infinite loops.
--- 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
@@ -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
@@ -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
PATCH v4 16/20 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
@@ -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
PATCH v4 17/20 bus/vdev: add device matching field driver
In reply to Gaetan RivetThe 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
@@ -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
@@ -417,10 +417,12 @@ vdev_unplug(struct rte_device *dev) }enum vdev_params { +RTE_VDEV_PARAMS_DRIVER ,RTE_VDEV_PARAMS_MAX , };static const char *vdev_params_keys[] = { + [RTE_VDEV_PARAMS_DRIVER ] ="driver" , [RTE_VDEV_PARAMS_MAX ] =NULL , };
@@ -429,9 +431,17 @@ vdev_dev_match(const struct rte_device *dev, const void *_kvlist) {const struct rte_kvargs *kvlist = _kvlist; +const struct rte_vdev_device *vdev; - (void ) kvlist; - (void ) dev; +if (kvlist ==NULL ) +/* Empty string matches everything. */ +return 0 ; + vdev =RTE_DEV_TO_VDEV_CONST (dev); +/* if any field does not match. */ +if (rte_kvargs_process (kvlist,"driver" , + &rte_kvargs_strcmp, + (void *)(intptr_t )vdev->device.driver->name)) +return -1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v4 18/20 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 | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 lib/librte_ether/rte_class_eth.c
lib/Makefile +1 -1
@@ -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
@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -lrte_mempool -lrte_ring -LDLIBS += -lrte_mbuf +LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.c
lib/librte_ether/rte_class_eth.c new file +73 -0
73 lines not on this page · raw message
Signature · 1 line
2.11.0
Re: [PATCH v4 18/20] ethdev: register ether layer as a class
Hi Gaetan
From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
Quoted 91 lines
Signed-off-by Gaetan Rivet <[email protected]>--- lib/Makefile | 2 +- lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644
lib/librte_ether/rte_class_eth.clib/Makefile +0
-0@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
librte_cmdlineDEPDIRS-librte_cmdline :=librte_eal
DIRS-$(CONFIG_RTE_LIBRTE_ETHER) +=librte_etherDEPDIRS-librte_ether
:=librte_netlibrte_eallibrte_mempoollibrte_ring-DEPDIRS-librte_ether +=librte_mbuf
+DEPDIRS-librte_ether +=librte_mbuflibrte_kvargs
DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) +=librte_bbdevDEPDIRS-librte_bbdev:=librte_eallibrte_mempoollibrte_mbuf
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) +=librte_cryptodevdiff --git
a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index3ca5782bb..a1a0393de100644lib/librte_ether/Makefile +1
-0@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -
lrte_mempool-lrte_ring -LDLIBS += -lrte_mbuflib/librte_ether/Makefile +2
-0+LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.clib/librte_ether/rte_class_eth.c new file +46
-0@@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2018 Gaëtan Rivet +*/ + +#include <string.h> + +#include <rte_class.h> +#include <rte_compat.h> +#include <rte_errno.h> +#include <rte_kvargs.h> +#include <rte_log.h> + +#include "rte_ethdev.h" +#include "rte_ethdev_core.h" + +enum eth_params { +RTE_ETH_PARAMS_MAX , +}; + +static const char *eth_params_keys[] = { + [RTE_ETH_PARAMS_MAX ] =NULL , +}; + +static int +eth_dev_match (struct rte_eth_dev *edev, +struct rte_kvargs *kvlist) +{ + (void ) kvlist; + (void ) edev; +return 0 ; +} + +static void * +eth_dev_iterate (const void *_start, +const char *str, +const struct rte_dev_iterator *it) +{ +const struct rte_eth_dev *start = _start; +struct rte_device *dev = it->device; +struct rte_kvargs *kvargs =NULL ; +struct rte_eth_dev *edev =NULL ; +uint16_t p =0 ; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str, eth_params_keys); +if (kvargs ==NULL ) {
lib/librte_ether/rte_class_eth.c line 56
Quoted 10 lines
lib/librte_ether/rte_class_eth.c new file +10
-0+RTE_LOG (ERR ,EAL ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } +if (start) + p = start->data->port_id +1 ; +for (p =rte_eth_find_next (p); + p <RTE_MAX_ETHPORTS ; + p =rte_eth_find_next (p +1 )) {
What are about differed\owned\bonded devices?
What is actually the use cases of this iterator?
DPDK internal management or applications?
Quoted 19 lines
lib/librte_ether/rte_class_eth.c new file +17
-1+ edev = &rte_eth_devices[p]; +if (dev != edev->device) + goto next_ethdev; +if (eth_dev_match (edev, kvargs) ==0 ) +break ; +next_ethdev: + edev =NULL ; + } +rte_kvargs_free (kvargs); +return edev; +} + +struct rte_class rte_class_eth = { + .dev_iterate = eth_dev_iterate, +}; + +RTE_REGISTER_CLASS (eth, rte_class_eth); --2.11.0
Re: [PATCH v4 18/20] ethdev: register ether layer as a class
Hi Matan,
Quoted 100 lines · Matan Azrad
Hi Gaetan
From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
Quoted 97 lines
Signed-off-by Gaetan Rivet <[email protected]>--- lib/Makefile | 2 +- lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644
lib/librte_ether/rte_class_eth.clib/Makefile +0
-0@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
librte_cmdlineDEPDIRS-librte_cmdline :=librte_eal
DIRS-$(CONFIG_RTE_LIBRTE_ETHER) +=librte_etherDEPDIRS-librte_ether
:=librte_netlibrte_eallibrte_mempoollibrte_ring-DEPDIRS-librte_ether +=librte_mbuf
+DEPDIRS-librte_ether +=librte_mbuflibrte_kvargs
DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) +=librte_bbdevDEPDIRS-librte_bbdev:=librte_eallibrte_mempoollibrte_mbuf
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) +=librte_cryptodevdiff --git
a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index3ca5782bb..a1a0393de100644lib/librte_ether/Makefile +1
-0@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_API CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -
lrte_mempool-lrte_ring -LDLIBS += -lrte_mbuflib/librte_ether/Makefile +2
-0+LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.clib/librte_ether/rte_class_eth.c new file +52
-0@@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2018 Gaëtan Rivet +*/ + +#include <string.h> + +#include <rte_class.h> +#include <rte_compat.h> +#include <rte_errno.h> +#include <rte_kvargs.h> +#include <rte_log.h> + +#include "rte_ethdev.h" +#include "rte_ethdev_core.h" + +enum eth_params { +RTE_ETH_PARAMS_MAX , +}; + +static const char *eth_params_keys[] = { + [RTE_ETH_PARAMS_MAX ] =NULL , +}; + +static int +eth_dev_match (struct rte_eth_dev *edev, +struct rte_kvargs *kvlist) +{ + (void ) kvlist; + (void ) edev; +return 0 ; +} + +static void * +eth_dev_iterate (const void *_start, +const char *str, +const struct rte_dev_iterator *it) +{ +const struct rte_eth_dev *start = _start; +struct rte_device *dev = it->device; +struct rte_kvargs *kvargs =NULL ; +struct rte_eth_dev *edev =NULL ; +uint16_t p =0 ; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str, eth_params_keys); +if (kvargs ==NULL ) { +RTE_LOG (ERR ,EAL ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } +if (start)
Quoted 9 lines
lib/librte_ether/rte_class_eth.c line 56
Quoted 4 lines
lib/librte_ether/rte_class_eth.c new file +4
-0+ p = start->data->port_id +1 ; +for (p =rte_eth_find_next (p); + p <RTE_MAX_ETHPORTS ; + p =rte_eth_find_next (p +1 )) {What are about differed\owned\bonded devices?
What is actually the use cases of this iterator?
DPDK internal management or applications?
This API is public, so anyone can use it.
It should be primarily used by internal systems however. I do not think Applications would be interested in calling the dev_iterate ops.
The EAL would provide a way to list interfaces from each layers. Then DPDK libraries (such as librte_ether) would translate this following their internal rules. librte_ether would thus for example here translate an rte_eth_dev handle to a port_id, that an application could use. If there was a need to filter by owner_id, then it would be the job of librte_ether.
The EAL cannot keep track of layers specifics, it can only provide generic APIs.
Quoted 20 lines
Quoted 19 lines
lib/librte_ether/rte_class_eth.c new file +17
-1+ edev = &rte_eth_devices[p]; +if (dev != edev->device) + goto next_ethdev; +if (eth_dev_match (edev, kvargs) ==0 ) +break ; +next_ethdev: + edev =NULL ; + } +rte_kvargs_free (kvargs); +return edev; +} + +struct rte_class rte_class_eth = { + .dev_iterate = eth_dev_iterate, +}; + +RTE_REGISTER_CLASS (eth, rte_class_eth); --2.11.0
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v4 18/20] ethdev: register ether layer as a class
Hi Gaetan
From: Gaëtan Rivet, Monday, April 9, 2018 10:47 AM
Quoted 119 lines
Hi Matan,
Quoted 22 lines · Matan Azrad
Hi Gaetan
From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
Quoted 19 lines
Signed-off-by Gaetan Rivet <[email protected]>--- lib/Makefile | 2 +- lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode100644
lib/librte_ether/rte_class_eth.clib/Makefile index 4206485d3..47513f03f renamed from lib/Makefile +0
-0100644
lib/Makefile +0
-0@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
librte_cmdlineDEPDIRS-librte_cmdline :=librte_eal
DIRS-$(CONFIG_RTE_LIBRTE_ETHER) +=librte_ether
DEPDIRS-librte_ether :=librte_netlibrte_eallibrte_mempoollibrte_ring-DEPDIRS-librte_ether +=librte_mbuf+DEPDIRS-librte_ether +=librte_mbuflibrte_kvargsQuoted 8 lines
lib/librte_ether/Makefile CFLAGS += -DALLOW_EXPERIMENTAL_API
Quoted 8 lines
DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) +=
librte_bbdevDEPDIRS-librte_bbdev:=librte_eallibrte_mempoollibrte_mbuf
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) +=librte_cryptodevdiff --git
a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index3ca5782bb..a1a0393de100644lib/librte_ether/Makefile +0
-0@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_APICFLAGS
Quoted 71 lines
Quoted 71 lines
lib/librte_ether/Makefile +1
-0+= -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -
lrte_mempool-lrte_ring -LDLIBS += -lrte_mbuflib/librte_ether/Makefile +2
-0+LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.clib/librte_ether/rte_class_eth.c new file +51
-0@@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2018 Gaëtan Rivet +*/ + +#include <string.h> + +#include <rte_class.h> +#include <rte_compat.h> +#include <rte_errno.h> +#include <rte_kvargs.h> +#include <rte_log.h> + +#include "rte_ethdev.h" +#include "rte_ethdev_core.h" + +enum eth_params { +RTE_ETH_PARAMS_MAX , +}; + +static const char *eth_params_keys[] = { + [RTE_ETH_PARAMS_MAX ] =NULL , +}; + +static int +eth_dev_match (struct rte_eth_dev *edev, +struct rte_kvargs *kvlist) +{ + (void ) kvlist; + (void ) edev; +return 0 ; +} + +static void * +eth_dev_iterate (const void *_start, +const char *str, +const struct rte_dev_iterator *it) { +const struct rte_eth_dev *start = _start; +struct rte_device *dev = it->device; +struct rte_kvargs *kvargs =NULL ; +struct rte_eth_dev *edev =NULL ; +uint16_t p =0 ; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str, eth_params_keys); +if (kvargs ==NULL ) { +RTE_LOG (ERR ,EAL ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } +if (start)Quoted 9 lines
lib/librte_ether/rte_class_eth.c line 56
Quoted 4 lines
lib/librte_ether/rte_class_eth.c new file +4
-0+ p = start->data->port_id +1 ; +for (p =rte_eth_find_next (p); + p <RTE_MAX_ETHPORTS ; + p =rte_eth_find_next (p +1 )) {What are about differed\owned\bonded devices?
What is actually the use cases of this iterator?
DPDK internal management or applications?This API is public, so anyone can use it.
It should be primarily used by internal systems however.
I do not think Applications would be interested in calling thedev_iterateops.
Quoted 7 lines
The EAL would provide a way to list interfaces from each layers. Then DPDK libraries (such as
librte_ether) would translate this following their internal rules.librte_etherwould thus for example here translate anrte_eth_devhandle to aport_id, that an application could use. If there was a need to filter byowner_id, then it would be the job oflibrte_ether.The EAL cannot keep track of layers specifics, it can only provide generic APIs.
This is exactly what I'm asking, what is the right behavior here?
Now, The code is skipping DEFFERED devices but iterating over owned\bonded devices. Looks like any USED port should be iterated...
Moreover, looks like there is chance to iterate over EAL device more than 1 time for loop, Is it OK?
Quoted 24 lines
Quoted 11 lines
Quoted 11 lines
lib/librte_ether/rte_class_eth.c new file +11
-0+ edev = &rte_eth_devices[p]; +if (dev != edev->device) + goto next_ethdev; +if (eth_dev_match (edev, kvargs) ==0 ) +break ; +next_ethdev: + edev =NULL ; + } +rte_kvargs_free (kvargs); +return edev; +}Quoted 9 lines
Quoted 8 lines
lib/librte_ether/rte_class_eth.c new file +6
-1+ +struct rte_class rte_class_eth = { + .dev_iterate = eth_dev_iterate, +}; + +RTE_REGISTER_CLASS (eth, rte_class_eth); --2.11.0
--
Gaëtan Rivet
6WIND
Re: [PATCH v4 18/20] ethdev: register ether layer as a class
Quoted 128 lines · Matan Azrad
Hi Gaetan
From: Gaëtan Rivet, Monday, April 9, 2018 10:47 AM
Quoted 125 lines
Hi Matan,
Quoted 22 lines · Matan Azrad
Hi Gaetan
From: Gaetan Rivet, Friday, March 30, 2018 12:24 AM
Quoted 19 lines
Signed-off-by Gaetan Rivet <[email protected]>--- lib/Makefile | 2 +- lib/librte_ether/Makefile | 3 +- lib/librte_ether/rte_class_eth.c | 73 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 2 deletions(-) create mode100644
lib/librte_ether/rte_class_eth.clib/Makefile index 4206485d3..47513f03f renamed from lib/Makefile +0
-0100644
lib/Makefile +0
-0@@ -23,7 +23,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_CMDLINE) +=
librte_cmdlineDEPDIRS-librte_cmdline :=librte_eal
DIRS-$(CONFIG_RTE_LIBRTE_ETHER) +=librte_ether
DEPDIRS-librte_ether :=librte_netlibrte_eallibrte_mempoollibrte_ring-DEPDIRS-librte_ether +=librte_mbuf+DEPDIRS-librte_ether +=librte_mbuflibrte_kvargsQuoted 8 lines
lib/librte_ether/Makefile CFLAGS += -DALLOW_EXPERIMENTAL_API
Quoted 8 lines
DIRS-$(CONFIG_RTE_LIBRTE_BBDEV) +=
librte_bbdevDEPDIRS-librte_bbdev:=librte_eallibrte_mempoollibrte_mbuf
DIRS-$(CONFIG_RTE_LIBRTE_CRYPTODEV) +=librte_cryptodevdiff --git
a/lib/librte_ether/Makefile b/lib/librte_ether/Makefile index3ca5782bb..a1a0393de100644lib/librte_ether/Makefile +0
-0@@ -12,13 +12,14 @@ CFLAGS += -DALLOW_EXPERIMENTAL_APICFLAGS
Quoted 71 lines
Quoted 71 lines
lib/librte_ether/Makefile +1
-0+= -O3 CFLAGS += $(WERROR_FLAGS) LDLIBS += -lrte_net -lrte_eal -
lrte_mempool-lrte_ring -LDLIBS += -lrte_mbuflib/librte_ether/Makefile +2
-0+LDLIBS += -lrte_mbuf -lrte_kvargs EXPORT_MAP := rte_ethdev_version.map LIBABIVER := 8 SRCS-y += rte_ethdev.c +SRCS-y += rte_class_eth.c SRCS-y += rte_flow.c SRCS-y += rte_tm.c SRCS-y += rte_mtr.clib/librte_ether/rte_class_eth.c new file +51
-0@@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: BSD-3-Clause +* Copyright(c) 2018 Gaëtan Rivet +*/ + +#include <string.h> + +#include <rte_class.h> +#include <rte_compat.h> +#include <rte_errno.h> +#include <rte_kvargs.h> +#include <rte_log.h> + +#include "rte_ethdev.h" +#include "rte_ethdev_core.h" + +enum eth_params { +RTE_ETH_PARAMS_MAX , +}; + +static const char *eth_params_keys[] = { + [RTE_ETH_PARAMS_MAX ] =NULL , +}; + +static int +eth_dev_match (struct rte_eth_dev *edev, +struct rte_kvargs *kvlist) +{ + (void ) kvlist; + (void ) edev; +return 0 ; +} + +static void * +eth_dev_iterate (const void *_start, +const char *str, +const struct rte_dev_iterator *it) { +const struct rte_eth_dev *start = _start; +struct rte_device *dev = it->device; +struct rte_kvargs *kvargs =NULL ; +struct rte_eth_dev *edev =NULL ; +uint16_t p =0 ; + +if (str !=NULL ) { + kvargs =rte_kvargs_parse (str, eth_params_keys); +if (kvargs ==NULL ) { +RTE_LOG (ERR ,EAL ,"cannot parse argument list\n" ); + rte_errno =EINVAL ; +return NULL ; + } + } +if (start)Quoted 9 lines
lib/librte_ether/rte_class_eth.c line 56
Quoted 4 lines
lib/librte_ether/rte_class_eth.c new file +4
-0+ p = start->data->port_id +1 ; +for (p =rte_eth_find_next (p); + p <RTE_MAX_ETHPORTS ; + p =rte_eth_find_next (p +1 )) {What are about differed\owned\bonded devices?
What is actually the use cases of this iterator?
DPDK internal management or applications?This API is public, so anyone can use it.
It should be primarily used by internal systems however.
I do not think Applications would be interested in calling thedev_iterateops.The EAL would provide a way to list interfaces from each layers. Then DPDK libraries (such as
librte_ether) would translate this following their internal rules.librte_etherwould thus for example here translate anrte_eth_devhandle to aport_id, that an application could use. If there was a need to filter byowner_id, then it would be the job oflibrte_ether.
Quoted 6 lines
Quoted 1 line
The EAL cannot keep track of layers specifics, it can only provide generic APIs.
This is exactly what I'm asking, what is the right behavior here?
From the EAL PoV: The layer should be perfectly transparent: all
internal objects should be returned.
Quoted 3 lines
Now, The code is skipping DEFFERED devices but iterating over owned\bonded devices. Looks like any USED port should be iterated...
Right, actually DEFERRED devices should probably be returned as well, good catch.
Quoted 2 lines
Moreover, looks like there is chance to iterate over EAL device more than 1 time for loop, Is it OK?
If by EAL device you mean rte_device, then yes, this is OK. Due to mlx4 PMD, it is now possible for PMDs to spawn several rte_eth_dev per rte_pci_device. A single rte_pci_device is a specialization of an rte_device. So an rte_device can be shared by several rte_eth_dev, and would be returned several times if need be.
Each time however, the rte_eth_dev layer should iterate over its internal object, meaning that even if the rte_device is the same, the overall context would still change.
Quoted 24 lines
Quoted 24 lines
Quoted 11 lines
Quoted 11 lines
lib/librte_ether/rte_class_eth.c new file +11
-0+ edev = &rte_eth_devices[p]; +if (dev != edev->device) + goto next_ethdev; +if (eth_dev_match (edev, kvargs) ==0 ) +break ; +next_ethdev: + edev =NULL ; + } +rte_kvargs_free (kvargs); +return edev; +}Quoted 9 lines
Quoted 8 lines
lib/librte_ether/rte_class_eth.c new file +6
-1+ +struct rte_class rte_class_eth = { + .dev_iterate = eth_dev_iterate, +}; + +RTE_REGISTER_CLASS (eth, rte_class_eth); --2.11.0
--
Gaëtan Rivet
6WIND
Signature · 2 lines
Gaëtan Rivet 6WIND
PATCH v4 19/20 ethdev: add device matching field name
In reply to Gaetan RivetThe 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 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
lib/librte_ether/rte_class_eth.c +8 -2
@@ -14,10 +14,12 @@#include "rte_ethdev_core.h" enum eth_params { +RTE_ETH_PARAMS_NAME ,RTE_ETH_PARAMS_MAX , };static const char *eth_params_keys[] = { + [RTE_ETH_PARAMS_NAME ] ="name" , [RTE_ETH_PARAMS_MAX ] =NULL , };
@@ -25,8 +27,12 @@ static int eth_dev_match(struct rte_eth_dev *edev, struct rte_kvargs *kvlist) { - (void) kvlist; - (void) edev; + struct rte_eth_dev_data *data; + + data = edev->data; +if (rte_kvargs_process (kvlist,"name" , + &rte_kvargs_strcmp, data->name)) +return -1 ;return 0 ; }
Signature · 1 line
2.11.0
PATCH v4 20/20 app/testpmd: add show device command
In reply to Gaetan RivetA 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
@@ -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
v5 cover Device querying
In reply to Gaetan RivetThis patchset introduces a new EAL API for querying devices, filtered by arbitrary properties.
The following elements are introduced to this end:
* A new object, "rte_class", is used to describe the device class abstraction layer (eth, crypto, ...).
* Both rte_bus and rte_class now offer a way to
list their devices and filter the result
using locally defined properties.
* The rte_dev API now has an rte_dev_iterator, which is the way for the user to define the device filter and iterate upon the resulting set.
As an example, the "eth" device class is implemented.
Additionally, the device filters for
+ rte_bus_pci
+ rte_bus_vdev
+ rte_class_eth
are implemented and can be used with some
properties each, to show how to extend those.
Some example of filters:
"bus=pci/class=eth"
"bus=pci"
"class=eth"
"class=eth,name=net_ring0"
"bus=pci,id=00:00.0"
"bus=vdev,driver=net_ring"
---
v2:
* Reworked the dev_iterate callback to simplify
its implementation.
Now dev_iterate implementation do not need to learn about the intricacies of the rte_dev_iterator. The rte_dev_iterator is managed purely by the rte_dev_iterator_next function. Buses and classes then do not have to care about settings things right.
Additionally, dev_iterate implementations do not have to sanitize their dev string anymore, they are prepared by the rte_dev layer prior, which also reduces the number of dynamic allocations.
v3:
* Introduced central constructor priority list.
* Removed lightweight kvarg parsing utility,
using librte_kvargs instead.
* Reversed dependencies of librte_kvargs and
librte_eal.
* Fixed a few bugs.
* @Bruce: I have noted the request for meson support.
I will install it and attempt it once the bulk of the work is done.
v4:
* Fixed a few bugs, added relevant acks,
fixed some typos.
* Made each matching functions actually check for a proper list of accepted properties.
* rte_kvargs now includes rte_eal directly and keeps rte_log.
* added generic string comparison function to rte_kvargs, as some kind of comparison should probably be shared by many layers.
v5:
* Rebased on master
* Use strcspn instead of custom function.
* Introduce private generic rte_eth_dev iterator. This could be generalized to other iterators (port_next, owner_id-aware, etc).
* Attempted to support meson.build.
Got lost in the implicit variables declared when inversing dependencies between kvargs and EAL. Removed anything related to meson.
* Postponed genericization of work from device query to device declaration.
Much bigger than anticipated, will let this part get in first and iterate over it.
Gaetan Rivet (21):
kvargs: build before EAL
eal: list acceptable init priorities
eal: introduce dtor macros
eal: introduce device class abstraction eal/class: register destructor
eal/dev: add device iterator interface eal/class: add device iteration
eal/bus: add device iteration
eal/dev: implement device iteration initialization eal/dev: implement device iteration
kvargs: add generic string matching callback bus/pci: fix find device implementation bus/pci: implement device iteration and comparison bus/pci: add device matching field id bus/vdev: fix find device implementation bus/vdev: implement device iteration bus/vdev: add device matching field driver
ethdev: add private generic device iterator
ethdev: register ether layer as a class
ethdev: add device matching field name app/testpmd: add show device command
app/test-pmd/cmdline.c | 52 ++++
drivers/bus/pci/Makefile | 2 +-
drivers/bus/pci/pci_common.c | 87 +++++-
drivers/bus/pci/rte_bus_pci.h | 3 +
drivers/bus/vdev/Makefile | 3 +-
drivers/bus/vdev/rte_bus_vdev.h | 3 +
drivers/bus/vdev/vdev.c | 66 ++++-
lib/Makefile | 7 +-
lib/librte_eal/bsdapp/eal/Makefile | 2 +
lib/librte_eal/common/Makefile | 4 +-
lib/librte_eal/common/eal_common_class.c | 62 ++++
lib/librte_eal/common/eal_common_dev.c | 316 +++++++++++++++++++++
lib/librte_eal/common/eal_common_log.c | 2 +-
lib/librte_eal/common/include/rte_bus.h | 3 +-
lib/librte_eal/common/include/rte_class.h | 127 +++++++++
lib/librte_eal/common/include/rte_common.h | 32 ++-
lib/librte_eal/common/include/rte_dev.h | 97 +++++++
lib/librte_eal/linuxapp/eal/Makefile | 2 +
lib/librte_eal/rte_eal_version.map | 4 +
lib/librte_ether/Makefile | 4 +-
lib/librte_ether/eth_private.c | 32 +++
lib/librte_ether/eth_private.h | 26 ++
lib/librte_ether/rte_class_eth.c | 86 ++++++
lib/librte_kvargs/Makefile | 3 +-
lib/librte_kvargs/rte_kvargs.c | 12 +-
lib/librte_kvargs/rte_kvargs.h | 28 ++
lib/librte_kvargs/rte_kvargs_version.map | 7 +
.../include => librte_kvargs}/rte_string_fns.h | 0
28 files changed, 1045 insertions(+), 27 deletions(-)
create mode 100644 lib/librte_eal/common/eal_common_class.c
create mode 100644 lib/librte_eal/common/include/rte_class.h
create mode 100644 lib/librte_ether/eth_private.c
create mode 100644 lib/librte_ether/eth_private.h
create mode 100644 lib/librte_ether/rte_class_eth.c
rename lib/{librte_eal/common/include => librte_kvargs}/rte_string_fns.h (100%)Signature · 1 line
2.11.0
PATCH v5 1/21 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
@@ -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
@@ -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
@@ -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
@@ -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
Signature · 1 line
2.11.0
PATCH v5 2/21 eal: list acceptable init priorities
In reply to Gaetan RivetBuild 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
@@ -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
@@ -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
@@ -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
Re: [PATCH v5 02/21] eal: list acceptable init priorities
Quoted 57 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.
Signed-off-by Gaetan Rivet <[email protected]>Acked-by Neil Horman <[email protected]>Acked-by Shreyansh Jain <[email protected]>--- 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@@ -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@@ -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@@ -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 112
Quoted 6 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.
Neil
Quoted 6 lines
lib/librte_eal/common/include/rte_common.h +0
-0/** * Force a function to be inlined Signature · 1 line
2.11.0
Re: [PATCH v5 02/21] eal: list acceptable init priorities
Hello Neil,
Quoted 70 lines · Neil Horman
Quoted 57 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.
Signed-off-by Gaetan Rivet <[email protected]>Acked-by Neil Horman <[email protected]>Acked-by Shreyansh Jain <[email protected]>--- 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@@ -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@@ -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@@ -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 112
Quoted 6 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_LASTpriority, and redefineRTE_INITtoRTE_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 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.
I'd be curious to hear if anyone has had issues of this kind.
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v5 02/21] eal: list acceptable init priorities
Quoted 73 lines · Gaëtan Rivet
Hello Neil,
Quoted 70 lines · Neil Horman
Quoted 57 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.
Signed-off-by Gaetan Rivet <[email protected]>Acked-by Neil Horman <[email protected]>Acked-by Shreyansh Jain <[email protected]>--- 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@@ -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@@ -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@@ -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 112
Quoted 6 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_LASTpriority, and redefineRTE_INITtoRTE_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_LASTis pretty harmless, but I'm not sure it's justified to add it. If you still think it is useful, I will do it.
It was more just a way to unify the macros is all, probably not important.
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
Neil
Quoted 4 lines
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v5 02/21] eal: list acceptable init priorities
Quoted 83 lines · Neil Horman
Quoted 73 lines · Gaëtan Rivet
Hello Neil,
Quoted 70 lines · Neil Horman
Quoted 57 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.
Signed-off-by Gaetan Rivet <[email protected]>Acked-by Neil Horman <[email protected]>Acked-by Shreyansh Jain <[email protected]>--- 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@@ -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@@ -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@@ -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 112
Quoted 6 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_LASTpriority, and redefineRTE_INITtoRTE_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_LASTis 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]
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
Neil
Quoted 4 lines
Signature · 2 lines
Gaëtan Rivet 6WIND
Re: [PATCH v5 02/21] eal: list acceptable init priorities
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.
Signed-off-by Gaetan Rivet <[email protected]>Acked-by Neil Horman <[email protected]>Acked-by Shreyansh Jain <[email protected]>--- 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@@ -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@@ -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@@ -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_LASTpriority, and redefineRTE_INITtoRTE_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_LASTis 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_PRIORITY65536, is used.--->8---
gcc/collect2.c---
/* Extractinit_pnumber 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]
A specified value for
RTE_PRIORITY_LASTis not a bad option - it would help in keeping the priorities bound without relying on the unknown of priority for unspecified constructors.
This is interesting, thanks for looking up the GCC code. Ok, unless someone has a strong reason not to, I will add RTE_PRIORITY_LAST. Not really convinced about it but not opposed enough either :) .
Regards,
Signature · 2 lines
Gaëtan Rivet 6WIND