diff --git a/lib/librte_queue/rte_queue.c b/lib/librte_queue/rte_queue.c
new file mode 100644
index 0000000..ddde778
--- /dev/null
+++ b/lib/librte_queue/rte_queue.c
@@ -0,0 +1,122 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Arm
+ */
+
+#include <sys/queue.h>
+#include <string.h>
+
+#include <rte_tailq.h>
+#include <rte_memzone.h>
+#include <rte_rwlock.h>
+#include <rte_eal_memconfig.h>
+#include "rte_queue.h"
+
+TAILQ_HEAD(rte_queue_list, rte_tailq_entry);
+
+static struct rte_tailq_elem rte_queue_tailq = {
+	.name = RTE_TAILQ_QUEUE_NAME,
+};
+EAL_REGISTER_TAILQ(rte_queue_tailq)
+
+/* create the queue */
+struct rte_queue *
+rte_queue_create(struct rte_queue_ctx *instance, const char *name,
+		unsigned int count, int socket_id, unsigned int flags)
+{
+	struct rte_queue *q = NULL;
+	struct rte_tailq_entry *te;
+	struct rte_queue_list *queue_list = NULL;
+
+	RTE_FUNC_PTR_OR_ERR_RET(*instance->ops->queue_create, NULL);
+
+	queue_list = RTE_TAILQ_CAST(rte_queue_tailq.head, rte_queue_list);
+
+	te = rte_zmalloc("QUEUE_TAILQ_ENTRY", sizeof(*te), 0);
+	if (te == NULL) {
+		RTE_LOG(ERR, RING, "Cannot reserve memory for tailq\n");
+		rte_errno = ENOMEM;
+		return NULL;
+	}
+
+	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
+
+	if (instance->ops->queue_create(instance->device, count, socket_id,
+					flags, &q)) {
+		rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+		rte_free(te);
+
+		return NULL;
+	}
+
+	te->data = q;
+	TAILQ_INSERT_TAIL(queue_list, te, next);
+	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+	return q;
+}
+
+/* free the queue */
+void
+rte_queue_free(struct rte_queue_ctx *instance, struct rte_queue *q)
+{
+	struct rte_tailq_entry *te = NULL;
+	struct rte_queue_list *queue_list = NULL;
+
+	RTE_FUNC_PTR_OR_ERR_RET(*instance->ops->queue_free, 0);
+
+	queue_list = RTE_TAILQ_CAST(rte_queue_tailq.head, rte_queue_list);
+	rte_rwlock_write_lock(RTE_EAL_TAILQ_RWLOCK);
+
+	/* find out tailq entry */
+	TAILQ_FOREACH(te, queue_list, next) {
+		if (te->data == (void *) q)
+			break;
+	}
+
+	if (te == NULL) {
+		rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+		return;
+	}
+
+	TAILQ_REMOVE(queue_list, te, next);
+
+	rte_rwlock_write_unlock(RTE_EAL_TAILQ_RWLOCK);
+
+	rte_free(te);
+
+	instance->ops->queue_free(instance->device, q);
+}
+
+/* enqueue to the queue */
+unsigned int
+rte_queue_enqueue_burst(struct rte_queue_ctx *instance, struct rte_queue *q,
+		void * const *obj_table, unsigned int n,
+		unsigned int *free_space)
+{
+	return instance->ops->queue_enqueue_burst(instance->device, q,
+						obj_table, n, free_space);
+}
+
+/* dequeue from the queue */
+void
+rte_queue_dequeue_burst(struct rte_queue_ctx *instance, struct rte_queue *q,
+		void * const *obj_table, unsigned int n,
+		unsigned int *available)
+{
+	return instance->ops->queue_enqueue_burst(instance->device, q,
+						obj_table, n, available);
+}
+
+/* return size of the queue */
+void
+rte_queue_get_size(struct rte_queue_ctx *instance, struct rte_queue *q)
+{
+	return instance->ops->queue_get_size(instance->device, q);
+}
+
+/* return usable size of the queue */
+void
+rte_queue_get_capacity(struct rte_queue_ctx *instance, struct rte_queue *q)
+{
+	return instance->ops->queue_get_capacity(instance->device, q);
+}
diff --git a/lib/librte_queue/rte_queue.h b/lib/librte_queue/rte_queue.h
new file mode 100644
index 0000000..90dc34d
--- /dev/null
+++ b/lib/librte_queue/rte_queue.h
@@ -0,0 +1,200 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Arm
+ */
+
+/**
+ * @file rte_queue.h
+ * @b EXPERIMENTAL: these APIs may change without prior notice
+ *
+ * RTE Queue
+ *
+ * This provides queue APIs for passing any data from one core to another.
+ */
+
+#ifndef _RTE_QUEUE_
+#define _RTE_QUEUE_
+
+#include <stdint.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+
+#define RTE_TAILQ_QUEUE_NAME "RTE_QUEUE"
+
+/**
+ * Context for queue device
+ *
+ * Queue instance for each driver to register queue operations.
+ */
+struct rte_queue_ctx {
+	void *device;
+	/**< Queue device attached */
+	const struct rte_queue_ops *ops;
+	/**< Pointer to queue ops for the device */
+};
+
+/**
+ * Handle to the implementation specific queue
+ */
+struct rte_queue {
+	RTE_STD_C11
+	union {
+		void *private_data;
+		/**< Queue implementation specific data */
+		uintptr_t queue_handle;
+		/**< Queue handle */
+	}
+};
+
+#define RTE_QUEUE_SP_ENQ 0x0001 /**< The enqueue is "single-producer". */
+#define RTE_QUEUE_SC_DEQ 0x0002 /**< The dequeue is "single-consumer". */
+#define RTE_QUEUE_NON_BLOCK 0x0004
+/**< On the same queue, producers do not block other producers,
+ *   consumers do not block other consumers.
+ */
+
+/*
+ * Create a queue
+ *
+ * This function creates a queue and returns a handle to it.
+ *
+ * @param name
+ *   Name to be given to the queue
+ * @param count
+ *   Minimum number of elements to be stored in the queue. If this is
+ *   not a power of 2, some implementations might use extra memory.
+ * @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
+ *   An OR of the following:
+ *    - RTE_QUEUE_SP_ENQ: If this flag is set, only one producer will
+ *      use this queue at a time. Otherwise, multiple producers use
+ *      this queue simultaneously.
+ *    - RTE_QUEUE_SC_DEQ: If this flag is set, only one consumer uses
+ *      this queue at a time. Otherwise, multiple consumers may use this
+ *      queue simultaneously.
+ *    - RTE_QUEUE_NON_BLOCK: If this flag is set, underlying queue
+ *      implementation should not block threads while doing queue operations.
+ *
+ * @return
+ *   On success, the pointer to the new allocated queue. NULL on error with
+ *    rte_errno set appropriately. Possible errno values include:
+ *    - E_RTE_NO_CONFIG - function could not get pointer to rte_config structure
+ *    - E_RTE_SECONDARY - function was called from a secondary process instance
+ *    - ENOSPC - the maximum number of memzones has already been allocated
+ *    - EEXIST - a memzone with the same name already exists
+ *    - ENOMEM - no appropriate memory area found in which to create memzone
+ */
+struct rte_queue *__rte_experimental
+rte_queue_create(struct rte_queue_ctx *instance, const char *name,
+		unsigned int count, int socket_id, unsigned int flags);
+
+/**
+ * Destroy the queue.
+ *
+ * @param q
+ *   Queue to free
+ */
+void __rte_experimental
+rte_queue_free(struct rte_queue_ctx *instance, struct rte_queue *q);
+
+/**
+ * Search for a queue based on its name
+ *
+ * @param name
+ *   The name of the queue.
+ * @return
+ *   The pointer to the queue matching the name, or NULL if not found,
+ *   with rte_errno set appropriately. Possible rte_errno values include:
+ *    - ENOENT - required entry not available to return.
+ */
+struct rte_queue *
+rte_queue_lookup(const char *name);
+
+/**
+ * Enqueue a set of objects onto a queue
+ *
+ * @param q
+ *   pointer to queue
+ * @param obj_table
+ *   pointer to an array of void * pointers (objects, events, pkts etc)
+ * @param n
+ *   number of objects to add to the queue from obj_table
+ * @return
+ *   Actual number of objects enqueued.
+ */
+unsigned int __rte_experimental
+rte_queue_enqueue_burst(struct rte_queue_ctx *instance, struct rte_queue *q,
+		void * const *obj_table, unsigned int n);
+
+/**
+ * Dequeue a set of objects from a queue
+ *
+ * @param q
+ *   pointer to queue
+ * @param obj_table
+ *   pointer to an array of void * pointers (objects, events, pkts etc)
+ * @param n
+ *   number of objects to dequeue from the queue to obj_table.
+ *   obj_table is assumed to have enough space.
+ * @return
+ *   Actual number of objects dequeued from queue, 0 if queue is empty
+ */
+unsigned int __rte_experimental
+rte_queue_dequeue_burst(struct rte_queue_ctx *instance, struct rte_queue *q,
+		void * const *obj_table,
+		unsigned int n);
+
+/**
+ * Returns the number of entries stored in the queue
+ *
+ * @param q
+ *   pointer to the queue
+ * @return
+ *   the number of elements in the queue
+ */
+unsigned int __rte_experimental
+rte_queue_get_count(struct rte_queue_ctx *instance, const struct rte_queue *q);
+
+/**
+ * Returns the number of free elements in the queue
+ *
+ * @param r
+ *   pointer to the queue
+ * @return
+ *   the number of free slots in the queue, i.e. the number of events that
+ *   can be successfully enqueued before dequeue must be called
+ */
+unsigned int __rte_experimental
+rte_queue_get_free_count(struct rte_queue_ctx *instance,
+		const struct rte_queue *q);
+
+/**
+ * Return the size of the queue.
+ *
+ * @param q
+ *   A pointer to the queue structure.
+ * @return
+ *   The size of the memory used by the queue.
+ *   NOTE: this is not the same as the usable space in the queue. To query that
+ *   use ``rte_queue_get_capacity()``.
+ */
+unsigned int __rte_experimental
+rte_queue_get_size(struct rte_queue_ctx *instance, const struct rte_queue *q);
+
+/**
+ * Return total number of elements which can be stored in the queue.
+ *
+ * @param r
+ *   A pointer to the queue structure.
+ * @return
+ *   The usable size of the queue.
+ */
+unsigned int __rte_experimental
+rte_queue_get_capacity(struct rte_queue_ctx *instance,
+		const struct rte_queue *q);
+
+#endif
diff --git a/lib/librte_queue/rte_queue_driver.h b/lib/librte_queue/rte_queue_driver.h
new file mode 100644
index 0000000..742cb6c
--- /dev/null
+++ b/lib/librte_queue/rte_queue_driver.h
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2018 Arm
+ */
+
+/**
+ * @file rte_queue_driver.h
+ * @b EXPERIMENTAL: these APIs may change without prior notice
+ *
+ * Declarations for driver functions
+ *
+ */
+
+#ifndef _RTE_QUEUE_DRIVER_H_
+#define _RTE_QUEUE_DRIVER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <rte_common.h>
+#include <rte_memory.h>
+#include <rte_malloc.h>
+
+/*
+ * Create a queue
+ *
+ * This function creates a queue and returns a handle to it.
+ *
+ * @param device
+ *   Queue device
+ * @param count
+ *   number of elements to be stored in the queue. If this is not a
+ *   power of 2, some implementations might use extra memory.
+ * @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
+ *   An OR of the following:
+ *    - RTE_QUEUE_SP_ENQ: If this flag is set, only one producer uses
+ *      this queue at a time. Otherwise, multiple producers use this
+ *      queue simultaneously.
+ *    - RTE_QUEUE_SC_DEQ: If this flag is set, only one consumer uses
+ *      this queue at a time. Otherwise, multiple consumers use this
+ *      queue simultaneously.
+ * @return
+ *    - Returns 0 if the queue is created successfully.
+ *    - Returns E_RTE_NO_CONFIG - function could not get pointer to
+ *				  rte_config structure
+ *    - Returns E_RTE_SECONDARY - function was called from a secondary
+ *				  process instance
+ *    - Returns ENOSPC - the maximum number of memzones has already been
+ *			 allocated
+ *    - Returns EEXIST - a memzone with the same name already exists
+ *    - Returns ENOMEM - no appropriate memory area found in which to
+ *			 create memzone
+ */
+
+typedef int (*queue_create_t)(void *device, unsigned int count, int socket_id,
+		unsigned int flags, struct rte_queue **queue);
+
+/**
+ * De-allocate all memory used by the queue.
+ *
+ * @param q
+ *   Queue to free
+ */
+typedef int (*queue_free_t)(void *device, struct rte_queue *q);
+
+/**
+ * Enqueue a set of objects onto a queue
+ *
+ * @param q
+ *   pointer to queue
+ * @param obj_table
+ *   pointer to an array of void * pointers (objects, events, pkts etc)
+ * @param n
+ *   number of objects to add to the queue from obj_table
+ * @param free_space
+ *   if non-null, is updated to indicate the amount of free slots in the
+ *   queue once the enqueue has completed.
+ * @return
+ *   Actual number of objects enqueued.
+ */
+typedef unsigned int
+(*queue_enqueue_burst_t)(void *device, struct rte_queue *q,
+		void * const *obj_table,
+		unsigned int n, unsigned int *free_space);
+
+/**
+ * Dequeue a set of objects from a queue
+ *
+ * @param q
+ *   pointer to queue
+ * @param obj_table
+ *   pointer to an array of void * pointers (objects, events, pkts etc)
+ * @param n
+ *   number of objects to dequeue from the queue to obj_table.
+ *   obj_table is assumed to have enough space.
+ * @param available
+ *   if non-null, is updated to indicate the number of objects remaining in
+ *   the queue once the dequeue has completed
+ * @return
+ *   Actual number of objects dequeued from queue, 0 if queue is empty
+ */
+typedef unsigned int
+(*queue_dequeue_burst_t)(void *device, struct rte_queue *q,
+		void * const *obj_table,
+		unsigned int n, uint16_t *available);
+
+/**
+ * Return the size of the queue.
+ *
+ * @param q
+ *   A pointer to the queue structure.
+ * @return
+ *   The size of the data store used by the queue.
+ *   NOTE: this is not the same as the usable space in the queue. To query that
+ *   use ``rte_queue_get_capacity()``.
+ */
+typedef unsigned int
+(*queue_get_size_t)(void *device, const struct rte_queue *q);
+
+/**
+ * Return the number of elements which can be stored in the queue.
+ *
+ * @param r
+ *   A pointer to the queue structure.
+ * @return
+ *   The usable size of the queue.
+ */
+typedef unsigned int
+(*queue_get_capacity_t)(void *device, const struct rte_queue *q);
+
+/** Queue operations function pointer table */
+struct rte_queue_ops {
+	queue_create_t create;
+	/**< Queue create. */
+	queue_free_t free;
+	/**< Destroy queue. */
+	queue_enqueue_burst_t enqueue_burst;
+	/**< Enqueue objects to the queue. */
+	queue_dequeue_burst_t dequeue_burst;
+	/**< Dequeue objects from the queue. */
+	queue_get_size_t get_size;
+	/**< Get size of the memory used by the queue */
+	queue_get_capacity_t get_capacity;
+	/**< Get total number of usable slots in the queue. */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
