@@ -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
};
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(-)