diff --git a/platform/linux-generic/include/odp_packet_io_internal.h b/platform/linux-generic/include/odp_packet_io_internal.h
index 8ebff1c..139b1bd 100644
--- a/platform/linux-generic/include/odp_packet_io_internal.h
+++ b/platform/linux-generic/include/odp_packet_io_internal.h
@@ -188,10 +188,10 @@ typedef struct pktio_if_ops {
 	int (*stats_reset)(pktio_entry_t *pktio_entry);
 	uint64_t (*pktin_ts_res)(pktio_entry_t *pktio_entry);
 	odp_time_t (*pktin_ts_from_ns)(pktio_entry_t *pktio_entry, uint64_t ns);
-	int (*recv)(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[],
-		    unsigned len);
-	int (*send)(pktio_entry_t *pktio_entry, const odp_packet_t pkt_table[],
-		    unsigned len);
+	int (*recv)(pktio_entry_t *entry, int index, odp_packet_t packets[],
+		    int num);
+	int (*send)(pktio_entry_t *entry, int index,
+		    const odp_packet_t packets[], int num);
 	uint32_t (*mtu_get)(pktio_entry_t *pktio_entry);
 	int (*promisc_mode_set)(pktio_entry_t *pktio_entry,  int enable);
 	int (*promisc_mode_get)(pktio_entry_t *pktio_entry);
@@ -205,10 +205,6 @@ typedef struct pktio_if_ops {
 				   const odp_pktin_queue_param_t *param);
 	int (*output_queues_config)(pktio_entry_t *pktio_entry,
 				    const odp_pktout_queue_param_t *p);
-	int (*recv_queue)(pktio_entry_t *entry, int index,
-			  odp_packet_t packets[], int num);
-	int (*send_queue)(pktio_entry_t *entry, int index,
-			  const odp_packet_t packets[], int num);
 } pktio_if_ops_t;
 
 int _odp_packet_cls_enq(pktio_entry_t *pktio_entry, const uint8_t *base,
diff --git a/platform/linux-generic/odp_packet_io.c b/platform/linux-generic/odp_packet_io.c
index 572db9b..652709e 100644
--- a/platform/linux-generic/odp_packet_io.c
+++ b/platform/linux-generic/odp_packet_io.c
@@ -531,54 +531,6 @@ odp_pktio_t odp_pktio_lookup(const char *name)
 	return hdl;
 }
 
-static int _odp_pktio_recv(pktio_entry_t *pktio_entry, odp_packet_t pkt_table[],
-			   int len)
-{
-	int pkts;
-	int i;
-
-	if (pktio_entry == NULL)
-		return -1;
-
-	odp_ticketlock_lock(&pktio_entry->s.rxl);
-	if (pktio_entry->s.param.in_mode == ODP_PKTIN_MODE_DISABLED) {
-		odp_ticketlock_unlock(&pktio_entry->s.rxl);
-		__odp_errno = EPERM;
-		return -1;
-	}
-	pkts = pktio_entry->s.ops->recv(pktio_entry, pkt_table, len);
-	odp_ticketlock_unlock(&pktio_entry->s.rxl);
-
-	if (pkts < 0)
-		return pkts;
-
-	for (i = 0; i < pkts; ++i)
-		odp_packet_hdr(pkt_table[i])->input = pktio_entry->s.handle;
-
-	return pkts;
-}
-
-static int _odp_pktio_send(pktio_entry_t *pktio_entry,
-			   const odp_packet_t pkt_table[], int len)
-{
-	int pkts;
-
-	if (pktio_entry == NULL)
-		return -1;
-
-	odp_ticketlock_lock(&pktio_entry->s.txl);
-	if (pktio_entry->s.state != STATE_STARTED ||
-	    pktio_entry->s.param.out_mode == ODP_PKTOUT_MODE_DISABLED) {
-			odp_ticketlock_unlock(&pktio_entry->s.txl);
-		__odp_errno = EPERM;
-		return -1;
-	}
-	pkts = pktio_entry->s.ops->send(pktio_entry, pkt_table, len);
-	odp_ticketlock_unlock(&pktio_entry->s.txl);
-
-	return pkts;
-}
-
 int pktout_enqueue(queue_entry_t *qentry, odp_buffer_hdr_t *buf_hdr)
 {
 	odp_packet_t pkt = _odp_packet_from_buffer(buf_hdr->handle.handle);
@@ -1532,11 +1484,7 @@ int odp_pktin_recv(odp_pktin_queue_t queue, odp_packet_t packets[], int num)
 		return -1;
 	}
 
-	if (entry->s.ops->recv_queue)
-		return entry->s.ops->recv_queue(entry, queue.index,
-						packets, num);
-
-	return single_recv_queue(entry, queue.index, packets, num);
+	return entry->s.ops->recv(entry, queue.index, packets, num);
 }
 
 int odp_pktin_recv_tmo(odp_pktin_queue_t queue, odp_packet_t packets[], int num,
@@ -1658,11 +1606,7 @@ int odp_pktout_send(odp_pktout_queue_t queue, const odp_packet_t packets[],
 		return -1;
 	}
 
-	if (entry->s.ops->send_queue)
-		return entry->s.ops->send_queue(entry, queue.index,
-						packets, num);
-
-	return single_send_queue(entry, queue.index, packets, num);
+	return entry->s.ops->send(entry, queue.index, packets, num);
 }
 
 int single_capability(odp_pktio_capability_t *capa)
@@ -1674,17 +1618,3 @@ int single_capability(odp_pktio_capability_t *capa)
 
 	return 0;
 }
-
-int single_recv_queue(pktio_entry_t *entry, int index, odp_packet_t packets[],
-		      int num)
-{
-	(void)index;
-	return _odp_pktio_recv(entry, packets, num);
-}
-
-int single_send_queue(pktio_entry_t *entry, int index,
-		      const odp_packet_t packets[], int num)
-{
-	(void)index;
-	return _odp_pktio_send(entry, packets, num);
-}
diff --git a/platform/linux-generic/pktio/dpdk.c b/platform/linux-generic/pktio/dpdk.c
index 831dc26..25dde7b 100644
--- a/platform/linux-generic/pktio/dpdk.c
+++ b/platform/linux-generic/pktio/dpdk.c
@@ -807,10 +807,8 @@ static inline int pkt_to_mbuf(pktio_entry_t *pktio_entry,
 	return i;
 }
 
-static int dpdk_recv_queue(pktio_entry_t *pktio_entry,
-			   int index,
-			   odp_packet_t pkt_table[],
-			   int num)
+static int dpdk_recv(pktio_entry_t *pktio_entry, int index,
+		     odp_packet_t pkt_table[], int num)
 {
 	pkt_dpdk_t *pkt_dpdk = &pktio_entry->s.pkt_dpdk;
 	pkt_cache_t *rx_cache = &pkt_dpdk->rx_cache[index];
@@ -879,10 +877,8 @@ static int dpdk_recv_queue(pktio_entry_t *pktio_entry,
 	return nb_rx;
 }
 
-static int dpdk_send_queue(pktio_entry_t *pktio_entry,
-			   int index,
-			   const odp_packet_t pkt_table[],
-			   int num)
+static int dpdk_send(pktio_entry_t *pktio_entry, int index,
+		     const odp_packet_t pkt_table[], int num)
 {
 	struct rte_mbuf *tx_mbufs[num];
 	pkt_dpdk_t *pkt_dpdk = &pktio_entry->s.pkt_dpdk;
@@ -1010,8 +1006,8 @@ const pktio_if_ops_t dpdk_pktio_ops = {
 	.stop = dpdk_stop,
 	.stats = dpdk_stats,
 	.stats_reset = dpdk_stats_reset,
-	.recv_queue = dpdk_recv_queue,
-	.send_queue = dpdk_send_queue,
+	.recv = dpdk_recv,
+	.send = dpdk_send,
 	.link_status = dpdk_link_status,
 	.mtu_get = dpdk_mtu_get,
 	.promisc_mode_set = dpdk_promisc_mode_set,
diff --git a/platform/linux-generic/pktio/ipc.c b/platform/linux-generic/pktio/ipc.c
index 8508824..93b0d01 100644
--- a/platform/linux-generic/pktio/ipc.c
+++ b/platform/linux-generic/pktio/ipc.c
@@ -486,8 +486,8 @@ static void _ipc_free_ring_packets(_ring_t *r)
 	}
 }
 
-static int ipc_pktio_recv(pktio_entry_t *pktio_entry,
-			  odp_packet_t pkt_table[], unsigned len)
+static int ipc_pktio_recv_lockless(pktio_entry_t *pktio_entry,
+				   odp_packet_t pkt_table[], int len)
 {
 	int pkts = 0;
 	int i;
@@ -580,6 +580,7 @@ static int ipc_pktio_recv(pktio_entry_t *pktio_entry,
 		odp_packet_hdr(pkt)->frame_len = phdr.frame_len;
 		odp_packet_hdr(pkt)->headroom = phdr.headroom;
 		odp_packet_hdr(pkt)->tailroom = phdr.tailroom;
+		odp_packet_hdr(pkt)->input = pktio_entry->s.handle;
 		pkt_table[i] = pkt;
 	}
 
@@ -592,13 +593,27 @@ static int ipc_pktio_recv(pktio_entry_t *pktio_entry,
 	return pkts;
 }
 
-static int ipc_pktio_send(pktio_entry_t *pktio_entry,
-			  const odp_packet_t pkt_table[], unsigned len)
+static int ipc_pktio_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  odp_packet_t pkt_table[], int len)
+{
+	int ret;
+
+	odp_ticketlock_lock(&pktio_entry->s.rxl);
+
+	ret = ipc_pktio_recv_lockless(pktio_entry, pkt_table, len);
+
+	odp_ticketlock_unlock(&pktio_entry->s.rxl);
+
+	return ret;
+}
+
+static int ipc_pktio_send_lockless(pktio_entry_t *pktio_entry,
+				   const odp_packet_t pkt_table[], int len)
 {
 	_ring_t *r;
 	void **rbuf_p;
 	int ret;
-	unsigned i;
+	int i;
 	uint32_t ready = odp_atomic_load_u32(&pktio_entry->s.ipc.ready);
 	odp_packet_t pkt_table_mapped[len]; /**< Ready to send packet has to be
 					      * in memory mapped pool. */
@@ -666,6 +681,20 @@ static int ipc_pktio_send(pktio_entry_t *pktio_entry,
 	return ret;
 }
 
+static int ipc_pktio_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  const odp_packet_t pkt_table[], int len)
+{
+	int ret;
+
+	odp_ticketlock_lock(&pktio_entry->s.txl);
+
+	ret = ipc_pktio_send_lockless(pktio_entry, pkt_table, len);
+
+	odp_ticketlock_unlock(&pktio_entry->s.txl);
+
+	return ret;
+}
+
 static uint32_t ipc_mtu_get(pktio_entry_t *pktio_entry ODP_UNUSED)
 {
 	/* mtu not limited, pool settings are used. */
diff --git a/platform/linux-generic/pktio/loop.c b/platform/linux-generic/pktio/loop.c
index cbb5ea9..cdf5326 100644
--- a/platform/linux-generic/pktio/loop.c
+++ b/platform/linux-generic/pktio/loop.c
@@ -48,8 +48,8 @@ static int loopback_close(pktio_entry_t *pktio_entry)
 	return odp_queue_destroy(pktio_entry->s.pkt_loop.loopq);
 }
 
-static int loopback_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
-			 unsigned len)
+static int loopback_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			 odp_packet_t pkts[], int len)
 {
 	int nbr, i;
 	odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX];
@@ -62,6 +62,8 @@ static int loopback_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 	if (odp_unlikely(len > QUEUE_MULTI_MAX))
 		len = QUEUE_MULTI_MAX;
 
+	odp_ticketlock_lock(&pktio_entry->s.rxl);
+
 	qentry = queue_to_qentry(pktio_entry->s.pkt_loop.loopq);
 	nbr = queue_deq_multi(qentry, hdr_tbl, len);
 
@@ -85,6 +87,7 @@ static int loopback_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 			switch (ret) {
 			case 0:
 				packet_set_ts(pkt_hdr, ts);
+				pkt_hdr->input = pktio_entry->s.handle;
 				pktio_entry->s.stats.in_octets +=
 					odp_packet_len(pkt);
 				break;
@@ -101,6 +104,9 @@ static int loopback_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 		pktio_entry->s.stats.in_errors += failed;
 		pktio_entry->s.stats.in_discards += discarded;
 		pktio_entry->s.stats.in_ucast_pkts += nbr - failed - discarded;
+
+		odp_ticketlock_unlock(&pktio_entry->s.rxl);
+
 		return -failed;
 	} else {
 		for (i = 0; i < nbr; ++i) {
@@ -110,20 +116,24 @@ static int loopback_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 			packet_parse_reset(pkt_hdr);
 			packet_parse_l2(pkt_hdr);
 			packet_set_ts(pkt_hdr, ts);
+			pkt_hdr->input = pktio_entry->s.handle;
 			pktio_entry->s.stats.in_octets +=
 				odp_packet_len(pkts[i]);
 		}
 		pktio_entry->s.stats.in_ucast_pkts += nbr;
+
+		odp_ticketlock_unlock(&pktio_entry->s.rxl);
+
 		return nbr;
 	}
 }
 
-static int loopback_send(pktio_entry_t *pktio_entry,
-			 const odp_packet_t pkt_tbl[], unsigned len)
+static int loopback_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			 const odp_packet_t pkt_tbl[], int len)
 {
 	odp_buffer_hdr_t *hdr_tbl[QUEUE_MULTI_MAX];
 	queue_entry_t *qentry;
-	unsigned i;
+	int i;
 	int ret;
 	uint32_t bytes = 0;
 
@@ -135,6 +145,8 @@ static int loopback_send(pktio_entry_t *pktio_entry,
 		bytes += odp_packet_len(pkt_tbl[i]);
 	}
 
+	odp_ticketlock_lock(&pktio_entry->s.txl);
+
 	qentry = queue_to_qentry(pktio_entry->s.pkt_loop.loopq);
 	ret = queue_enq_multi(qentry, hdr_tbl, len, 0);
 	if (ret > 0) {
@@ -142,6 +154,8 @@ static int loopback_send(pktio_entry_t *pktio_entry,
 		pktio_entry->s.stats.out_octets += bytes;
 	}
 
+	odp_ticketlock_unlock(&pktio_entry->s.txl);
+
 	return ret;
 }
 
@@ -229,6 +243,4 @@ const pktio_if_ops_t loopback_pktio_ops = {
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
-	.recv_queue = NULL,
-	.send_queue = NULL
 };
diff --git a/platform/linux-generic/pktio/netmap.c b/platform/linux-generic/pktio/netmap.c
index 820629c..59cb276 100644
--- a/platform/linux-generic/pktio/netmap.c
+++ b/platform/linux-generic/pktio/netmap.c
@@ -690,8 +690,8 @@ static inline int netmap_recv_desc(pktio_entry_t *pktio_entry,
 	return num_rx;
 }
 
-static int netmap_recv_queue(pktio_entry_t *pktio_entry, int index,
-			     odp_packet_t pkt_table[], int num)
+static int netmap_recv(pktio_entry_t *pktio_entry, int index,
+		       odp_packet_t pkt_table[], int num)
 {
 	struct nm_desc *desc;
 	pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm;
@@ -744,8 +744,8 @@ static int netmap_recv_queue(pktio_entry_t *pktio_entry, int index,
 	return num_rx;
 }
 
-static int netmap_send_queue(pktio_entry_t *pktio_entry, int index,
-			     const odp_packet_t pkt_table[], int num)
+static int netmap_send(pktio_entry_t *pktio_entry, int index,
+		       const odp_packet_t pkt_table[], int num)
 {
 	pkt_netmap_t *pkt_nm = &pktio_entry->s.pkt_nm;
 	struct pollfd polld;
@@ -913,8 +913,8 @@ const pktio_if_ops_t netmap_pktio_ops = {
 	.config = NULL,
 	.input_queues_config = netmap_input_queues_config,
 	.output_queues_config = netmap_output_queues_config,
-	.recv_queue = netmap_recv_queue,
-	.send_queue = netmap_send_queue
+	.recv = netmap_recv,
+	.send = netmap_send
 };
 
 #endif /* ODP_NETMAP */
diff --git a/platform/linux-generic/pktio/pcap.c b/platform/linux-generic/pktio/pcap.c
index aeb20ed..b719849 100644
--- a/platform/linux-generic/pktio/pcap.c
+++ b/platform/linux-generic/pktio/pcap.c
@@ -201,10 +201,10 @@ static int _pcapif_reopen(pkt_pcap_t *pcap)
 	return 0;
 }
 
-static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
-			   unsigned len)
+static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			   odp_packet_t pkts[], int len)
 {
-	unsigned i;
+	int i;
 	struct pcap_pkthdr *hdr;
 	const u_char *data;
 	odp_packet_t pkt;
@@ -214,12 +214,12 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 	odp_time_t ts_val;
 	odp_time_t *ts = NULL;
 
-	if (pktio_entry->s.state != STATE_STARTED)
-		return 0;
+	odp_ticketlock_lock(&pktio_entry->s.rxl);
 
-	if (!pcap->rx)
+	if (pktio_entry->s.state != STATE_STARTED || !pcap->rx) {
+		odp_ticketlock_unlock(&pktio_entry->s.rxl);
 		return 0;
-
+	}
 	if (pktio_entry->s.config.pktin.bit.ts_all ||
 	    pktio_entry->s.config.pktin.bit.ts_ptp)
 		ts = &ts_val;
@@ -266,17 +266,20 @@ static int pcapif_recv_pkt(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 		pktio_entry->s.stats.in_octets += pkt_hdr->frame_len;
 
 		packet_set_ts(pkt_hdr, ts);
+		pkt_hdr->input = pktio_entry->s.handle;
 
 		pkts[i] = pkt;
 		pkt = ODP_PACKET_INVALID;
 
 		i++;
 	}
+	pktio_entry->s.stats.in_ucast_pkts += i;
+
+	odp_ticketlock_unlock(&pktio_entry->s.rxl);
 
 	if (pkt != ODP_PACKET_INVALID)
 		odp_packet_free(pkt);
 
-	pktio_entry->s.stats.in_ucast_pkts += i;
 	return i;
 }
 
@@ -300,21 +303,27 @@ static int _pcapif_dump_pkt(pkt_pcap_t *pcap, odp_packet_t pkt)
 	return 0;
 }
 
-static int pcapif_send_pkt(pktio_entry_t *pktio_entry,
-			   const odp_packet_t pkts[],
-			   unsigned len)
+static int pcapif_send_pkt(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			   const odp_packet_t pkts[], int len)
 {
 	pkt_pcap_t *pcap = &pktio_entry->s.pkt_pcap;
-	unsigned i;
+	int i;
 
-	ODP_ASSERT(pktio_entry->s.state == STATE_STARTED);
+	odp_ticketlock_lock(&pktio_entry->s.txl);
+
+	if (pktio_entry->s.state != STATE_STARTED) {
+		odp_ticketlock_unlock(&pktio_entry->s.txl);
+		return 0;
+	}
 
 	for (i = 0; i < len; ++i) {
 		int pkt_len = odp_packet_len(pkts[i]);
 
 		if (pkt_len > PKTIO_PCAP_MTU) {
-			if (i == 0)
+			if (i == 0) {
+				odp_ticketlock_unlock(&pktio_entry->s.txl);
 				return -1;
+			}
 			break;
 		}
 
@@ -327,6 +336,8 @@ static int pcapif_send_pkt(pktio_entry_t *pktio_entry,
 
 	pktio_entry->s.stats.out_ucast_pkts += i;
 
+	odp_ticketlock_unlock(&pktio_entry->s.txl);
+
 	return i;
 }
 
@@ -440,6 +451,4 @@ const pktio_if_ops_t pcap_pktio_ops = {
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
-	.recv_queue = NULL,
-	.send_queue = NULL
 };
diff --git a/platform/linux-generic/pktio/socket.c b/platform/linux-generic/pktio/socket.c
index c0de59f..c7df7c7 100644
--- a/platform/linux-generic/pktio/socket.c
+++ b/platform/linux-generic/pktio/socket.c
@@ -606,8 +606,8 @@ static uint32_t _rx_pkt_to_iovec(odp_packet_t pkt,
 /*
  * ODP_PACKET_SOCKET_MMSG:
  */
-static int sock_mmsg_recv(pktio_entry_t *pktio_entry,
-			  odp_packet_t pkt_table[], unsigned len)
+static int sock_mmsg_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  odp_packet_t pkt_table[], int len)
 {
 	pkt_sock_t *pkt_sock = &pktio_entry->s.pkt_sock;
 	odp_time_t ts_val;
@@ -624,6 +624,8 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry,
 	if (odp_unlikely(len > ODP_PACKET_SOCKET_MAX_BURST_RX))
 		return -1;
 
+	odp_ticketlock_lock(&pktio_entry->s.rxl);
+
 	if (pktio_entry->s.config.pktin.bit.ts_all ||
 	    pktio_entry->s.config.pktin.bit.ts_ptp)
 		ts = &ts_val;
@@ -707,6 +709,7 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry,
 					     msgvec[i].msg_len);
 			packet_parse_l2(pkt_hdr);
 			packet_set_ts(pkt_hdr, ts);
+			pkt_hdr->input = pktio_entry->s.handle;
 
 			pkt_table[nb_rx] = pkt_table[i];
 			nb_rx++;
@@ -716,6 +719,9 @@ static int sock_mmsg_recv(pktio_entry_t *pktio_entry,
 		for (; i < msgvec_len; i++)
 			odp_packet_free(pkt_table[i]);
 	}
+
+	odp_ticketlock_unlock(&pktio_entry->s.rxl);
+
 	return nb_rx;
 }
 
@@ -741,19 +747,21 @@ static uint32_t _tx_pkt_to_iovec(odp_packet_t pkt,
 /*
  * ODP_PACKET_SOCKET_MMSG:
  */
-static int sock_mmsg_send(pktio_entry_t *pktio_entry,
-			  const odp_packet_t pkt_table[], unsigned len)
+static int sock_mmsg_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  const odp_packet_t pkt_table[], int len)
 {
 	pkt_sock_t *pkt_sock = &pktio_entry->s.pkt_sock;
 	struct mmsghdr msgvec[ODP_PACKET_SOCKET_MAX_BURST_TX];
 	struct iovec iovecs[ODP_PACKET_SOCKET_MAX_BURST_TX][ODP_BUFFER_MAX_SEG];
 	int ret;
 	int sockfd;
-	unsigned n, i;
+	int n, i;
 
 	if (odp_unlikely(len > ODP_PACKET_SOCKET_MAX_BURST_TX))
 		return -1;
 
+	odp_ticketlock_lock(&pktio_entry->s.txl);
+
 	sockfd = pkt_sock->sockfd;
 	memset(msgvec, 0, sizeof(msgvec));
 
@@ -768,7 +776,8 @@ static int sock_mmsg_send(pktio_entry_t *pktio_entry,
 		if (odp_unlikely(ret <= -1)) {
 			if (i == 0 && SOCK_ERR_REPORT(errno)) {
 				__odp_errno = errno;
-			ODP_ERR("sendmmsg(): %s\n", strerror(errno));
+				ODP_ERR("sendmmsg(): %s\n", strerror(errno));
+				odp_ticketlock_unlock(&pktio_entry->s.txl);
 				return -1;
 			}
 			break;
@@ -777,6 +786,8 @@ static int sock_mmsg_send(pktio_entry_t *pktio_entry,
 		i += ret;
 	}
 
+	odp_ticketlock_unlock(&pktio_entry->s.txl);
+
 	for (n = 0; n < i; ++n)
 		odp_packet_free(pkt_table[n]);
 
@@ -891,6 +902,4 @@ const pktio_if_ops_t sock_mmsg_pktio_ops = {
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
-	.recv_queue = NULL,
-	.send_queue = NULL
 };
diff --git a/platform/linux-generic/pktio/socket_mmap.c b/platform/linux-generic/pktio/socket_mmap.c
index c14ec9f..ce05775 100644
--- a/platform/linux-generic/pktio/socket_mmap.c
+++ b/platform/linux-generic/pktio/socket_mmap.c
@@ -219,6 +219,7 @@ static inline unsigned pkt_mmap_v2_rx(pktio_entry_t *pktio_entry,
 
 			packet_parse_l2(hdr);
 			packet_set_ts(hdr, ts);
+			hdr->input = pktio_entry->s.handle;
 
 			nb_rx++;
 		}
@@ -581,22 +582,32 @@ error:
 	return -1;
 }
 
-static int sock_mmap_recv(pktio_entry_t *pktio_entry,
-			  odp_packet_t pkt_table[], unsigned len)
+static int sock_mmap_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  odp_packet_t pkt_table[], int len)
 {
 	pkt_sock_mmap_t *const pkt_sock = &pktio_entry->s.pkt_sock_mmap;
+	int ret;
 
-	return pkt_mmap_v2_rx(pktio_entry, pkt_sock,
-			      pkt_table, len, pkt_sock->if_mac);
+	odp_ticketlock_lock(&pktio_entry->s.rxl);
+	ret = pkt_mmap_v2_rx(pktio_entry, pkt_sock, pkt_table, len,
+			     pkt_sock->if_mac);
+	odp_ticketlock_unlock(&pktio_entry->s.rxl);
+
+	return ret;
 }
 
-static int sock_mmap_send(pktio_entry_t *pktio_entry,
-			  const odp_packet_t pkt_table[], unsigned len)
+static int sock_mmap_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  const odp_packet_t pkt_table[], int len)
 {
+	int ret;
 	pkt_sock_mmap_t *const pkt_sock = &pktio_entry->s.pkt_sock_mmap;
 
-	return pkt_mmap_v2_tx(pkt_sock->tx_ring.sock, &pkt_sock->tx_ring,
-			      pkt_table, len);
+	odp_ticketlock_lock(&pktio_entry->s.txl);
+	ret = pkt_mmap_v2_tx(pkt_sock->tx_ring.sock, &pkt_sock->tx_ring,
+			     pkt_table, len);
+	odp_ticketlock_unlock(&pktio_entry->s.txl);
+
+	return ret;
 }
 
 static uint32_t sock_mmap_mtu_get(pktio_entry_t *pktio_entry)
@@ -695,6 +706,4 @@ const pktio_if_ops_t sock_mmap_pktio_ops = {
 	.config = NULL,
 	.input_queues_config = NULL,
 	.output_queues_config = NULL,
-	.recv_queue = NULL,
-	.send_queue = NULL
 };
diff --git a/platform/linux-generic/pktio/tap.c b/platform/linux-generic/pktio/tap.c
index 4ca11e6..975ad25 100644
--- a/platform/linux-generic/pktio/tap.c
+++ b/platform/linux-generic/pktio/tap.c
@@ -179,13 +179,13 @@ static int tap_pktio_close(pktio_entry_t *pktio_entry)
 	return ret;
 }
 
-static odp_packet_t pack_odp_pkt(odp_pool_t pool, const void *data,
+static odp_packet_t pack_odp_pkt(pktio_entry_t *pktio_entry, const void *data,
 				 unsigned int len, odp_time_t *ts)
 {
 	odp_packet_t pkt;
 	odp_packet_hdr_t *pkt_hdr;
 
-	pkt = packet_alloc(pool, len, 1);
+	pkt = packet_alloc(pktio_entry->s.pkt_tap.pool, len, 1);
 
 	if (pkt == ODP_PACKET_INVALID)
 		return pkt;
@@ -199,20 +199,23 @@ static odp_packet_t pack_odp_pkt(odp_pool_t pool, const void *data,
 	pkt_hdr = odp_packet_hdr(pkt);
 	packet_parse_l2(pkt_hdr);
 	packet_set_ts(pkt_hdr, ts);
+	pkt_hdr->input = pktio_entry->s.handle;
 
 	return pkt;
 }
 
-static int tap_pktio_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
-			  unsigned len)
+static int tap_pktio_recv(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  odp_packet_t pkts[], int len)
 {
 	ssize_t retval;
-	unsigned i;
+	int i;
 	uint8_t buf[BUF_SIZE];
 	pkt_tap_t *tap = &pktio_entry->s.pkt_tap;
 	odp_time_t ts_val;
 	odp_time_t *ts = NULL;
 
+	odp_ticketlock_lock(&pktio_entry->s.rxl);
+
 	if (pktio_entry->s.config.pktin.bit.ts_all ||
 	    pktio_entry->s.config.pktin.bit.ts_ptp)
 		ts = &ts_val;
@@ -230,19 +233,21 @@ static int tap_pktio_recv(pktio_entry_t *pktio_entry, odp_packet_t pkts[],
 			break;
 		}
 
-		pkts[i] = pack_odp_pkt(tap->pool, buf, retval, ts);
+		pkts[i] = pack_odp_pkt(pktio_entry, buf, retval, ts);
 		if (pkts[i] == ODP_PACKET_INVALID)
 			break;
 	}
 
+	odp_ticketlock_unlock(&pktio_entry->s.rxl);
+
 	return i;
 }
 
-static int tap_pktio_send(pktio_entry_t *pktio_entry, const odp_packet_t pkts[],
-			  unsigned len)
+static int tap_pktio_send_lockless(pktio_entry_t *pktio_entry,
+				   const odp_packet_t pkts[], int len)
 {
 	ssize_t retval;
-	unsigned i, n;
+	int i, n;
 	uint32_t pkt_len;
 	uint8_t buf[BUF_SIZE];
 	pkt_tap_t *tap = &pktio_entry->s.pkt_tap;
@@ -290,6 +295,20 @@ static int tap_pktio_send(pktio_entry_t *pktio_entry, const odp_packet_t pkts[],
 	return i;
 }
 
+static int tap_pktio_send(pktio_entry_t *pktio_entry, int index ODP_UNUSED,
+			  const odp_packet_t pkts[], int len)
+{
+	int ret;
+
+	odp_ticketlock_lock(&pktio_entry->s.txl);
+
+	ret = tap_pktio_send_lockless(pktio_entry, pkts, len);
+
+	odp_ticketlock_unlock(&pktio_entry->s.txl);
+
+	return ret;
+}
+
 static uint32_t tap_mtu_get(pktio_entry_t *pktio_entry)
 {
 	uint32_t ret;
