> -----Original Message-----
> From: Olivier Matz [mailto:olivier.matz@6wind.com]
> Sent: Monday, February 25, 2019 4:43 AM
> To: Eads, Gage <gage.eads@intel.com>
> Cc: dev@dpdk.org; arybchenko@solarflare.com; Richardson, Bruce
> <bruce.richardson@intel.com>; Ananyev, Konstantin
> <konstantin.ananyev@intel.com>; gavin.hu@arm.com;
> Honnappa.Nagarahalli@arm.com; nd@arm.com; thomas@monjalon.net
> Subject: Re: [PATCH 1/7] stack: introduce rte stack library
>
> Hi Gage,
>
> Please find few comments below.
>
> On Fri, Feb 22, 2019 at 10:06:49AM -0600, Gage Eads wrote:
> > The rte_stack library provides an API for configuration and use of a
> > bounded stack of pointers. Push and pop operations are MT-safe,
> > allowing concurrent access, and the interface supports pushing and
> > popping multiple pointers at a time.
> >
> > The library's interface is modeled after another DPDK data structure,
> > rte_ring, and its lock-based implementation is derived from the stack
> > mempool handler. An upcoming commit will migrate the stack mempool
> > handler to rte_stack.
> >
> > Signed-off-by: Gage Eads <gage.eads@intel.com>
>
> [...]
>
> > --- /dev/null
> > +++ b/doc/guides/prog_guide/stack_lib.rst
> > @@ -0,0 +1,26 @@
> > +.. SPDX-License-Identifier: BSD-3-Clause
> > + Copyright(c) 2019 Intel Corporation.
> > +
> > +Stack Library
> > +=============
> > +
> > +DPDK's stack library provides an API for configuration and use of a
> > +bounded stack of pointers.
> > +
> > +The stack library provides the following basic operations:
> > +
> > +* Create a uniquely named stack of a user-specified size and using a user-
> specified socket.
> > +
> > +* Push and pop a burst of one or more stack objects (pointers). These
> function are multi-threading safe.
> > +
> > +* Free a previously created stack.
> > +
> > +* Lookup a pointer to a stack by its name.
> > +
> > +* Query a stack's current depth and number of free entries.
>
> It seems the 80-cols limitation also applies to documentation:
> https://mails.dpdk.org/archives/dev/2019-February/124917.html
>
Sure, will fix in v2.
> [...]
>
> > --- /dev/null
> > +++ b/lib/librte_stack/rte_stack.h
> > @@ -0,0 +1,277 @@
> > +/* SPDX-License-Identifier: BSD-3-Clause
> > + * Copyright(c) 2019 Intel Corporation */
> > +
> > +/**
> > + * @file rte_stack.h
> > + * @b EXPERIMENTAL: this API may change without prior notice
> > + *
> > + * RTE Stack.
> > + * librte_stack provides an API for configuration and use of a
> > +bounded stack of
> > + * pointers. Push and pop operations are MT-safe, allowing concurrent
> > +access,
> > + * and the interface supports pushing and popping multiple pointers at a time.
> > + */
> > +
> > +#ifndef _RTE_STACK_H_
> > +#define _RTE_STACK_H_
> > +
> > +#ifdef __cplusplus
> > +extern "C" {
> > +#endif
> > +
> > +#include <rte_errno.h>
> > +#include <rte_memzone.h>
> > +#include <rte_spinlock.h>
> > +
> > +#define RTE_TAILQ_STACK_NAME "RTE_STACK"
> > +#define RTE_STACK_MZ_PREFIX "STK_"
> > +/**< The maximum length of a stack name. */ #define
> > +RTE_STACK_NAMESIZE (RTE_MEMZONE_NAMESIZE - \
> > + sizeof(RTE_STACK_MZ_PREFIX) + 1)
> > +
> > +/* Structure containing the LIFO, its current length, and a lock for
> > +mutual
> > + * exclusion.
> > + */
> > +struct rte_lifo {
> > + rte_spinlock_t lock; /**< LIFO lock */
> > + uint32_t len; /**< LIFO len */
> > + void *objs[]; /**< LIFO pointer table */ };
> > +
> > +/* The RTE stack structure contains the LIFO structure itself, plus
> > +metadata
> > + * such as its name and memzone pointer.
> > + */
> > +struct rte_stack {
> > + /** Name of the stack. */
> > + char name[RTE_STACK_NAMESIZE] __rte_cache_aligned;
> > + /** Memzone containing the rte_stack structure */
> > + const struct rte_memzone *memzone;
> > + uint32_t capacity; /**< Usable size of the stack */
> > + uint32_t flags; /**< Flags supplied at creation */
> > + struct rte_lifo lifo; /**< LIFO structure */ } __rte_cache_aligned;
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice
> > + *
> > + * @internal Push several objects on the stack (MT-safe)
> > + *
> > + * @param s
> > + * A pointer to the stack structure.
> > + * @param obj_table
> > + * A pointer to a table of void * pointers (objects).
> > + * @param n
> > + * The number of objects to push on the stack from the obj_table.
> > + * @return
> > + * Actual number of objects pushed (either 0 or *n*).
> > + */
>
> Minor: a dot is missing at the end of the title. There are few in this patch, and
> maybe in next ones.
>
Will fix.
> [...]
>
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice
> > + *
> > + * Return the number of used entries in a stack.
> > + *
> > + * @param s
> > + * A pointer to the stack structure.
> > + * @return
> > + * The number of used entries in the stack.
> > + */
> > +static __rte_always_inline unsigned int __rte_experimental
> > +rte_stack_count(struct rte_stack *s) {
> > + return (unsigned int)s->lifo.len;
> > +}
>
> The argument can be const.
>
> > +
> > +/**
> > + * @warning
> > + * @b EXPERIMENTAL: this API may change without prior notice
> > + *
> > + * Return the number of free entries in a stack.
> > + *
> > + * @param s
> > + * A pointer to the stack structure.
> > + * @return
> > + * The number of free entries in the stack.
> > + */
> > +static __rte_always_inline unsigned int __rte_experimental
> > +rte_stack_free_count(struct rte_stack *s) {
> > + return s->capacity - rte_stack_count(s); }
>
> Same here.
Unfortunately the const keyword causes a discarded-qualifiers warning in the non-blocking implementation, due to the call to rte_atomic64_read().
Thanks,
Gage
@@ -407,6 +407,12 @@ F: drivers/raw/skeleton_rawdev/
F: test/test/test_rawdev.c
F: doc/guides/prog_guide/rawdev.rst
+Stack API - EXPERIMENTAL
+M: Gage Eads <gage.eads@intel.com>
+M: Olivier Matz <olivier.matz@6wind.com>
+F: lib/librte_stack/
+F: doc/guides/prog_guide/stack_lib.rst
+
Memory Pool Drivers
-------------------
@@ -980,3 +980,8 @@ CONFIG_RTE_APP_CRYPTO_PERF=y
# Compile the eventdev application
#
CONFIG_RTE_APP_EVENTDEV=y
+
+#
+# Compile librte_stack
+#
+CONFIG_RTE_LIBRTE_STACK=y
@@ -124,6 +124,7 @@ The public API headers are grouped by topics:
[mbuf] (@ref rte_mbuf.h),
[mbuf pool ops] (@ref rte_mbuf_pool_ops.h),
[ring] (@ref rte_ring.h),
+ [stack] (@ref rte_stack.h),
[tailq] (@ref rte_tailq.h),
[bitmap] (@ref rte_bitmap.h)
@@ -56,6 +56,7 @@ INPUT = @TOPDIR@/doc/api/doxy-api-index.md \
@TOPDIR@/lib/librte_ring \
@TOPDIR@/lib/librte_sched \
@TOPDIR@/lib/librte_security \
+ @TOPDIR@/lib/librte_stack \
@TOPDIR@/lib/librte_table \
@TOPDIR@/lib/librte_telemetry \
@TOPDIR@/lib/librte_timer \
@@ -55,6 +55,7 @@ Programmer's Guide
metrics_lib
bpf_lib
ipsec_lib
+ stack_lib
source_org
dev_kit_build_system
dev_kit_root_make_help
new file mode 100644
@@ -0,0 +1,26 @@
+.. SPDX-License-Identifier: BSD-3-Clause
+ Copyright(c) 2019 Intel Corporation.
+
+Stack Library
+=============
+
+DPDK's stack library provides an API for configuration and use of a bounded stack of
+pointers.
+
+The stack library provides the following basic operations:
+
+* Create a uniquely named stack of a user-specified size and using a user-specified socket.
+
+* Push and pop a burst of one or more stack objects (pointers). These function are multi-threading safe.
+
+* Free a previously created stack.
+
+* Lookup a pointer to a stack by its name.
+
+* Query a stack's current depth and number of free entries.
+
+Implementation
+~~~~~~~~~~~~~~
+
+The stack consists of a contiguous array of pointers, a current index, and a
+spinlock. Accesses to the stack are made multi-thread safe by the spinlock.
@@ -65,6 +65,11 @@ New Features
process.
* Added support for Rx packet types list in a secondary process.
+* **Added Stack API.**
+
+ Added a new stack API for configuration and use of a bounded stack of
+ pointers. The API provides MT-safe push and pop operations that can operate
+ on one or more pointers per operation.
Removed Items
-------------
@@ -111,6 +111,8 @@ DIRS-$(CONFIG_RTE_LIBRTE_IPSEC) += librte_ipsec
DEPDIRS-librte_ipsec := librte_eal librte_mbuf librte_cryptodev librte_security
DIRS-$(CONFIG_RTE_LIBRTE_TELEMETRY) += librte_telemetry
DEPDIRS-librte_telemetry := librte_eal librte_metrics librte_ethdev
+DIRS-$(CONFIG_RTE_LIBRTE_STACK) += librte_stack
+DEPDIRS-librte_stack := librte_eal
ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y)
DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni
new file mode 100644
@@ -0,0 +1,23 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Intel Corporation
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# library name
+LIB = librte_stack.a
+
+CFLAGS += $(WERROR_FLAGS) -I$(SRCDIR) -O3
+CFLAGS += -DALLOW_EXPERIMENTAL_API
+LDLIBS += -lrte_eal
+
+EXPORT_MAP := rte_stack_version.map
+
+LIBABIVER := 1
+
+# all source are stored in SRCS-y
+SRCS-$(CONFIG_RTE_LIBRTE_STACK) := rte_stack.c
+
+# install includes
+SYMLINK-$(CONFIG_RTE_LIBRTE_STACK)-include := rte_stack.h
+
+include $(RTE_SDK)/mk/rte.lib.mk
new file mode 100644
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: BSD-3-Clause
+# Copyright(c) 2019 Intel Corporation
+
+allow_experimental_apis = true
+
+version = 1
+sources = files('rte_stack.c')
+headers = files('rte_stack.h')
new file mode 100644
@@ -0,0 +1,194 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#include <string.h>
+
+#include <rte_atomic.h>
+#include <rte_eal.h>
+#include <rte_eal_memconfig.h>
+#include <rte_errno.h>
+#include <rte_malloc.h>
+#include <rte_memzone.h>
+#include <rte_rwlock.h>
+#include <rte_tailq.h>
+
+#include "rte_stack.h"
+#include "rte_stack_pvt.h"
+
+int stack_logtype;
+
+TAILQ_HEAD(rte_stack_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_stack_tailq = {
+ .name = RTE_TAILQ_STACK_NAME,
+};
+EAL_REGISTER_TAILQ(rte_stack_tailq)
+
+static void
+lifo_init(struct rte_stack *s)
+{
+ rte_spinlock_init(&s->lifo.lock);
+}
+
+static void
+rte_stack_init(struct rte_stack *s)
+{
+ memset(s, 0, sizeof(*s));
+
+ lifo_init(s);
+}
+
+static ssize_t
+rte_stack_get_memsize(unsigned int count)
+{
+ ssize_t sz = sizeof(struct rte_stack);
+
+ /* Add padding to avoid false sharing conflicts */
+ sz += RTE_CACHE_LINE_ROUNDUP(count * sizeof(void *)) +
+ 2 * RTE_CACHE_LINE_SIZE;
+
+ return sz;
+}
+
+struct rte_stack *
+rte_stack_create(const char *name, unsigned int count, int socket_id,
+ uint32_t flags)
+{
+ char mz_name[RTE_MEMZONE_NAMESIZE];
+ struct rte_stack_list *stack_list;
+ const struct rte_memzone *mz;
+ struct rte_tailq_entry *te;
+ struct rte_stack *s;
+ unsigned int sz;
+ int ret;
+
+ RTE_SET_USED(flags);
+
+ sz = rte_stack_get_memsize(count);
+
+ ret = snprintf(mz_name, sizeof(mz_name), "%s%s",
+ RTE_STACK_MZ_PREFIX, name);
+ if (ret < 0 || ret >= (int)sizeof(mz_name)) {
+ rte_errno = ENAMETOOLONG;
+ return NULL;
+ }
+
+ te = rte_zmalloc("STACK_TAILQ_ENTRY", sizeof(*te), 0);
+ if (te == NULL) {
+ STACK_LOG_ERR("Cannot reserve memory for tailq\n");
+ rte_errno = ENOMEM;
+ return NULL;
+ }
+
+ rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
+
+ mz = rte_memzone_reserve_aligned(mz_name, sz, socket_id,
+ 0, __alignof__(*s));
+ if (mz == NULL) {
+ STACK_LOG_ERR("Cannot reserve stack memzone!\n");
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+ rte_free(te);
+ return NULL;
+ }
+
+ s = mz->addr;
+
+ rte_stack_init(s);
+
+ /* Store the name for later lookups */
+ ret = snprintf(s->name, sizeof(s->name), "%s", name);
+ if (ret < 0 || ret >= (int)sizeof(s->name)) {
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+ rte_errno = ENAMETOOLONG;
+ rte_free(te);
+ rte_memzone_free(mz);
+ return NULL;
+ }
+
+ s->memzone = mz;
+ s->capacity = count;
+ s->flags = flags;
+
+ te->data = s;
+
+ stack_list = RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list);
+
+ TAILQ_INSERT_TAIL(stack_list, te, next);
+
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+ return s;
+}
+
+void
+rte_stack_free(struct rte_stack *lifo)
+{
+ struct rte_stack_list *stack_list;
+ struct rte_tailq_entry *te;
+
+ if (lifo == NULL)
+ return;
+
+ stack_list = RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list);
+ rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
+
+ /* find out tailq entry */
+ TAILQ_FOREACH(te, stack_list, next) {
+ if (te->data == lifo)
+ break;
+ }
+
+ if (te == NULL) {
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+ return;
+ }
+
+ TAILQ_REMOVE(stack_list, te, next);
+
+ rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+ rte_free(te);
+
+ rte_memzone_free(lifo->memzone);
+}
+
+struct rte_stack *
+rte_stack_lookup(const char *name)
+{
+ struct rte_stack_list *stack_list;
+ struct rte_tailq_entry *te;
+ struct rte_stack *r = NULL;
+
+ if (name == NULL) {
+ rte_errno = EINVAL;
+ return NULL;
+ }
+
+ stack_list = RTE_TAILQ_CAST(rte_stack_tailq.head, rte_stack_list);
+
+ rte_rwlock_read_lock(RTE_EAL_TAILQ_RWLOCK);
+
+ TAILQ_FOREACH(te, stack_list, next) {
+ r = (struct rte_stack *) te->data;
+ if (strncmp(name, r->name, RTE_STACK_NAMESIZE) == 0)
+ break;
+ }
+
+ rte_rwlock_read_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+ if (te == NULL) {
+ rte_errno = ENOENT;
+ return NULL;
+ }
+
+ return r;
+}
+
+RTE_INIT(librte_stack_init_log)
+{
+ stack_logtype = rte_log_register("lib.stack");
+ if (stack_logtype >= 0)
+ rte_log_set_level(stack_logtype, RTE_LOG_NOTICE);
+}
new file mode 100644
@@ -0,0 +1,277 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+/**
+ * @file rte_stack.h
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * RTE Stack.
+ * librte_stack provides an API for configuration and use of a bounded stack of
+ * pointers. Push and pop operations are MT-safe, allowing concurrent access,
+ * and the interface supports pushing and popping multiple pointers at a time.
+ */
+
+#ifndef _RTE_STACK_H_
+#define _RTE_STACK_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_errno.h>
+#include <rte_memzone.h>
+#include <rte_spinlock.h>
+
+#define RTE_TAILQ_STACK_NAME "RTE_STACK"
+#define RTE_STACK_MZ_PREFIX "STK_"
+/**< The maximum length of a stack name. */
+#define RTE_STACK_NAMESIZE (RTE_MEMZONE_NAMESIZE - \
+ sizeof(RTE_STACK_MZ_PREFIX) + 1)
+
+/* Structure containing the LIFO, its current length, and a lock for mutual
+ * exclusion.
+ */
+struct rte_lifo {
+ rte_spinlock_t lock; /**< LIFO lock */
+ uint32_t len; /**< LIFO len */
+ void *objs[]; /**< LIFO pointer table */
+};
+
+/* The RTE stack structure contains the LIFO structure itself, plus metadata
+ * such as its name and memzone pointer.
+ */
+struct rte_stack {
+ /** Name of the stack. */
+ char name[RTE_STACK_NAMESIZE] __rte_cache_aligned;
+ /** Memzone containing the rte_stack structure */
+ const struct rte_memzone *memzone;
+ uint32_t capacity; /**< Usable size of the stack */
+ uint32_t flags; /**< Flags supplied at creation */
+ struct rte_lifo lifo; /**< LIFO structure */
+} __rte_cache_aligned;
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * @internal Push several objects on the stack (MT-safe)
+ *
+ * @param s
+ * A pointer to the stack structure.
+ * @param obj_table
+ * A pointer to a table of void * pointers (objects).
+ * @param n
+ * The number of objects to push on the stack from the obj_table.
+ * @return
+ * Actual number of objects pushed (either 0 or *n*).
+ */
+static __rte_always_inline unsigned int __rte_experimental
+rte_lifo_push(struct rte_stack *s, void * const *obj_table, unsigned int n)
+{
+ unsigned int index;
+ void **cache_objs;
+
+ rte_spinlock_lock(&s->lifo.lock);
+ cache_objs = &s->lifo.objs[s->lifo.len];
+
+ /* Is there sufficient space in the stack? */
+ if ((s->lifo.len + n) > s->capacity) {
+ rte_spinlock_unlock(&s->lifo.lock);
+ return 0;
+ }
+
+ /* Add elements back into the cache */
+ for (index = 0; index < n; ++index, obj_table++)
+ cache_objs[index] = *obj_table;
+
+ s->lifo.len += n;
+
+ rte_spinlock_unlock(&s->lifo.lock);
+ return n;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Push several objects on the stack (MT-safe)
+ *
+ * @param s
+ * A pointer to the stack structure.
+ * @param obj_table
+ * A pointer to a table of void * pointers (objects).
+ * @param n
+ * The number of objects to push on the stack from the obj_table.
+ * @return
+ * Actual number of objects pushed (either 0 or *n*).
+ */
+static __rte_always_inline unsigned int __rte_experimental
+rte_stack_push(struct rte_stack *s, void * const *obj_table, unsigned int n)
+{
+ return rte_lifo_push(s, obj_table, n);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * @internal Pop several objects from the stack (MT-safe)
+ *
+ * @param s
+ * A pointer to the stack structure.
+ * @param obj_table
+ * A pointer to a table of void * pointers (objects).
+ * @param n
+ * The number of objects to pull from the stack.
+ * @return
+ * Actual number of objects popped (either 0 or *n*).
+ */
+static __rte_always_inline unsigned int __rte_experimental
+rte_lifo_pop(struct rte_stack *s, void **obj_table, unsigned int n)
+{
+ unsigned int index, len;
+ void **cache_objs;
+
+ rte_spinlock_lock(&s->lifo.lock);
+
+ if (unlikely(n > s->lifo.len)) {
+ rte_spinlock_unlock(&s->lifo.lock);
+ return 0;
+ }
+
+ cache_objs = s->lifo.objs;
+
+ for (index = 0, len = s->lifo.len - 1; index < n;
+ ++index, len--, obj_table++)
+ *obj_table = cache_objs[len];
+
+ s->lifo.len -= n;
+ rte_spinlock_unlock(&s->lifo.lock);
+
+ return n;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Pop several objects from the stack (MT-safe)
+ *
+ * @param s
+ * A pointer to the stack structure.
+ * @param obj_table
+ * A pointer to a table of void * pointers (objects).
+ * @param n
+ * The number of objects to pull from the stack.
+ * @return
+ * Actual number of objects popped (either 0 or *n*).
+ */
+static __rte_always_inline unsigned int __rte_experimental
+rte_stack_pop(struct rte_stack *s, void **obj_table, unsigned int n)
+{
+ if (unlikely(n == 0 || obj_table == NULL))
+ return 0;
+
+ return rte_lifo_pop(s, obj_table, n);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the number of used entries in a stack.
+ *
+ * @param s
+ * A pointer to the stack structure.
+ * @return
+ * The number of used entries in the stack.
+ */
+static __rte_always_inline unsigned int __rte_experimental
+rte_stack_count(struct rte_stack *s)
+{
+ return (unsigned int)s->lifo.len;
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Return the number of free entries in a stack.
+ *
+ * @param s
+ * A pointer to the stack structure.
+ * @return
+ * The number of free entries in the stack.
+ */
+static __rte_always_inline unsigned int __rte_experimental
+rte_stack_free_count(struct rte_stack *s)
+{
+ return s->capacity - rte_stack_count(s);
+}
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Create a new stack named *name* in memory.
+ *
+ * This function uses ``memzone_reserve()`` to allocate memory for a stack of
+ * size *count*. The behavior of the stack is controlled by the *flags*.
+ *
+ * @param name
+ * The name of the stack.
+ * @param count
+ * The size of the stack.
+ * @param socket_id
+ * The *socket_id* argument is the socket identifier in case of
+ * NUMA. The value can be *SOCKET_ID_ANY* if there is no NUMA
+ * constraint for the reserved zone.
+ * @param flags
+ * Reserved for future use
+ * @return
+ * On success, the pointer to the new allocated stack. NULL on error with
+ * rte_errno set appropriately. Possible errno values include:
+ * - ENOSPC - the maximum number of memzones has already been allocated
+ * - EEXIST - a stack with the same name already exists
+ * - ENOMEM - insufficient memory to create the stack
+ * - ENAMETOOLONG - name size exceeds RTE_STACK_NAMESIZE
+ */
+struct rte_stack *__rte_experimental
+rte_stack_create(const char *name, unsigned int count, int socket_id,
+ uint32_t flags);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Free all memory used by the stack.
+ *
+ * @param s
+ * Stack to free
+ */
+void __rte_experimental
+rte_stack_free(struct rte_stack *s);
+
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice
+ *
+ * Lookup a stack by its name
+ *
+ * @param name
+ * The name of the stack.
+ * @return
+ * The pointer to the stack matching the name, or NULL if not found,
+ * with rte_errno set appropriately. Possible rte_errno values include:
+ * - ENOENT - Stack with name *name* not found.
+ * - EINVAL - *name* pointer is NULL.
+ */
+struct rte_stack * __rte_experimental
+rte_stack_lookup(const char *name);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_STACK_H_ */
new file mode 100644
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019 Intel Corporation
+ */
+
+#ifndef _RTE_STACK_PVT_H_
+#define _RTE_STACK_PVT_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <rte_log.h>
+
+extern int stack_logtype;
+
+#define STACK_LOG(level, fmt, args...) \
+ rte_log(RTE_LOG_ ##level, stack_logtype, "%s(): "fmt "\n", \
+ __func__, ##args)
+
+#define STACK_LOG_ERR(fmt, args...) \
+ STACK_LOG(ERR, fmt, ## args)
+
+#define STACK_LOG_WARN(fmt, args...) \
+ STACK_LOG(WARNING, fmt, ## args)
+
+#define STACK_LOG_INFO(fmt, args...) \
+ STACK_LOG(INFO, fmt, ## args)
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _RTE_STACK_PVT_H_ */
new file mode 100644
@@ -0,0 +1,9 @@
+EXPERIMENTAL {
+ global:
+
+ rte_stack_create;
+ rte_stack_free;
+ rte_stack_lookup;
+
+ local: *;
+};
@@ -21,7 +21,7 @@ libraries = [ 'compat', # just a header, used for versioning
'gro', 'gso', 'ip_frag', 'jobstats',
'kni', 'latencystats', 'lpm', 'member',
'power', 'pdump', 'rawdev',
- 'reorder', 'sched', 'security', 'vhost',
+ 'reorder', 'sched', 'security', 'stack', 'vhost',
#ipsec lib depends on crypto and security
'ipsec',
# add pkt framework libs which use other libs from above
@@ -87,6 +87,7 @@ _LDLIBS-$(CONFIG_RTE_LIBRTE_SECURITY) += -lrte_security
_LDLIBS-$(CONFIG_RTE_LIBRTE_COMPRESSDEV) += -lrte_compressdev
_LDLIBS-$(CONFIG_RTE_LIBRTE_EVENTDEV) += -lrte_eventdev
_LDLIBS-$(CONFIG_RTE_LIBRTE_RAWDEV) += -lrte_rawdev
+_LDLIBS-$(CONFIG_RTE_LIBRTE_STACK) += -lrte_stack
_LDLIBS-$(CONFIG_RTE_LIBRTE_TIMER) += -lrte_timer
_LDLIBS-$(CONFIG_RTE_LIBRTE_MEMPOOL) += -lrte_mempool
_LDLIBS-$(CONFIG_RTE_DRIVER_MEMPOOL_RING) += -lrte_mempool_ring