diff --git a/example/l3fwd/odp_l3fwd.c b/example/l3fwd/odp_l3fwd.c
index 9e29e1b..5539711 100644
--- a/example/l3fwd/odp_l3fwd.c
+++ b/example/l3fwd/odp_l3fwd.c
@@ -62,6 +62,7 @@ struct thread_arg_s {
 	uint64_t rx_drops;
 	uint64_t tx_drops;
 	struct {
+		int if_idx;	/* interface index */
 		int nb_rxq;	/* number of rxq this thread will access */
 		int rxq[MAX_NB_QUEUE];	/* rxq[i] is index in pktio.ifin[] */
 		int txq_idx;	/* index in pktio.ifout[] */
@@ -175,7 +176,7 @@ static inline void ipv4_dec_ttl_csum_update(odph_ipv4hdr_t *ip)
 		ip->chksum += odp_cpu_to_be_16(1 << 8);
 }
 
-static int l3fwd_pkt_hash(odp_packet_t pkt, int sif)
+static inline int l3fwd_pkt_hash(odp_packet_t pkt, int sif)
 {
 	fwd_db_entry_t *entry;
 	ipv4_tuple5_t key;
@@ -217,7 +218,7 @@ static int l3fwd_pkt_hash(odp_packet_t pkt, int sif)
 	return dif;
 }
 
-static int l3fwd_pkt_lpm(odp_packet_t pkt, int sif)
+static inline int l3fwd_pkt_lpm(odp_packet_t pkt, int sif)
 {
 	odph_ipv4hdr_t *ip;
 	odph_ethhdr_t *eth;
@@ -275,75 +276,83 @@ static inline int drop_err_pkts(odp_packet_t pkt_tbl[], unsigned num)
 	return dropped;
 }
 
-static void l3fwd_one_queue(uint32_t sif, int rxq_idx, void *thr_arg)
+static int run_worker(void *arg)
 {
-	odp_packet_t *tbl;
-	odp_pktout_queue_t outq;
+	int if_idx;
+	struct thread_arg_s *thr_arg = arg;
 	odp_pktin_queue_t inq;
+	int input_ifs[thr_arg->nb_pktio];
+	odp_pktin_queue_t input_queues[thr_arg->nb_pktio];
+	odp_pktout_queue_t output_queues[global.cmd_args.if_count];
 	odp_packet_t pkt_tbl[MAX_PKT_BURST];
-	struct thread_arg_s *arg;
+	odp_packet_t *tbl;
 	int pkts, drop, sent;
 	int dst_port, dif;
-	int i;
+	int i, j;
+	int pktio = 0;
+	int num_pktio = 0;
 
-	arg = thr_arg;
-	inq = global.l3fwd_pktios[sif].ifin[rxq_idx];
-	pkts = odp_pktin_recv(inq, pkt_tbl, MAX_PKT_BURST);
-	if (pkts <= 0)
-		return;
+	/* Copy all required handles to local memory */
+	for (i = 0; i < global.cmd_args.if_count; i++) {
+		int txq_idx = thr_arg->pktio[i].txq_idx;
 
-	arg->packets += pkts;
-	drop = drop_err_pkts(pkt_tbl, pkts);
-	pkts -= drop;
-	arg->rx_drops += drop;
+		output_queues[i] =  global.l3fwd_pktios[i].ifout[txq_idx];
 
-	dif = global.fwd_func(pkt_tbl[0], sif);
-	tbl = &pkt_tbl[0];
-	while (pkts) {
-		int txq_idx;
+		if_idx = thr_arg->pktio[i].if_idx;
+		for (j = 0; j < thr_arg->pktio[i].nb_rxq; j++) {
+			int rxq_idx = thr_arg->pktio[i].rxq[j];
 
-		dst_port = dif;
-		for (i = 1; i < pkts; i++) {
-			dif = global.fwd_func(tbl[i], sif);
-			if (dif != dst_port)
-				break;
+			inq = global.l3fwd_pktios[if_idx].ifin[rxq_idx];
+			input_ifs[num_pktio] = if_idx;
+			input_queues[num_pktio] = inq;
+			num_pktio++;
 		}
-
-		txq_idx = arg->pktio[dst_port].txq_idx;
-		outq = global.l3fwd_pktios[dst_port].ifout[txq_idx];
-		sent = odp_pktout_send(outq, tbl, i);
-		if (odp_unlikely(sent < i)) {
-			sent = sent < 0 ? 0 : sent;
-			odp_packet_free_multi(&tbl[sent], i - sent);
-			arg->tx_drops += i - sent;
-		}
-
-		if (i < pkts)
-			tbl += i;
-
-		pkts -= i;
 	}
-}
 
-static int run_worker(void *arg)
-{
-	int if_idx, rxq, nb_rxq;
-	struct thread_arg_s *thr_arg = arg;
+	num_pktio = thr_arg->nb_pktio;
+	if_idx = input_ifs[pktio];
+	inq = input_queues[pktio];
 
 	odp_barrier_wait(&barrier);
 
 	while (!exit_threads) {
-		for (if_idx = 0; if_idx < thr_arg->nb_pktio; if_idx++) {
-			nb_rxq = thr_arg->pktio[if_idx].nb_rxq;
-			if (!nb_rxq || thr_arg->thr_idx == INVALID_ID)
-				continue;
+		if (num_pktio > 1) {
+			if_idx = input_ifs[pktio];
+			inq = input_queues[pktio];
+			pktio++;
+			if (pktio == num_pktio)
+				pktio = 0;
+		}
 
-			for (rxq = 0; rxq < nb_rxq; rxq++) {
-				int rxq_idx;
+		pkts = odp_pktin_recv(inq, pkt_tbl, MAX_PKT_BURST);
+		if (pkts <= 0)
+			continue;
 
-				rxq_idx = thr_arg->pktio[if_idx].rxq[rxq];
-				l3fwd_one_queue(if_idx, rxq_idx, arg);
+		thr_arg->packets += pkts;
+		drop = drop_err_pkts(pkt_tbl, pkts);
+		pkts -= drop;
+		thr_arg->rx_drops += drop;
+
+		dif = global.fwd_func(pkt_tbl[0], if_idx);
+		tbl = &pkt_tbl[0];
+		while (pkts) {
+			dst_port = dif;
+			for (i = 1; i < pkts; i++) {
+				dif = global.fwd_func(tbl[i], if_idx);
+				if (dif != dst_port)
+					break;
+			}
+			sent = odp_pktout_send(output_queues[dst_port], tbl, i);
+			if (odp_unlikely(sent < i)) {
+				sent = sent < 0 ? 0 : sent;
+				odp_packet_free_multi(&tbl[sent], i - sent);
+				thr_arg->tx_drops += i - sent;
 			}
+
+			if (i < pkts)
+				tbl += i;
+
+			pkts -= i;
 		}
 	}
 
@@ -675,7 +684,7 @@ static void print_info(char *progname, app_args_t *args)
  */
 static void setup_worker_qconf(app_args_t *args)
 {
-	int nb_worker, if_count;
+	int nb_worker, if_count, pktio;
 	int i, j, rxq_idx;
 	struct thread_arg_s *arg;
 	struct l3fwd_pktio_s *port;
@@ -692,10 +701,11 @@ static void setup_worker_qconf(app_args_t *args)
 				arg->thr_idx = i;
 				j = i % if_count;
 				port = &global.l3fwd_pktios[j];
-				rxq_idx = arg->pktio[j].nb_rxq;
-				arg->pktio[j].rxq[rxq_idx] =
+				arg->pktio[0].rxq[0] =
 					port->rxq_idx % port->nb_rxq;
-				arg->pktio[j].nb_rxq++;
+				arg->pktio[0].nb_rxq = 1;
+				arg->pktio[0].if_idx = j;
+				arg->nb_pktio = 1;
 				port->rxq_idx++;
 			}
 		} else {
@@ -705,9 +715,12 @@ static void setup_worker_qconf(app_args_t *args)
 				arg->thr_idx = j;
 				port = &global.l3fwd_pktios[i];
 				rxq_idx = arg->pktio[i].nb_rxq;
-				arg->pktio[i].rxq[rxq_idx] =
+				pktio = arg->nb_pktio;
+				arg->pktio[pktio].rxq[rxq_idx] =
 					port->rxq_idx % port->nb_rxq;
-				arg->pktio[i].nb_rxq++;
+				arg->pktio[pktio].nb_rxq++;
+				arg->pktio[pktio].if_idx = i;
+				arg->nb_pktio++;
 				port->rxq_idx++;
 			}
 		}
@@ -747,12 +760,21 @@ static void setup_worker_qconf(app_args_t *args)
 
 		/* put the queue into worker_args */
 		arg = &global.worker_args[q->core_idx];
-		rxq_idx =  arg->pktio[q->if_idx].nb_rxq;
-		arg->pktio[q->if_idx].rxq[rxq_idx] = q->rxq_idx;
-		arg->pktio[q->if_idx].nb_rxq++;
+
+		/* Check if interface already has queues configured */
+		for (j = 0; j < args->if_count; j++) {
+			if (arg->pktio[j].if_idx == q->if_idx)
+				break;
+		}
+		if (j == args->if_count)
+			j = arg->nb_pktio++;
+
+		rxq_idx =  arg->pktio[j].nb_rxq;
+		arg->pktio[j].rxq[rxq_idx] = q->rxq_idx;
+		arg->pktio[j].nb_rxq++;
+		arg->pktio[j].if_idx = q->if_idx;
 		arg->thr_idx = q->core_idx;
 	}
-
 	/* distribute tx queues among threads */
 	for (i = 0; i < args->worker_count; i++) {
 		arg = &global.worker_args[i];
@@ -821,7 +843,7 @@ static void setup_worker_qconf(app_args_t *args)
 
 static void print_qconf_table(app_args_t *args)
 {
-	int i, j, k, qid;
+	int i, j, k, qid, if_idx;
 	char buf[32];
 	struct thread_arg_s *thr_arg;
 
@@ -836,7 +858,9 @@ static void print_qconf_table(app_args_t *args)
 			if (!thr_arg->pktio[j].nb_rxq)
 				continue;
 
-			snprintf(buf, 32, "%s/%d", args->if_names[j], j);
+			if_idx = thr_arg->pktio[j].if_idx;
+			snprintf(buf, 32, "%s/%d", args->if_names[if_idx],
+				 if_idx);
 			for (k = 0; k < MAX_NB_QUEUE; k++) {
 				qid = thr_arg->pktio[j].rxq[k];
 				if (qid != INVALID_ID)
@@ -948,6 +972,7 @@ int main(int argc, char **argv)
 		for (j = 0; j < MAX_NB_PKTIO; j++) {
 			thr_arg->thr_idx = INVALID_ID;
 			thr_arg->pktio[j].txq_idx = INVALID_ID;
+			thr_arg->pktio[j].if_idx = INVALID_ID;
 			memset(thr_arg->pktio[j].rxq, INVALID_ID,
 			       sizeof(thr_arg->pktio[j].rxq));
 		}
@@ -1069,7 +1094,6 @@ int main(int argc, char **argv)
 		odp_cpumask_t thr_mask;
 
 		arg = &global.worker_args[i];
-		arg->nb_pktio = args->if_count;
 		odp_cpumask_zero(&thr_mask);
 		odp_cpumask_set(&thr_mask, cpu);
 		thr_params.arg = arg;
