[3/3] validation: pktio: test for transmit error handling

Message ID 1440089058-12833-3-git-send-email-stuart.haslam@linaro.org
State New
Headers show

Commit Message

Stuart Haslam Aug. 20, 2015, 4:44 p.m.
Test that transmit errors are handled correctly by attempting to send a
packet larger than the MTU of the interface.

Signed-off-by: Stuart Haslam <stuart.haslam@linaro.org>
---
 test/validation/pktio/pktio.c | 168 +++++++++++++++++++++++++++++++++++++-----
 1 file changed, 148 insertions(+), 20 deletions(-)

Patch

diff --git a/test/validation/pktio/pktio.c b/test/validation/pktio/pktio.c
index be4f940..340d691 100644
--- a/test/validation/pktio/pktio.c
+++ b/test/validation/pktio/pktio.c
@@ -21,6 +21,7 @@ 
 #define MAX_NUM_IFACES         2
 #define TEST_SEQ_INVALID       ((uint32_t)~0)
 #define TEST_SEQ_MAGIC         0x92749451
+#define TX_BATCH_LEN           4
 
 /** interface names used for testing */
 static const char *iface_name[MAX_NUM_IFACES];
@@ -34,6 +35,7 @@  typedef struct {
 	odp_pktio_t id;
 	odp_queue_t outq;
 	odp_queue_t inq;
+	enum { PKTIN_MODE_RECV, PKTIN_MODE_POLL, PKTIN_MODE_SCHED } mode;
 } pktio_info_t;
 
 /** magic number and sequence at start of UDP payload */
@@ -336,31 +338,40 @@  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;
 
 	start = odp_time_cycles();
 
 	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, ns);
-
-		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->mode == PKTIN_MODE_RECV) {
+			odp_pktio_recv(pktio_rx->id, &pkt, 1);
+		} else {
+			if (pktio_rx->mode == PKTIN_MODE_POLL)
+				ev = queue_deq_wait_time(pktio_rx->inq, ns);
+			else
+				ev = odp_schedule(NULL,
+						  odp_schedule_wait_time(ns));
+
+			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_buffer_free(odp_buffer_from_event(ev));
+		if (pkt != ODP_PACKET_INVALID) {
+			if (pktio_pkt_seq(pkt) == seq)
+				return pkt;
+
+			odp_packet_free(pkt);
 		}
 
 		now = odp_time_cycles();
@@ -424,7 +435,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;
@@ -454,10 +465,13 @@  static void test_txrx(odp_queue_type_t q_type, int num_pkts)
 		}
 		create_inq(io->id, q_type);
 		io->outq = odp_pktio_outq_getdef(io->id);
-		if (q_type == ODP_QUEUE_TYPE_POLL)
+		if (q_type == ODP_QUEUE_TYPE_POLL) {
+			io->mode = PKTIN_MODE_POLL;
 			io->inq = odp_pktio_inq_getdef(io->id);
-		else
+		} else {
+			io->mode = PKTIN_MODE_SCHED;
 			io->inq = ODP_QUEUE_INVALID;
+		}
 	}
 
 	/* if we have two interfaces then send through one and receive on
@@ -479,7 +493,7 @@  void pktio_test_poll_queue(void)
 
 void pktio_test_poll_multi(void)
 {
-	test_txrx(ODP_QUEUE_TYPE_POLL, 4);
+	test_txrx(ODP_QUEUE_TYPE_POLL, TX_BATCH_LEN);
 }
 
 void pktio_test_sched_queue(void)
@@ -489,7 +503,7 @@  void pktio_test_sched_queue(void)
 
 void pktio_test_sched_multi(void)
 {
-	test_txrx(ODP_QUEUE_TYPE_SCHED, 4);
+	test_txrx(ODP_QUEUE_TYPE_SCHED, TX_BATCH_LEN);
 }
 
 void pktio_test_jumbo(void)
@@ -632,6 +646,118 @@  void pktio_test_inq(void)
 	CU_ASSERT(odp_pktio_close(pktio) == 0);
 }
 
+static void pktio_test_send_failure(void)
+{
+	odp_pktio_t pktio_tx, pktio_rx;
+	odp_packet_t pkt_tbl[TX_BATCH_LEN];
+	uint32_t pkt_seq[TX_BATCH_LEN];
+	int ret, mtu, i = 0;
+	odp_pool_param_t pool_params;
+	odp_pool_t pkt_pool;
+	int long_pkt_idx = TX_BATCH_LEN / 2;
+	pktio_info_t info_rx;
+	int pkt_len_toobig;
+
+	pktio_tx = create_pktio(iface_name[0], 0);
+	if (pktio_tx == ODP_PKTIO_INVALID) {
+		CU_FAIL("failed to open pktio");
+		return;
+	}
+
+	/* read the MTU from the transmit interface */
+	mtu = odp_pktio_mtu(pktio_tx);
+
+	/* if the interface MTU is larger that the biggest packet we can
+	 * allocate then we can't use this method to test transmit failures */
+	pkt_len_toobig = mtu + 32;
+	if (pkt_len_toobig > ODP_CONFIG_PACKET_BUF_LEN_MAX) {
+		CU_ASSERT(odp_pktio_close(pktio_tx) == 0);
+		return;
+	}
+
+	/* configure the pool so that we can generate test packets larger
+	 * than the interface MTU */
+	memset(&pool_params, 0, sizeof(pool_params));
+	pool_params.pkt.len     = pkt_len_toobig;
+	pool_params.pkt.seg_len = pool_params.pkt.len;
+	pool_params.pkt.num     = TX_BATCH_LEN + 1;
+	pool_params.type        = ODP_POOL_PACKET;
+	pkt_pool = odp_pool_create("pkt_pool_oversize", &pool_params);
+	CU_ASSERT_FATAL(pkt_pool != ODP_POOL_INVALID);
+
+	if (num_ifaces > 1)
+		pktio_rx = create_pktio(iface_name[1], 1);
+	else
+		pktio_rx = pktio_tx;
+
+	/* generate a batch of packets with a single overly long packet
+	 * in the middle */
+	for (i = 0; i < TX_BATCH_LEN; ++i) {
+		uint32_t pkt_len;
+
+		if (i == long_pkt_idx)
+			pkt_len = pool_params.pkt.len;
+		else
+			pkt_len = PKT_LEN_NORMAL;
+
+		pkt_tbl[i] = odp_packet_alloc(pkt_pool, pkt_len);
+		if (pkt_tbl[i] == ODP_PACKET_INVALID)
+			break;
+
+		pkt_seq[i] = pktio_init_packet(pkt_tbl[i]);
+		if (pkt_seq[i] == TEST_SEQ_INVALID)
+			break;
+	}
+
+	if (i != TX_BATCH_LEN) {
+		CU_FAIL("failed to generate test packets\n");
+		return;
+	}
+
+	/* try to send the batch with the long packet in the middle, the
+	 * initial short packets should be sent */
+	odp_errno_zero();
+	ret = odp_pktio_send(pktio_tx, pkt_tbl, TX_BATCH_LEN);
+	CU_ASSERT(ret == long_pkt_idx);
+	CU_ASSERT(odp_errno() == 0);
+
+	info_rx.id   = pktio_rx;
+	info_rx.outq = ODP_QUEUE_INVALID;
+	info_rx.inq  = ODP_QUEUE_INVALID;
+	info_rx.mode = PKTIN_MODE_RECV;
+
+	for (i = 0; i < ret; ++i) {
+		pkt_tbl[i] = wait_for_packet(&info_rx,
+					     pkt_seq[i], ODP_TIME_SEC);
+		if (pkt_tbl[i] == ODP_PACKET_INVALID)
+			break;
+	}
+
+	if (i != ret) {
+		CU_FAIL("failed to receive transmitted packets\n");
+		return;
+	}
+
+	/* now try to send starting with the too-long packet and verify
+	 * it fails */
+	odp_errno_zero();
+	ret = odp_pktio_send(pktio_tx,
+			     &pkt_tbl[long_pkt_idx],
+			     TX_BATCH_LEN - long_pkt_idx);
+	CU_ASSERT(ret == -1);
+	CU_ASSERT(odp_errno() != 0);
+
+	for (i = 0; i < TX_BATCH_LEN; ++i) {
+		if (pkt_tbl[i] != ODP_PACKET_INVALID)
+			odp_packet_free(pkt_tbl[i]);
+	}
+
+	if (pktio_rx != pktio_tx)
+		CU_ASSERT(odp_pktio_close(pktio_rx) == 0);
+	CU_ASSERT(odp_pktio_close(pktio_tx) == 0);
+	CU_ASSERT(odp_pool_destroy(pkt_pool) == 0);
+}
+
 static int create_pool(const char *iface, int num)
 {
 	char pool_name[ODP_POOL_NAME_LEN];
@@ -737,6 +863,7 @@  CU_TestInfo pktio_suite_unsegmented[] = {
 	{"pktio sched queues",	pktio_test_sched_queue},
 	{"pktio sched multi",	pktio_test_sched_multi},
 	{"pktio jumbo frames",	pktio_test_jumbo},
+	{"pktio send failure",	pktio_test_send_failure},
 	{"pktio mtu",		pktio_test_mtu},
 	{"pktio promisc mode",	pktio_test_promisc},
 	{"pktio mac",		pktio_test_mac},
@@ -750,6 +877,7 @@  CU_TestInfo pktio_suite_segmented[] = {
 	{"pktio sched queues",	pktio_test_sched_queue},
 	{"pktio sched multi",	pktio_test_sched_multi},
 	{"pktio jumbo frames",	pktio_test_jumbo},
+	{"pktio send failure",	pktio_test_send_failure},
 	CU_TEST_INFO_NULL
 };