diff --git a/app/test/test_tailq.c b/app/test/test_tailq.c
index 56656f0..c046a8a 100644
--- a/app/test/test_tailq.c
+++ b/app/test/test_tailq.c
@@ -34,6 +34,7 @@
 #include <stdio.h>
 #include <stdint.h>
 #include <stdarg.h>
+#include <string.h>
 #include <errno.h>
 #include <sys/queue.h>
 
@@ -49,40 +50,59 @@
 	return 1; \
 } while (0)
 
-#define DEFAULT_TAILQ (RTE_TAILQ_NUM)
+static struct rte_tailq_elem rte_dummy_tailq = {
+	.name = "dummy",
+};
+EAL_REGISTER_TAILQ(rte_dummy_tailq)
+
+static struct rte_tailq_elem rte_dummy_dyn_tailq = {
+	.name = "dummy_dyn",
+};
+static struct rte_tailq_elem rte_dummy_dyn2_tailq = {
+	.name = "dummy_dyn",
+};
 
 static struct rte_tailq_entry d_elem;
+static struct rte_tailq_entry d_dyn_elem;
 
 static int
-test_tailq_create(void)
+test_tailq_early(void)
 {
 	struct rte_tailq_entry_head *d_head;
-	unsigned i;
 
-	/* create a first tailq and check its non-null */
-	d_head = RTE_TAILQ_LOOKUP_BY_IDX(DEFAULT_TAILQ, rte_tailq_entry_head);
+	d_head = RTE_TAILQ_CAST(rte_dummy_tailq.head, rte_tailq_entry_head);
 	if (d_head == NULL)
-		do_return("Error allocating dummy_q0\n");
+		do_return("Error %s has not been initialised\n",
+			  rte_dummy_tailq.name);
 
-	/* check we can add an item to it
-	 */
+	/* check we can add an item to it */
 	TAILQ_INSERT_TAIL(d_head, &d_elem, next);
 
-	/* try allocating dummy_q0 again, and check for failure */
-	if (RTE_TAILQ_LOOKUP_BY_IDX(DEFAULT_TAILQ, rte_tailq_entry_head) == NULL)
-		do_return("Error, non-null result returned when attemption to "
-				"re-allocate a tailq\n");
+	return 0;
+}
+
+static int
+test_tailq_create(void)
+{
+	struct rte_tailq_entry_head *d_head;
+
+	/* create a tailq and check its non-null (since we are post-eal init) */
+	if ((rte_eal_tailq_register(&rte_dummy_dyn_tailq) < 0) ||
+	    (rte_dummy_dyn_tailq.head == NULL))
+		do_return("Error allocating %s\n", rte_dummy_dyn_tailq.name);
+
+	d_head = RTE_TAILQ_CAST(rte_dummy_dyn_tailq.head, rte_tailq_entry_head);
 
-	/* now fill up the tailq slots available and check we get an error */
-	for (i = RTE_TAILQ_NUM; i < RTE_MAX_TAILQ; i++){
-		if ((d_head = RTE_TAILQ_LOOKUP_BY_IDX(i,
-				rte_tailq_entry_head)) == NULL)
-			break;
-	}
+	/* check we can add an item to it */
+	TAILQ_INSERT_TAIL(d_head, &d_dyn_elem, next);
 
-	/* check that we had an error return before RTE_MAX_TAILQ */
-	if (i != RTE_MAX_TAILQ)
-		do_return("Error, we did not have a reservation as expected\n");
+	if (strcmp(rte_dummy_dyn2_tailq.name, rte_dummy_dyn_tailq.name))
+		do_return("Error, something is wrong in the tailq test\n");
+
+	/* try allocating again, and check for failure */
+	if (!rte_eal_tailq_register(&rte_dummy_dyn2_tailq))
+		do_return("Error, registering the same tailq %s did not fail\n",
+			  rte_dummy_dyn2_tailq.name);
 
 	return 0;
 }
@@ -94,8 +114,10 @@ test_tailq_lookup(void)
 	struct rte_tailq_entry_head *d_head;
 	struct rte_tailq_entry *d_ptr;
 
-	d_head = RTE_TAILQ_LOOKUP_BY_IDX(DEFAULT_TAILQ, rte_tailq_entry_head);
-	if (d_head == NULL)
+	d_head = RTE_TAILQ_LOOKUP(rte_dummy_tailq.name, rte_tailq_entry_head);
+	/* rte_dummy_tailq has been registered by EAL_REGISTER_TAILQ */
+	if (d_head == NULL ||
+	    d_head != RTE_TAILQ_CAST(rte_dummy_tailq.head, rte_tailq_entry_head))
 		do_return("Error with tailq lookup\n");
 
 	TAILQ_FOREACH(d_ptr, d_head, next)
@@ -103,8 +125,19 @@ test_tailq_lookup(void)
 			do_return("Error with tailq returned from lookup - "
 					"expected element not found\n");
 
+	d_head = RTE_TAILQ_LOOKUP(rte_dummy_dyn_tailq.name, rte_tailq_entry_head);
+	/* rte_dummy_dyn_tailq has been registered by test_tailq_create */
+	if (d_head == NULL ||
+	    d_head != RTE_TAILQ_CAST(rte_dummy_dyn_tailq.head, rte_tailq_entry_head))
+		do_return("Error with tailq lookup\n");
+
+	TAILQ_FOREACH(d_ptr, d_head, next)
+		if (d_ptr != &d_dyn_elem)
+			do_return("Error with tailq returned from lookup - "
+					"expected element not found\n");
+
 	/* now try a bad/error lookup */
-	d_head = RTE_TAILQ_LOOKUP_BY_IDX(RTE_MAX_TAILQ, rte_tailq_entry_head);
+	d_head = RTE_TAILQ_LOOKUP("coucou", rte_tailq_entry_head);
 	if (d_head != NULL)
 		do_return("Error, lookup does not return NULL for bad tailq name\n");
 
@@ -115,6 +148,7 @@ static int
 test_tailq(void)
 {
 	int ret = 0;
+	ret |= test_tailq_early();
 	ret |= test_tailq_create();
 	ret |= test_tailq_lookup();
 	return ret;
diff --git a/lib/librte_eal/bsdapp/eal/rte_eal_version.map b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
index c94fe8e..e42ea74 100644
--- a/lib/librte_eal/bsdapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/bsdapp/eal/rte_eal_version.map
@@ -45,6 +45,7 @@ DPDK_2.0 {
 	rte_eal_remote_launch;
 	rte_eal_tailq_lookup;
 	rte_eal_tailq_lookup_by_idx;
+	rte_eal_tailq_register;
 	rte_eal_wait_lcore;
 	rte_exit;
 	rte_get_hpet_cycles;
diff --git a/lib/librte_eal/common/eal_common_tailqs.c b/lib/librte_eal/common/eal_common_tailqs.c
index 975ee74..3c4e70d 100644
--- a/lib/librte_eal/common/eal_common_tailqs.c
+++ b/lib/librte_eal/common/eal_common_tailqs.c
@@ -51,6 +51,7 @@
 #include <rte_branch_prediction.h>
 #include <rte_log.h>
 #include <rte_string_fns.h>
+#include <rte_debug.h>
 
 #include "eal_private.h"
 
@@ -62,6 +63,14 @@ const char* rte_tailq_names[RTE_MAX_TAILQ] = {
 #include <rte_tailq_elem.h>
 };
 
+TAILQ_HEAD(rte_tailq_elem_head, rte_tailq_elem);
+/* local tailq list */
+static struct rte_tailq_elem_head rte_tailq_elem_head =
+	TAILQ_HEAD_INITIALIZER(rte_tailq_elem_head);
+
+/* number of tailqs registered, -1 before call to rte_eal_tailqs_init */
+static int rte_tailqs_count = -1;
+
 struct rte_tailq_head *
 rte_eal_tailq_lookup(const char *name)
 {
@@ -72,9 +81,13 @@ rte_eal_tailq_lookup(const char *name)
 		return NULL;
 
 	for (i = 0; i < RTE_MAX_TAILQ; i++) {
-		if (rte_tailq_names[i] == NULL)
-			continue;
-		if (!strncmp(name, rte_tailq_names[i], RTE_TAILQ_NAMESIZE-1))
+		if (i < RTE_TAILQ_NUM &&
+		    !strncmp(name, rte_tailq_names[i], RTE_TAILQ_NAMESIZE-1))
+			return &mcfg->tailq_head[i];
+
+		/* if past static entries, look at shared mem for names */
+		if (!strncmp(name, mcfg->tailq_head[i].name,
+			     RTE_TAILQ_NAMESIZE-1))
 			return &mcfg->tailq_head[i];
 	}
 
@@ -103,31 +116,130 @@ rte_dump_tailq(FILE *f)
 	mcfg = rte_eal_get_configuration()->mem_config;
 
 	rte_rwlock_read_lock(&mcfg->qlock);
-	for (i=0; i < RTE_MAX_TAILQ; i++) {
+	for (i = 0; i < RTE_MAX_TAILQ; i++) {
 		const struct rte_tailq_head *tailq = &mcfg->tailq_head[i];
 		const struct rte_tailq_entry_head *head = &tailq->tailq_head;
+		const char *name = "nil";
 
-		fprintf(f, "Tailq %u: qname:<%s>, tqh_first:%p, tqh_last:%p\n", i,
-		       (rte_tailq_names[i] != NULL ? rte_tailq_names[i]:"nil"),
-		       head->tqh_first, head->tqh_last);
+		if (rte_tailq_names[i])
+			name = rte_tailq_names[i];
+		else if (tailq->name)
+			name = tailq->name;
+
+		fprintf(f, "Tailq %u: qname:<%s>, tqh_first:%p, tqh_last:%p\n",
+			i, name, head->tqh_first, head->tqh_last);
 	}
 	rte_rwlock_read_unlock(&mcfg->qlock);
 }
 
+static struct rte_tailq_head *
+rte_eal_tailq_create(const char *name)
+{
+	struct rte_tailq_head *head = NULL;
+
+	if (!rte_eal_tailq_lookup(name) &&
+	    (rte_tailqs_count + 1 < RTE_MAX_TAILQ)) {
+		struct rte_mem_config *mcfg;
+
+		mcfg = rte_eal_get_configuration()->mem_config;
+		head = &mcfg->tailq_head[rte_tailqs_count];
+		snprintf(head->name, sizeof(head->name) - 1, "%s", name);
+		TAILQ_INIT(&head->tailq_head);
+		rte_tailqs_count++;
+	}
+
+	return head;
+}
+
+/* local register, used to store "early" tailqs before rte_eal_init() and to
+ * ensure secondary process only registers tailqs once. */
+static int
+rte_eal_tailq_local_register(struct rte_tailq_elem *t)
+{
+	struct rte_tailq_elem *temp;
+
+	TAILQ_FOREACH(temp, &rte_tailq_elem_head, next) {
+		if (!strncmp(t->name, temp->name, sizeof(temp->name)))
+			return -1;
+	}
+
+	TAILQ_INSERT_TAIL(&rte_tailq_elem_head, t, next);
+	return 0;
+}
+
+static void
+rte_eal_tailq_update(struct rte_tailq_elem *t)
+{
+	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
+		/* primary process is the only one that creates */
+		t->head = rte_eal_tailq_create(t->name);
+	} else {
+		t->head = rte_eal_tailq_lookup(t->name);
+	}
+}
+
+int
+rte_eal_tailq_register(struct rte_tailq_elem *t)
+{
+	if (rte_eal_tailq_local_register(t) < 0) {
+		rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL,
+			"%s tailq is already registered\n", t->name);
+		goto error;
+	}
+
+	/* if a register happens after rte_eal_tailqs_init(), then we can update
+	 * tailq head */
+	if (rte_tailqs_count >= 0) {
+		rte_eal_tailq_update(t);
+		if (t->head == NULL) {
+			rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL,
+				"Cannot initialize tailq: %s\n", t->name);
+			TAILQ_REMOVE(&rte_tailq_elem_head, t, next);
+			goto error;
+		}
+	}
+
+	return 0;
+
+error:
+	t->head = NULL;
+	return -1;
+}
+
 int
 rte_eal_tailqs_init(void)
 {
 	unsigned i;
 	struct rte_mem_config *mcfg = NULL;
+	struct rte_tailq_elem *t;
 
 	RTE_BUILD_BUG_ON(RTE_MAX_TAILQ < RTE_TAILQ_NUM);
 
 	if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
 		mcfg = rte_eal_get_configuration()->mem_config;
-		for (i = 0; i < RTE_MAX_TAILQ; i++)
+		for (i = 0; i < RTE_TAILQ_NUM; i++)
 			TAILQ_INIT(&mcfg->tailq_head[i].tailq_head);
 	}
 
+	/* mark those static entries as already taken */
+	rte_tailqs_count = RTE_TAILQ_NUM;
+
+	TAILQ_FOREACH(t, &rte_tailq_elem_head, next) {
+		/* second part of register job for "early" tailqs, see
+		 * rte_eal_tailq_register and EAL_REGISTER_TAILQ */
+		rte_eal_tailq_update(t);
+		if (t->head == NULL) {
+			rte_log(RTE_LOG_ERR, RTE_LOGTYPE_EAL,
+				"Cannot initialize tailq: %s\n", t->name);
+			/* no need to TAILQ_REMOVE, we are going to panic in
+			 * rte_eal_init() */
+			goto fail;
+		}
+	}
+
 	return 0;
-}
 
+fail:
+	rte_dump_tailq(stderr);
+	return -1;
+}
diff --git a/lib/librte_eal/common/include/rte_tailq.h b/lib/librte_eal/common/include/rte_tailq.h
index 6b7278c..df11183 100644
--- a/lib/librte_eal/common/include/rte_tailq.h
+++ b/lib/librte_eal/common/include/rte_tailq.h
@@ -46,6 +46,7 @@ extern "C" {
 
 #include <sys/queue.h>
 #include <stdio.h>
+#include <rte_debug.h>
 
 /** dummy structure type used by the rte_tailq APIs */
 struct rte_tailq_entry {
@@ -67,6 +68,17 @@ TAILQ_HEAD(rte_tailq_entry_head, rte_tailq_entry);
  */
 struct rte_tailq_head {
 	struct rte_tailq_entry_head tailq_head; /**< NOTE: must be first element */
+	char name[RTE_TAILQ_NAMESIZE];
+};
+
+struct rte_tailq_elem {
+	/**
+	 * Reference to head in shared mem, updated at init time by
+	 * rte_eal_tailqs_init()
+	 */
+	struct rte_tailq_head *head;
+	TAILQ_ENTRY(rte_tailq_elem) next;
+	const char name[RTE_TAILQ_NAMESIZE];
 };
 
 /**
@@ -151,6 +163,32 @@ struct rte_tailq_head *rte_eal_tailq_lookup(const char *name);
  */
 struct rte_tailq_head *rte_eal_tailq_lookup_by_idx(const unsigned idx);
 
+/**
+ * Register a tail queue.
+ *
+ * Register a tail queue from shared memory.
+ * This function is mainly used by EAL_REGISTER_TAILQ macro which is used to
+ * register tailq from the different dpdk libraries. Since this macro is a
+ * constructor, the function has no access to dpdk shared memory, so the
+ * registered tailq can not be used before call to rte_eal_init() which calls
+ * rte_eal_tailqs_init().
+ *
+ * @param t
+ *   The tailq element which contains the name of the tailq you want to
+ *   create (/retrieve when in secondary process).
+ * @return
+ *   0 on success or -1 in case of an error.
+ */
+int rte_eal_tailq_register(struct rte_tailq_elem *t);
+
+#define EAL_REGISTER_TAILQ(t) \
+void tailqinitfn_ ##t(void); \
+void __attribute__((constructor, used)) tailqinitfn_ ##t(void) \
+{ \
+	if (rte_eal_tailq_register(&t) < 0) \
+		rte_panic("Cannot initialize tailq: %s\n", t.name); \
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/lib/librte_eal/linuxapp/eal/rte_eal_version.map b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
index a1ba203..3db5856 100644
--- a/lib/librte_eal/linuxapp/eal/rte_eal_version.map
+++ b/lib/librte_eal/linuxapp/eal/rte_eal_version.map
@@ -49,6 +49,7 @@ DPDK_2.0 {
 	rte_eal_remote_launch;
 	rte_eal_tailq_lookup;
 	rte_eal_tailq_lookup_by_idx;
+	rte_eal_tailq_register;
 	rte_eal_vdev_init;
 	rte_eal_vdev_uninit;
 	rte_eal_wait_lcore;
