[PATCHv2,6/7] validation: pktio: add support for direct receive

Message ID 1441360547-18999-6-git-send-email-stuart.haslam@linaro.org
State New
Headers show

Commit Message

Stuart Haslam Sept. 4, 2015, 9:55 a.m.
Add a couple of tests for receiving packets directly via
odp_pktio_recv().

Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>
---
 test/validation/pktio/pktio.c | 103 ++++++++++++++++++++++++++----------------
 test/validation/pktio/pktio.h |   2 +
 2 files changed, 66 insertions(+), 39 deletions(-)

Comments

Maxim Uvarov Sept. 7, 2015, 11:14 a.m. | #1
On 09/04/15 12:55, Stuart Haslam wrote:
> Add a couple of tests for receiving packets directly via
> odp_pktio_recv().
>
> Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>
> ---
>   test/validation/pktio/pktio.c | 103 ++++++++++++++++++++++++++----------------
>   test/validation/pktio/pktio.h |   2 +
>   2 files changed, 66 insertions(+), 39 deletions(-)
>
> diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
> index c74fab3..95c3c34 100644
> --- a/test/validation/pktio/pktio.c
> +++ b/test/validation/pktio/pktio.c
> @@ -34,6 +34,7 @@ typedef struct {
>   	odp_pktio_t id;
>   	odp_queue_t outq;
>   	odp_queue_t inq;
> +	odp_pktio_input_mode_t in_mode;
>   } pktio_info_t;
>   
>   /** magic number and sequence at start of UDP payload */
> @@ -250,7 +251,7 @@ static int default_pool_create(void)
>   	return 0;
>   }
>   
> -static odp_pktio_t create_pktio(int iface_idx, odp_queue_type_t q_type)
> +static odp_pktio_t create_pktio(int iface_idx, odp_pktio_input_mode_t mode)
>   {
>   	odp_pktio_t pktio;
>   	odp_pktio_param_t pktio_param;
> @@ -258,10 +259,7 @@ static odp_pktio_t create_pktio(int iface_idx, odp_queue_type_t q_type)
>   
>   	memset(&pktio_param, 0, sizeof(pktio_param));
>   
> -	if (q_type == ODP_QUEUE_TYPE_POLL)
> -		pktio_param.in_mode = ODP_PKTIN_MODE_POLL;
> -	else
> -		pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
> +	pktio_param.in_mode = mode;
>   
>   	pktio = odp_pktio_open(iface, pool[iface_idx], &pktio_param);
>   	if (pktio == ODP_PKTIO_INVALID)
> @@ -348,33 +346,41 @@ static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns)
>   	return ODP_EVENT_INVALID;
>   }
>   
> -static odp_packet_t wait_for_packet(odp_queue_t queue,
> +static odp_packet_t wait_for_packet(pktio_info_t *pktio_rx,
>   				    uint32_t seq, uint64_t ns)
>   {
>   	uint64_t start, now, diff;
>   	odp_event_t ev;
> -	odp_packet_t pkt = ODP_PACKET_INVALID;
> +	odp_packet_t pkt;
>   	uint64_t wait;
>   
>   	start = odp_time_cycles();
>   	wait = odp_schedule_wait_time(ns);
>   
>   	do {
> -		if (queue != ODP_QUEUE_INVALID &&
> -		    odp_queue_type(queue) == ODP_QUEUE_TYPE_POLL)
> -			ev = queue_deq_wait_time(queue, ns);
> -		else
> -			ev  = odp_schedule(NULL, wait);
> -
> -		if (ev != ODP_EVENT_INVALID) {
> -			if (odp_event_type(ev) == ODP_EVENT_PACKET) {
> -				pkt = odp_packet_from_event(ev);
> -				if (pktio_pkt_seq(pkt) == seq)
> -					return pkt;
> +		pkt = ODP_PACKET_INVALID;
> +
setting to invalid.
> +		if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV) {
> +			odp_pktio_recv(pktio_rx->id, &pkt, 1);
issue recv
> +		} else {
> +			if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> +				ev = queue_deq_wait_time(pktio_rx->inq, ns);
> +			else
> +				ev = odp_schedule(NULL, wait);
> +
> +			if (ev != ODP_EVENT_INVALID) {
> +				if (odp_event_type(ev) == ODP_EVENT_PACKET)
> +					pkt = odp_packet_from_event(ev);
> +				else
> +					odp_event_free(ev);
>   			}
> +		}
>   
> -			/* not interested in this event */
> -			odp_event_free(ev);
> +		if (pkt != ODP_PACKET_INVALID) {

and that check for invalid.

In my understanding recv() can return -1 and in the same time it can 
corrupt buffer memory or already set it to some valid packet value.
In case with direct recv() it's better to relay on return code then on 
memory buffer (&pkt).

Maxim.

> +			if (pktio_pkt_seq(pkt) == seq)
> +				return pkt;
> +
> +			odp_packet_free(pkt);
>   		}
>   
>   		now = odp_time_cycles();
> @@ -438,7 +444,7 @@ static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
>   
>   	/* and wait for them to arrive back */
>   	for (i = 0; i < num_pkts; ++i) {
> -		rx_pkt = wait_for_packet(pktio_b->inq, tx_seq[i], ODP_TIME_SEC);
> +		rx_pkt = wait_for_packet(pktio_b, tx_seq[i], ODP_TIME_SEC);
>   
>   		if (rx_pkt == ODP_PACKET_INVALID)
>   			break;
> @@ -450,7 +456,7 @@ static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
>   	CU_ASSERT(i == num_pkts);
>   }
>   
> -static void test_txrx(odp_queue_type_t q_type, int num_pkts)
> +static void test_txrx(odp_pktio_input_mode_t in_mode, int num_pkts)
>   {
>   	int ret, i, if_b;
>   	pktio_info_t pktios[MAX_NUM_IFACES];
> @@ -461,17 +467,21 @@ static void test_txrx(odp_queue_type_t q_type, int num_pkts)
>   		io = &pktios[i];
>   
>   		io->name = iface_name[i];
> -		io->id   = create_pktio(i, q_type);
> +		io->id   = create_pktio(i, in_mode);
>   		if (io->id == ODP_PKTIO_INVALID) {
>   			CU_FAIL("failed to open iface");
>   			return;
>   		}
> -		create_inq(io->id, q_type);
>   		io->outq = odp_pktio_outq_getdef(io->id);
> -		if (q_type == ODP_QUEUE_TYPE_POLL)
> +		io->in_mode = in_mode;
> +
> +		if (in_mode == ODP_PKTIN_MODE_POLL) {
> +			create_inq(io->id, ODP_QUEUE_TYPE_POLL);
>   			io->inq = odp_pktio_inq_getdef(io->id);
> -		else
> +		} else if (in_mode == ODP_PKTIN_MODE_SCHED) {
> +			create_inq(io->id, ODP_QUEUE_TYPE_SCHED);
>   			io->inq = ODP_QUEUE_INVALID;
> +		}
>   
>   		ret = odp_pktio_start(io->id);
>   		CU_ASSERT(ret == 0);
> @@ -483,7 +493,8 @@ static void test_txrx(odp_queue_type_t q_type, int num_pkts)
>   	pktio_txrx_multi(&pktios[0], &pktios[if_b], num_pkts);
>   
>   	for (i = 0; i < num_ifaces; ++i) {
> -		destroy_inq(pktios[i].id);
> +		if (in_mode != ODP_PKTIN_MODE_RECV)
> +			destroy_inq(pktios[i].id);
>   		ret = odp_pktio_close(pktios[i].id);
>   		CU_ASSERT(ret == 0);
>   	}
> @@ -491,22 +502,32 @@ static void test_txrx(odp_queue_type_t q_type, int num_pkts)
>   
>   void pktio_test_poll_queue(void)
>   {
> -	test_txrx(ODP_QUEUE_TYPE_POLL, 1);
> +	test_txrx(ODP_PKTIN_MODE_POLL, 1);
>   }
>   
>   void pktio_test_poll_multi(void)
>   {
> -	test_txrx(ODP_QUEUE_TYPE_POLL, 4);
> +	test_txrx(ODP_PKTIN_MODE_POLL, 4);
>   }
>   
>   void pktio_test_sched_queue(void)
>   {
> -	test_txrx(ODP_QUEUE_TYPE_SCHED, 1);
> +	test_txrx(ODP_PKTIN_MODE_SCHED, 1);
>   }
>   
>   void pktio_test_sched_multi(void)
>   {
> -	test_txrx(ODP_QUEUE_TYPE_SCHED, 4);
> +	test_txrx(ODP_PKTIN_MODE_SCHED, 4);
> +}
> +
> +void pktio_test_recv(void)
> +{
> +	test_txrx(ODP_PKTIN_MODE_RECV, 1);
> +}
> +
> +void pktio_test_recv_multi(void)
> +{
> +	test_txrx(ODP_PKTIN_MODE_RECV, 4);
>   }
>   
>   void pktio_test_jumbo(void)
> @@ -520,7 +541,7 @@ void pktio_test_mtu(void)
>   {
>   	int ret;
>   	int mtu;
> -	odp_pktio_t pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
> +	odp_pktio_t pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
>   
>   	mtu = odp_pktio_mtu(pktio);
>   	CU_ASSERT(mtu > 0);
> @@ -534,7 +555,7 @@ void pktio_test_mtu(void)
>   void pktio_test_promisc(void)
>   {
>   	int ret;
> -	odp_pktio_t pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
> +	odp_pktio_t pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
>   
>   	ret = odp_pktio_promisc_mode_set(pktio, 1);
>   	CU_ASSERT(0 == ret);
> @@ -561,7 +582,7 @@ void pktio_test_mac(void)
>   	int ret;
>   	odp_pktio_t pktio;
>   
> -	pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
> +	pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
>   
>   	mac_len = odp_pktio_mac_addr(pktio, mac_addr, sizeof(mac_addr));
>   	CU_ASSERT(ODPH_ETHADDR_LEN == mac_len);
> @@ -582,9 +603,9 @@ void pktio_test_inq_remdef(void)
>   	uint64_t wait;
>   	int i;
>   
> -	pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
> +	pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
>   	CU_ASSERT(pktio != ODP_PKTIO_INVALID);
> -	CU_ASSERT(create_inq(pktio, ODP_QUEUE_TYPE_POLL) == 0);
> +	CU_ASSERT(create_inq(pktio, ODP_QUEUE_TYPE_SCHED) == 0);
>   	inq = odp_pktio_inq_getdef(pktio);
>   	CU_ASSERT(inq != ODP_QUEUE_INVALID);
>   	CU_ASSERT(odp_pktio_inq_remdef(pktio) == 0);
> @@ -610,7 +631,7 @@ void pktio_test_open(void)
>   
>   	/* test the sequence open->close->open->close() */
>   	for (i = 0; i < 2; ++i) {
> -		pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
> +		pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
>   		CU_ASSERT(pktio != ODP_PKTIO_INVALID);
>   		CU_ASSERT(odp_pktio_close(pktio) == 0);
>   	}
> @@ -649,7 +670,7 @@ void pktio_test_inq(void)
>   {
>   	odp_pktio_t pktio;
>   
> -	pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
> +	pktio = create_pktio(0, ODP_PKTIN_MODE_POLL);
>   	CU_ASSERT(pktio != ODP_PKTIO_INVALID);
>   
>   	CU_ASSERT(create_inq(pktio, ODP_QUEUE_TYPE_POLL) == 0);
> @@ -668,7 +689,7 @@ static void pktio_test_start_stop(void)
>   	uint64_t wait = odp_schedule_wait_time(ODP_TIME_MSEC);
>   
>   	for (i = 0; i < num_ifaces; i++) {
> -		pktio[i] = create_pktio(i, ODP_QUEUE_TYPE_SCHED);
> +		pktio[i] = create_pktio(i, ODP_PKTIN_MODE_SCHED);
>   		CU_ASSERT(pktio[i] != ODP_PKTIO_INVALID);
>   		create_inq(pktio[i],  ODP_QUEUE_TYPE_SCHED);
>   	}
> @@ -873,6 +894,8 @@ CU_TestInfo pktio_suite_unsegmented[] = {
>   	_CU_TEST_INFO(pktio_test_poll_multi),
>   	_CU_TEST_INFO(pktio_test_sched_queue),
>   	_CU_TEST_INFO(pktio_test_sched_multi),
> +	_CU_TEST_INFO(pktio_test_recv),
> +	_CU_TEST_INFO(pktio_test_recv_multi),
>   	_CU_TEST_INFO(pktio_test_jumbo),
>   	_CU_TEST_INFO(pktio_test_mtu),
>   	_CU_TEST_INFO(pktio_test_promisc),
> @@ -887,6 +910,8 @@ CU_TestInfo pktio_suite_segmented[] = {
>   	_CU_TEST_INFO(pktio_test_poll_multi),
>   	_CU_TEST_INFO(pktio_test_sched_queue),
>   	_CU_TEST_INFO(pktio_test_sched_multi),
> +	_CU_TEST_INFO(pktio_test_recv),
> +	_CU_TEST_INFO(pktio_test_recv_multi),
>   	_CU_TEST_INFO(pktio_test_jumbo),
>   	CU_TEST_INFO_NULL
>   };
> diff --git a/test/validation/pktio/pktio.h b/test/validation/pktio/pktio.h
> index feaf7fb..a14287c 100644
> --- a/test/validation/pktio/pktio.h
> +++ b/test/validation/pktio/pktio.h
> @@ -14,6 +14,8 @@ void pktio_test_poll_queue(void);
>   void pktio_test_poll_multi(void);
>   void pktio_test_sched_queue(void);
>   void pktio_test_sched_multi(void);
> +void pktio_test_recv(void);
> +void pktio_test_recv_multi(void);
>   void pktio_test_jumbo(void);
>   void pktio_test_mtu(void);
>   void pktio_test_promisc(void);
Stuart Haslam Sept. 7, 2015, 2:46 p.m. | #2
On Mon, Sep 07, 2015 at 02:14:50PM +0300, Maxim Uvarov wrote:
> On 09/04/15 12:55, Stuart Haslam wrote:
> >Add a couple of tests for receiving packets directly via
> >odp_pktio_recv().
> >
> >Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>
> >---
> >  test/validation/pktio/pktio.c | 103 ++++++++++++++++++++++++++----------------
> >  test/validation/pktio/pktio.h |   2 +
> >  2 files changed, 66 insertions(+), 39 deletions(-)
> >
> >diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
> >index c74fab3..95c3c34 100644
> >--- a/test/validation/pktio/pktio.c
> >+++ b/test/validation/pktio/pktio.c
> >@@ -34,6 +34,7 @@ typedef struct {
> >  	odp_pktio_t id;
> >  	odp_queue_t outq;
> >  	odp_queue_t inq;
> >+	odp_pktio_input_mode_t in_mode;
> >  } pktio_info_t;
> >  /** magic number and sequence at start of UDP payload */
> >@@ -250,7 +251,7 @@ static int default_pool_create(void)
> >  	return 0;
> >  }
> >-static odp_pktio_t create_pktio(int iface_idx, odp_queue_type_t q_type)
> >+static odp_pktio_t create_pktio(int iface_idx, odp_pktio_input_mode_t mode)
> >  {
> >  	odp_pktio_t pktio;
> >  	odp_pktio_param_t pktio_param;
> >@@ -258,10 +259,7 @@ static odp_pktio_t create_pktio(int iface_idx, odp_queue_type_t q_type)
> >  	memset(&pktio_param, 0, sizeof(pktio_param));
> >-	if (q_type == ODP_QUEUE_TYPE_POLL)
> >-		pktio_param.in_mode = ODP_PKTIN_MODE_POLL;
> >-	else
> >-		pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
> >+	pktio_param.in_mode = mode;
> >  	pktio = odp_pktio_open(iface, pool[iface_idx], &pktio_param);
> >  	if (pktio == ODP_PKTIO_INVALID)
> >@@ -348,33 +346,41 @@ static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns)
> >  	return ODP_EVENT_INVALID;
> >  }
> >-static odp_packet_t wait_for_packet(odp_queue_t queue,
> >+static odp_packet_t wait_for_packet(pktio_info_t *pktio_rx,
> >  				    uint32_t seq, uint64_t ns)
> >  {
> >  	uint64_t start, now, diff;
> >  	odp_event_t ev;
> >-	odp_packet_t pkt = ODP_PACKET_INVALID;
> >+	odp_packet_t pkt;
> >  	uint64_t wait;
> >  	start = odp_time_cycles();
> >  	wait = odp_schedule_wait_time(ns);
> >  	do {
> >-		if (queue != ODP_QUEUE_INVALID &&
> >-		    odp_queue_type(queue) == ODP_QUEUE_TYPE_POLL)
> >-			ev = queue_deq_wait_time(queue, ns);
> >-		else
> >-			ev  = odp_schedule(NULL, wait);
> >-
> >-		if (ev != ODP_EVENT_INVALID) {
> >-			if (odp_event_type(ev) == ODP_EVENT_PACKET) {
> >-				pkt = odp_packet_from_event(ev);
> >-				if (pktio_pkt_seq(pkt) == seq)
> >-					return pkt;
> >+		pkt = ODP_PACKET_INVALID;
> >+
> setting to invalid.
> >+		if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV) {
> >+			odp_pktio_recv(pktio_rx->id, &pkt, 1);
> issue recv
> >+		} else {
> >+			if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
> >+				ev = queue_deq_wait_time(pktio_rx->inq, ns);
> >+			else
> >+				ev = odp_schedule(NULL, wait);
> >+
> >+			if (ev != ODP_EVENT_INVALID) {
> >+				if (odp_event_type(ev) == ODP_EVENT_PACKET)
> >+					pkt = odp_packet_from_event(ev);
> >+				else
> >+					odp_event_free(ev);
> >  			}
> >+		}
> >-			/* not interested in this event */
> >-			odp_event_free(ev);
> >+		if (pkt != ODP_PACKET_INVALID) {
> 
> and that check for invalid.
> 
> In my understanding recv() can return -1 and in the same time it can
> corrupt buffer memory or already set it to some valid packet value.
> In case with direct recv() it's better to relay on return code then
> on memory buffer (&pkt).
> 
> Maxim.

I agree, should be checking the return value, I'll change it.

Patch

diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
index c74fab3..95c3c34 100644
--- a/test/validation/pktio/pktio.c
+++ b/test/validation/pktio/pktio.c
@@ -34,6 +34,7 @@  typedef struct {
 	odp_pktio_t id;
 	odp_queue_t outq;
 	odp_queue_t inq;
+	odp_pktio_input_mode_t in_mode;
 } pktio_info_t;
 
 /** magic number and sequence at start of UDP payload */
@@ -250,7 +251,7 @@  static int default_pool_create(void)
 	return 0;
 }
 
-static odp_pktio_t create_pktio(int iface_idx, odp_queue_type_t q_type)
+static odp_pktio_t create_pktio(int iface_idx, odp_pktio_input_mode_t mode)
 {
 	odp_pktio_t pktio;
 	odp_pktio_param_t pktio_param;
@@ -258,10 +259,7 @@  static odp_pktio_t create_pktio(int iface_idx, odp_queue_type_t q_type)
 
 	memset(&pktio_param, 0, sizeof(pktio_param));
 
-	if (q_type == ODP_QUEUE_TYPE_POLL)
-		pktio_param.in_mode = ODP_PKTIN_MODE_POLL;
-	else
-		pktio_param.in_mode = ODP_PKTIN_MODE_SCHED;
+	pktio_param.in_mode = mode;
 
 	pktio = odp_pktio_open(iface, pool[iface_idx], &pktio_param);
 	if (pktio == ODP_PKTIO_INVALID)
@@ -348,33 +346,41 @@  static odp_event_t queue_deq_wait_time(odp_queue_t queue, uint64_t ns)
 	return ODP_EVENT_INVALID;
 }
 
-static odp_packet_t wait_for_packet(odp_queue_t queue,
+static odp_packet_t wait_for_packet(pktio_info_t *pktio_rx,
 				    uint32_t seq, uint64_t ns)
 {
 	uint64_t start, now, diff;
 	odp_event_t ev;
-	odp_packet_t pkt = ODP_PACKET_INVALID;
+	odp_packet_t pkt;
 	uint64_t wait;
 
 	start = odp_time_cycles();
 	wait = odp_schedule_wait_time(ns);
 
 	do {
-		if (queue != ODP_QUEUE_INVALID &&
-		    odp_queue_type(queue) == ODP_QUEUE_TYPE_POLL)
-			ev = queue_deq_wait_time(queue, ns);
-		else
-			ev  = odp_schedule(NULL, wait);
-
-		if (ev != ODP_EVENT_INVALID) {
-			if (odp_event_type(ev) == ODP_EVENT_PACKET) {
-				pkt = odp_packet_from_event(ev);
-				if (pktio_pkt_seq(pkt) == seq)
-					return pkt;
+		pkt = ODP_PACKET_INVALID;
+
+		if (pktio_rx->in_mode == ODP_PKTIN_MODE_RECV) {
+			odp_pktio_recv(pktio_rx->id, &pkt, 1);
+		} else {
+			if (pktio_rx->in_mode == ODP_PKTIN_MODE_POLL)
+				ev = queue_deq_wait_time(pktio_rx->inq, ns);
+			else
+				ev = odp_schedule(NULL, wait);
+
+			if (ev != ODP_EVENT_INVALID) {
+				if (odp_event_type(ev) == ODP_EVENT_PACKET)
+					pkt = odp_packet_from_event(ev);
+				else
+					odp_event_free(ev);
 			}
+		}
 
-			/* not interested in this event */
-			odp_event_free(ev);
+		if (pkt != ODP_PACKET_INVALID) {
+			if (pktio_pkt_seq(pkt) == seq)
+				return pkt;
+
+			odp_packet_free(pkt);
 		}
 
 		now = odp_time_cycles();
@@ -438,7 +444,7 @@  static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
 
 	/* and wait for them to arrive back */
 	for (i = 0; i < num_pkts; ++i) {
-		rx_pkt = wait_for_packet(pktio_b->inq, tx_seq[i], ODP_TIME_SEC);
+		rx_pkt = wait_for_packet(pktio_b, tx_seq[i], ODP_TIME_SEC);
 
 		if (rx_pkt == ODP_PACKET_INVALID)
 			break;
@@ -450,7 +456,7 @@  static void pktio_txrx_multi(pktio_info_t *pktio_a, pktio_info_t *pktio_b,
 	CU_ASSERT(i == num_pkts);
 }
 
-static void test_txrx(odp_queue_type_t q_type, int num_pkts)
+static void test_txrx(odp_pktio_input_mode_t in_mode, int num_pkts)
 {
 	int ret, i, if_b;
 	pktio_info_t pktios[MAX_NUM_IFACES];
@@ -461,17 +467,21 @@  static void test_txrx(odp_queue_type_t q_type, int num_pkts)
 		io = &pktios[i];
 
 		io->name = iface_name[i];
-		io->id   = create_pktio(i, q_type);
+		io->id   = create_pktio(i, in_mode);
 		if (io->id == ODP_PKTIO_INVALID) {
 			CU_FAIL("failed to open iface");
 			return;
 		}
-		create_inq(io->id, q_type);
 		io->outq = odp_pktio_outq_getdef(io->id);
-		if (q_type == ODP_QUEUE_TYPE_POLL)
+		io->in_mode = in_mode;
+
+		if (in_mode == ODP_PKTIN_MODE_POLL) {
+			create_inq(io->id, ODP_QUEUE_TYPE_POLL);
 			io->inq = odp_pktio_inq_getdef(io->id);
-		else
+		} else if (in_mode == ODP_PKTIN_MODE_SCHED) {
+			create_inq(io->id, ODP_QUEUE_TYPE_SCHED);
 			io->inq = ODP_QUEUE_INVALID;
+		}
 
 		ret = odp_pktio_start(io->id);
 		CU_ASSERT(ret == 0);
@@ -483,7 +493,8 @@  static void test_txrx(odp_queue_type_t q_type, int num_pkts)
 	pktio_txrx_multi(&pktios[0], &pktios[if_b], num_pkts);
 
 	for (i = 0; i < num_ifaces; ++i) {
-		destroy_inq(pktios[i].id);
+		if (in_mode != ODP_PKTIN_MODE_RECV)
+			destroy_inq(pktios[i].id);
 		ret = odp_pktio_close(pktios[i].id);
 		CU_ASSERT(ret == 0);
 	}
@@ -491,22 +502,32 @@  static void test_txrx(odp_queue_type_t q_type, int num_pkts)
 
 void pktio_test_poll_queue(void)
 {
-	test_txrx(ODP_QUEUE_TYPE_POLL, 1);
+	test_txrx(ODP_PKTIN_MODE_POLL, 1);
 }
 
 void pktio_test_poll_multi(void)
 {
-	test_txrx(ODP_QUEUE_TYPE_POLL, 4);
+	test_txrx(ODP_PKTIN_MODE_POLL, 4);
 }
 
 void pktio_test_sched_queue(void)
 {
-	test_txrx(ODP_QUEUE_TYPE_SCHED, 1);
+	test_txrx(ODP_PKTIN_MODE_SCHED, 1);
 }
 
 void pktio_test_sched_multi(void)
 {
-	test_txrx(ODP_QUEUE_TYPE_SCHED, 4);
+	test_txrx(ODP_PKTIN_MODE_SCHED, 4);
+}
+
+void pktio_test_recv(void)
+{
+	test_txrx(ODP_PKTIN_MODE_RECV, 1);
+}
+
+void pktio_test_recv_multi(void)
+{
+	test_txrx(ODP_PKTIN_MODE_RECV, 4);
 }
 
 void pktio_test_jumbo(void)
@@ -520,7 +541,7 @@  void pktio_test_mtu(void)
 {
 	int ret;
 	int mtu;
-	odp_pktio_t pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
+	odp_pktio_t pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
 
 	mtu = odp_pktio_mtu(pktio);
 	CU_ASSERT(mtu > 0);
@@ -534,7 +555,7 @@  void pktio_test_mtu(void)
 void pktio_test_promisc(void)
 {
 	int ret;
-	odp_pktio_t pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
+	odp_pktio_t pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
 
 	ret = odp_pktio_promisc_mode_set(pktio, 1);
 	CU_ASSERT(0 == ret);
@@ -561,7 +582,7 @@  void pktio_test_mac(void)
 	int ret;
 	odp_pktio_t pktio;
 
-	pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
+	pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
 
 	mac_len = odp_pktio_mac_addr(pktio, mac_addr, sizeof(mac_addr));
 	CU_ASSERT(ODPH_ETHADDR_LEN == mac_len);
@@ -582,9 +603,9 @@  void pktio_test_inq_remdef(void)
 	uint64_t wait;
 	int i;
 
-	pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
+	pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
 	CU_ASSERT(pktio != ODP_PKTIO_INVALID);
-	CU_ASSERT(create_inq(pktio, ODP_QUEUE_TYPE_POLL) == 0);
+	CU_ASSERT(create_inq(pktio, ODP_QUEUE_TYPE_SCHED) == 0);
 	inq = odp_pktio_inq_getdef(pktio);
 	CU_ASSERT(inq != ODP_QUEUE_INVALID);
 	CU_ASSERT(odp_pktio_inq_remdef(pktio) == 0);
@@ -610,7 +631,7 @@  void pktio_test_open(void)
 
 	/* test the sequence open->close->open->close() */
 	for (i = 0; i < 2; ++i) {
-		pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
+		pktio = create_pktio(0, ODP_PKTIN_MODE_SCHED);
 		CU_ASSERT(pktio != ODP_PKTIO_INVALID);
 		CU_ASSERT(odp_pktio_close(pktio) == 0);
 	}
@@ -649,7 +670,7 @@  void pktio_test_inq(void)
 {
 	odp_pktio_t pktio;
 
-	pktio = create_pktio(0, ODP_QUEUE_TYPE_SCHED);
+	pktio = create_pktio(0, ODP_PKTIN_MODE_POLL);
 	CU_ASSERT(pktio != ODP_PKTIO_INVALID);
 
 	CU_ASSERT(create_inq(pktio, ODP_QUEUE_TYPE_POLL) == 0);
@@ -668,7 +689,7 @@  static void pktio_test_start_stop(void)
 	uint64_t wait = odp_schedule_wait_time(ODP_TIME_MSEC);
 
 	for (i = 0; i < num_ifaces; i++) {
-		pktio[i] = create_pktio(i, ODP_QUEUE_TYPE_SCHED);
+		pktio[i] = create_pktio(i, ODP_PKTIN_MODE_SCHED);
 		CU_ASSERT(pktio[i] != ODP_PKTIO_INVALID);
 		create_inq(pktio[i],  ODP_QUEUE_TYPE_SCHED);
 	}
@@ -873,6 +894,8 @@  CU_TestInfo pktio_suite_unsegmented[] = {
 	_CU_TEST_INFO(pktio_test_poll_multi),
 	_CU_TEST_INFO(pktio_test_sched_queue),
 	_CU_TEST_INFO(pktio_test_sched_multi),
+	_CU_TEST_INFO(pktio_test_recv),
+	_CU_TEST_INFO(pktio_test_recv_multi),
 	_CU_TEST_INFO(pktio_test_jumbo),
 	_CU_TEST_INFO(pktio_test_mtu),
 	_CU_TEST_INFO(pktio_test_promisc),
@@ -887,6 +910,8 @@  CU_TestInfo pktio_suite_segmented[] = {
 	_CU_TEST_INFO(pktio_test_poll_multi),
 	_CU_TEST_INFO(pktio_test_sched_queue),
 	_CU_TEST_INFO(pktio_test_sched_multi),
+	_CU_TEST_INFO(pktio_test_recv),
+	_CU_TEST_INFO(pktio_test_recv_multi),
 	_CU_TEST_INFO(pktio_test_jumbo),
 	CU_TEST_INFO_NULL
 };
diff --git a/test/validation/pktio/pktio.h b/test/validation/pktio/pktio.h
index feaf7fb..a14287c 100644
--- a/test/validation/pktio/pktio.h
+++ b/test/validation/pktio/pktio.h
@@ -14,6 +14,8 @@  void pktio_test_poll_queue(void);
 void pktio_test_poll_multi(void);
 void pktio_test_sched_queue(void);
 void pktio_test_sched_multi(void);
+void pktio_test_recv(void);
+void pktio_test_recv_multi(void);
 void pktio_test_jumbo(void);
 void pktio_test_mtu(void);
 void pktio_test_promisc(void);