diff --git a/example/ipsec/Makefile.am b/example/ipsec/Makefile.am
index 46613065d..85905ffa7 100644
--- a/example/ipsec/Makefile.am
+++ b/example/ipsec/Makefile.am
@@ -19,12 +19,10 @@ odp_ipsec_SOURCES = odp_ipsec.c \
 		    odp_ipsec_sa_db.c \
 		    odp_ipsec_sp_db.c \
 		    odp_ipsec_fwd_db.c \
-		    odp_ipsec_loop_db.c \
 		    odp_ipsec_cache.c \
 		    odp_ipsec_stream.c \
 		    odp_ipsec_cache.h \
 		    odp_ipsec_fwd_db.h \
-		    odp_ipsec_loop_db.h \
 		    odp_ipsec_misc.h \
 		    odp_ipsec_sa_db.h \
 		    odp_ipsec_sp_db.h \
diff --git a/example/ipsec/README b/example/ipsec/README
index 74f1d26e7..a8b741c76 100644
--- a/example/ipsec/README
+++ b/example/ipsec/README
@@ -164,8 +164,7 @@ At VM2 console use tcpdump to observe IPsec packets :
 6. Standalone Loopback Tests
 
 BASH batch files are now included to run several simple loopback tests that
-do not require any packet IO.  The scripts create internal "loopback" (not
-real Linux loopback interfaces but simply ODP queues) as opposed to packet
+do not require any packet IO.  The scripts create internal "loopback" packet
 interfaces.
 Before running the example bash scripts add odp_ipsec to your PATH
 export PATH="<path_to_odp_ipsec>:$PATH"
diff --git a/example/ipsec/odp_ipsec.c b/example/ipsec/odp_ipsec.c
index 4015158ac..a69f92564 100644
--- a/example/ipsec/odp_ipsec.c
+++ b/example/ipsec/odp_ipsec.c
@@ -40,7 +40,6 @@
 #include <odp_ipsec_sa_db.h>
 #include <odp_ipsec_sp_db.h>
 #include <odp_ipsec_fwd_db.h>
-#include <odp_ipsec_loop_db.h>
 #include <odp_ipsec_cache.h>
 #include <odp_ipsec_stream.h>
 
@@ -407,76 +406,20 @@ void ipsec_init_post(crypto_api_mode_e api_mode)
 	}
 }
 
-/**
- * Initialize loopback
- *
- * Initialize ODP queues to create our own idea of loopbacks, which allow
- * testing without physical interfaces.  Interface name string will be of
- * the format "loopX" where X is the decimal number of the interface.
- *
- * @param intf     Loopback interface name string
- */
-#if 0 /* Temporarely disable loopback mode. Needs packet output event queues */
 static
-void initialize_loop(char *intf)
+int check_stream_db_out(const char *intf)
 {
-	int idx;
-	odp_queue_t outq_def;
-	odp_queue_t inq_def;
-	char queue_name[ODP_QUEUE_NAME_LEN];
-	odp_queue_param_t qparam;
-	uint8_t *mac;
-	char mac_str[MAX_STRING];
-
-	/* Derive loopback interface index */
-	idx = loop_if_index(intf);
-	if (idx < 0) {
-		EXAMPLE_ERR("Error: loopback \"%s\" invalid\n", intf);
-		exit(EXIT_FAILURE);
-	}
+	stream_db_entry_t *stream = NULL;
 
-	/* Create input queue */
-	odp_queue_param_init(&qparam);
-	qparam.type        = ODP_QUEUE_TYPE_SCHED;
-	qparam.sched.prio  = ODP_SCHED_PRIO_DEFAULT;
-	qparam.sched.sync  = ODP_SCHED_SYNC_ATOMIC;
-	qparam.sched.group = ODP_SCHED_GROUP_ALL;
-	snprintf(queue_name, sizeof(queue_name), "%i-loop_inq_def", idx);
-	queue_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
-
-	inq_def = queue_create(queue_name, &qparam);
-	if (ODP_QUEUE_INVALID == inq_def) {
-		EXAMPLE_ERR("Error: input queue creation failed for %s\n",
-			    intf);
-		exit(EXIT_FAILURE);
+	/* For each stream look for input and output IPsec entries */
+	for (stream = stream_db->list; NULL != stream; stream = stream->next) {
+		if (!strcmp(stream->output.intf, intf))
+			return 1;
 	}
-	/* Create output queue */
-	snprintf(queue_name, sizeof(queue_name), "%i-loop_outq_def", idx);
-	queue_name[ODP_QUEUE_NAME_LEN - 1] = '\0';
 
-	outq_def = queue_create(queue_name, NULL);
-	if (ODP_QUEUE_INVALID == outq_def) {
-		EXAMPLE_ERR("Error: output queue creation failed for %s\n",
-			    intf);
-		exit(EXIT_FAILURE);
-	}
-
-	/* Initialize the loopback DB entry */
-	create_loopback_db_entry(idx, inq_def, outq_def, pkt_pool);
-	mac = query_loopback_db_mac(idx);
-
-	printf("Created loop:%02i, queue mode (ATOMIC queues)\n"
-	       "          default loop%02i-INPUT queue:%" PRIu64 "\n"
-	       "          default loop%02i-OUTPUT queue:%" PRIu64 "\n"
-	       "          source mac address %s\n",
-	       idx, idx, odp_queue_to_u64(inq_def), idx,
-	       odp_queue_to_u64(outq_def),
-	       mac_addr_str(mac_str, mac));
-
-	/* Resolve any routes using this interface for output */
-	resolve_fwd_db(intf, outq_def, mac);
+	return 0;
 }
-#endif
+
 /**
  * Initialize interface
  *
@@ -499,7 +442,8 @@ void initialize_intf(char *intf)
 
 	odp_pktio_param_init(&pktio_param);
 
-	if (getenv("ODP_IPSEC_USE_POLL_QUEUES"))
+	if (getenv("ODP_IPSEC_USE_POLL_QUEUES") ||
+	    check_stream_db_out(intf))
 		pktio_param.in_mode = ODP_PKTIN_MODE_QUEUE;
 	else
 		pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
@@ -1267,7 +1211,6 @@ main(int argc, char *argv[])
 	/* Must init our databases before parsing args */
 	ipsec_init_pre();
 	init_fwd_db();
-	init_loopback_db();
 	init_stream_db();
 
 	/* Parse and store the application arguments */
@@ -1328,12 +1271,7 @@ main(int argc, char *argv[])
 
 	/* Initialize interfaces (which resolves FWD DB entries */
 	for (i = 0; i < args->appl.if_count; i++) {
-#if 0 /* Temporarely disable loopback mode. Needs packet output event queues */
-		if (!strncmp("loop", args->appl.if_names[i], strlen("loop")))
-			initialize_loop(args->appl.if_names[i]);
-		else
-#endif
-			initialize_intf(args->appl.if_names[i]);
+		initialize_intf(args->appl.if_names[i]);
 	}
 
 	/* If we have test streams build them before starting workers */
@@ -1377,9 +1315,6 @@ main(int argc, char *argv[])
 	shm = odp_shm_lookup("shm_fwd_db");
 	if (odp_shm_free(shm) != 0)
 		EXAMPLE_ERR("Error: shm free shm_fwd_db failed\n");
-	shm = odp_shm_lookup("loopback_db");
-	if (odp_shm_free(shm) != 0)
-		EXAMPLE_ERR("Error: shm free loopback_db failed\n");
 	shm = odp_shm_lookup("shm_sa_db");
 	if (odp_shm_free(shm) != 0)
 		EXAMPLE_ERR("Error: shm free shm_sa_db failed\n");
diff --git a/example/ipsec/odp_ipsec_loop_db.c b/example/ipsec/odp_ipsec_loop_db.c
deleted file mode 100644
index 1d5e404ee..000000000
--- a/example/ipsec/odp_ipsec_loop_db.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Copyright (c) 2014, Linaro Limited
- * All rights reserved.
- *
- * SPDX-License-Identifier:     BSD-3-Clause
- */
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <example_debug.h>
-
-#include <odp_api.h>
-
-#include <odp_ipsec_loop_db.h>
-
-loopback_db_t *loopback_db;
-
-void init_loopback_db(void)
-{
-	int idx;
-	odp_shm_t shm;
-
-	shm = odp_shm_reserve("loopback_db",
-			      sizeof(loopback_db_t),
-			      ODP_CACHE_LINE_SIZE,
-			      0);
-
-	loopback_db = odp_shm_addr(shm);
-
-	if (loopback_db == NULL) {
-		EXAMPLE_ERR("Error: shared mem alloc failed.\n");
-		exit(EXIT_FAILURE);
-	}
-	memset(loopback_db, 0, sizeof(*loopback_db));
-
-	for (idx = 0; idx < MAX_LOOPBACK; idx++) {
-		loopback_db->intf[idx].inq_def = ODP_QUEUE_INVALID;
-		loopback_db->intf[idx].outq_def = ODP_QUEUE_INVALID;
-	}
-}
-
-void create_loopback_db_entry(int idx,
-			      odp_queue_t inq_def,
-			      odp_queue_t outq_def,
-			      odp_pool_t pkt_pool)
-{
-	loopback_db_entry_t *entry = &loopback_db->intf[idx];
-
-	/* Save queues */
-	entry->inq_def = inq_def;
-	entry->outq_def = outq_def;
-	entry->pkt_pool = pkt_pool;
-
-	/* Create dummy MAC address */
-	memset(entry->mac, (0xF0 | idx), sizeof(entry->mac));
-}
diff --git a/example/ipsec/odp_ipsec_loop_db.h b/example/ipsec/odp_ipsec_loop_db.h
deleted file mode 100644
index 1f9ade6d3..000000000
--- a/example/ipsec/odp_ipsec_loop_db.h
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright (c) 2014, Linaro Limited
- * All rights reserved.
- *
- * SPDX-License-Identifier:     BSD-3-Clause
- */
-
-#ifndef ODP_IPSEC_LOOP_DB_H_
-#define ODP_IPSEC_LOOP_DB_H_
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <odp_api.h>
-#include <odp_ipsec_misc.h>
-
-/**
- * Loopback database entry structure
- */
-typedef struct loopback_db_entry_s {
-	odp_queue_t inq_def;
-	odp_queue_t outq_def;
-	odp_pool_t  pkt_pool;
-	uint8_t     mac[ODPH_ETHADDR_LEN];
-} loopback_db_entry_t;
-
-typedef struct loopback_db_s {
-	loopback_db_entry_t  intf[MAX_LOOPBACK];
-} loopback_db_t;
-
-extern loopback_db_t *loopback_db;
-
-/** Initialize loopback database global control structure */
-void init_loopback_db(void);
-
-/**
- * Create loopback DB entry for an interface
- *
- * Loopback interfaces are specified from command line with
- * an index 0-9.
- *
- * @param idx      Index of interface in database
- * @param inq_def  Input queue
- * @param outq_def Output queue
- * @param pkt_pool Pool to create packets from
- */
-void create_loopback_db_entry(int idx,
-			      odp_queue_t inq_def,
-			      odp_queue_t outq_def,
-			      odp_pool_t pkt_pool);
-
-/**
- * Parse loop interface index
- *
- * @param b     Pointer to buffer to parse
- *
- * @return interface index (0 to (MAX_LOOPBACK - 1)) else -1
- */
-static inline
-int loop_if_index(char *b)
-{
-	int ret;
-	int idx;
-
-	/* Derive loopback interface index */
-	ret = sscanf(b, "loop%d", &idx);
-	if ((1 != ret) || (idx < 0) || (idx >= MAX_LOOPBACK))
-		return -1;
-	return idx;
-}
-
-/**
- * Query loopback DB entry MAC address
- *
- * @param idx     Loopback DB index of the interface
- *
- * @return MAC address pointer
- */
-static inline
-uint8_t *query_loopback_db_mac(int idx)
-{
-	return loopback_db->intf[idx].mac;
-}
-
-/**
- * Query loopback DB entry input queue
- *
- * @param idx     Loopback DB index of the interface
- *
- * @return ODP queue
- */
-static inline
-odp_queue_t query_loopback_db_inq(int idx)
-{
-	return loopback_db->intf[idx].inq_def;
-}
-
-/**
- * Query loopback DB entry output queue
- *
- * @param idx     Loopback DB index of the interface
- *
- * @return ODP queue
- */
-static inline
-odp_queue_t query_loopback_db_outq(int idx)
-{
-	return loopback_db->intf[idx].outq_def;
-}
-
-/**
- * Query loopback DB entry packet pool
- *
- * @param idx     Loopback DB index of the interface
- *
- * @return ODP buffer pool
- */
-static inline
-odp_pool_t query_loopback_db_pkt_pool(int idx)
-{
-	return loopback_db->intf[idx].pkt_pool;
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/example/ipsec/odp_ipsec_stream.c b/example/ipsec/odp_ipsec_stream.c
index bc5d572f0..c287282e8 100644
--- a/example/ipsec/odp_ipsec_stream.c
+++ b/example/ipsec/odp_ipsec_stream.c
@@ -24,7 +24,6 @@
 #include <odp/helper/odph_api.h>
 
 #include <odp_ipsec_stream.h>
-#include <odp_ipsec_loop_db.h>
 
 #define STREAM_MAGIC 0xBABE01234567CAFE
 
@@ -94,15 +93,10 @@ int create_stream_db_entry(char *input)
 			parse_ipv4_string(token, &entry->dst_ip, NULL);
 			break;
 		case 2:
-			entry->input.loop = loop_if_index(token);
-			if (entry->input.loop < 0) {
-				EXAMPLE_ERR("Error: stream must have input"
-					    " loop\n");
-				exit(EXIT_FAILURE);
-			}
+			entry->input.intf = strdup(token);
 			break;
 		case 3:
-			entry->output.loop = loop_if_index(token);
+			entry->output.intf = strdup(token);
 			break;
 		case 4:
 			entry->count = atoi(token);
@@ -157,11 +151,15 @@ void resolve_stream_db(void)
 						  NULL);
 		stream->input.entry = entry;
 
+		stream->input.pktio = odp_pktio_lookup(stream->input.intf);
+
 		/* Lookup output entry */
 		entry = find_ipsec_cache_entry_out(stream->src_ip,
 						   stream->dst_ip,
 						   0);
 		stream->output.entry = entry;
+
+		stream->output.pktio = odp_pktio_lookup(stream->output.intf);
 	}
 }
 
@@ -556,8 +554,25 @@ int create_stream_db_inputs(void)
 	/* For each stream create corresponding input packets */
 	for (stream = stream_db->list; NULL != stream; stream = stream->next) {
 		int count;
-		uint8_t *dmac = query_loopback_db_mac(stream->input.loop);
-		odp_queue_t queue = query_loopback_db_inq(stream->input.loop);
+		int ret;
+		uint8_t dmac[ODPH_ETHADDR_LEN];
+		odp_pktout_queue_t queue;
+
+		ret = odp_pktio_mac_addr(stream->input.pktio,
+					 dmac, sizeof(dmac));
+		if (ret <= 0) {
+			EXAMPLE_ERR("Error: failed during MAC address get "
+				    "for %s\n",
+					stream->input.intf);
+			continue;
+		}
+
+		ret = odp_pktout_queue(stream->input.pktio, &queue, 1);
+		if (ret < 1) {
+			EXAMPLE_ERR("Error: failed to get outqueue for %s\n",
+				    stream->input.intf);
+			continue;
+		}
 
 		for (count = stream->count; count > 0; count--) {
 			odp_packet_t pkt;
@@ -568,7 +583,7 @@ int create_stream_db_inputs(void)
 				break;
 			}
 			stream->created++;
-			if (odp_queue_enq(queue, odp_packet_to_event(pkt))) {
+			if (odp_pktout_send(queue, &pkt, 1) != 1) {
 				odp_packet_free(pkt);
 				printf("Queue enqueue failed\n");
 				break;
@@ -594,13 +609,16 @@ odp_bool_t verify_stream_db_outputs(void)
 	for (stream = stream_db->list; NULL != stream; stream = stream->next) {
 		int idx;
 		int count;
+		int ret;
 		odp_queue_t queue;
 		odp_event_t ev_tbl[LOOP_DEQ_COUNT];
 
-		queue = query_loopback_db_outq(stream->output.loop);
-
-		if (ODP_QUEUE_INVALID == queue)
+		ret = odp_pktin_event_queue(stream->output.pktio, &queue, 1);
+		if (ret < 1) {
+			EXAMPLE_ERR("Error: failed to get inqueue for %s\n",
+				    stream->output.intf);
 			continue;
+		}
 
 		for (;;) {
 			if (env) {
diff --git a/example/ipsec/odp_ipsec_stream.h b/example/ipsec/odp_ipsec_stream.h
index 6f6f7dff4..4d047360a 100644
--- a/example/ipsec/odp_ipsec_stream.h
+++ b/example/ipsec/odp_ipsec_stream.h
@@ -28,13 +28,15 @@ typedef struct stream_db_entry_s {
 	uint32_t         created;       /**< Number successfully created */
 	uint32_t         verified;      /**< Number successfully verified */
 	struct {
-		int      loop;          /**< Input loop interface index */
+		const char *intf;	/**< Input interface name */
+		odp_pktio_t pktio;	/**< Input PktI/O interface */
 		uint32_t ah_seq;        /**< AH sequence number if present */
 		uint32_t esp_seq;       /**< ESP sequence number if present */
 		ipsec_cache_entry_t *entry;  /**< IPsec to apply on input */
 	} input;
 	struct {
-		int      loop;          /**< Output loop interface index */
+		const char *intf;	/**< Output interface name */
+		odp_pktio_t pktio;	/**< Output PktI/O interface */
 		ipsec_cache_entry_t *entry;  /**t IPsec to verify on output */
 	} output;
 } stream_db_entry_t;
