DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs
@ 2019-04-15 12:40 Lavanya Govindarajan
  2019-04-15 12:40 ` Lavanya Govindarajan
                   ` (5 more replies)
  0 siblings, 6 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-04-15 12:40 UTC (permalink / raw)
  To: dev; +Cc: reshma.pattan, olivier.matz, bruce.richardson, Lavanya Govindarajan

added new unit test cases for
rte_validate_tx_offload,
rte_pktmbuf_alloc_bulk,
rte_pktmbuf_read,
rte_pktmbuf_ext_shinfo_init_helper,
rte_pktmbuf_attach_extbuf,
rte_mbuf_ext_refcnt_read,
rte_mbuf_ext_refcnt_update,
rte_mbuf_ext_refcnt_set,
rte_pktmbuf_detach_extbuf

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
---
 app/test/test_mbuf.c | 820 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 817 insertions(+), 3 deletions(-)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 030385ec5..74259b313 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -28,16 +28,24 @@
 #include <rte_random.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
 
 #include "test.h"
 
+#define MEMPOOL_CACHE_SIZE      32
 #define MBUF_DATA_SIZE          2048
 #define NB_MBUF                 128
 #define MBUF_TEST_DATA_LEN      1464
 #define MBUF_TEST_DATA_LEN2     50
+#define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
+#define MBUF_TEST_SEG_SIZE      64
+#define MBUF_TEST_BURST         8
+#define EXT_BUF_TEST_DATA_LEN   1024
 
 /* size of private data for mbuf in pktmbuf_pool2 */
 #define MBUF2_PRIV_SIZE         128
@@ -59,6 +67,21 @@ static unsigned refcnt_lcore[RTE_MAX_LCORE];
 
 #endif
 
+/* Test flags for tx_offload capacity */
+enum test_mbuf_tx_ol_flag {
+	MBUF_TEST_INVALID_FLAG = 0,
+	MBUF_TEST_IP_CKSUM_IPV6_SET,
+	MBUF_TEST_IP_TYPE_NOT_SET,
+	MBUF_TEST_IP_TYPE_SET,
+	MBUF_TEST_NULL_TSO_SEGSZ,
+	MBUF_TEST_TSO_IP_CKSUM_NOT_SET,
+	MBUF_TEST_TSO_IPV6_SET,
+	MBUF_TEST_TSO_IP_CKSUM_SET,
+	MBUF_TEST_OUTER_IPV4_NOT_SET,
+	MBUF_TEST_OUTER_IPV4_SET,
+	MBUF_TEST_OL_MASK_NOT_SET
+};
+
 /*
  * MBUF
  * ====
@@ -502,7 +525,6 @@ test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,
 		rte_pktmbuf_free(clone2);
 	return -1;
 }
-#undef GOTO_FAIL
 
 /*
  * test allocation and free of mbufs
@@ -1122,6 +1144,706 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+/*
+ * Test to validate tx offload flags in a packet
+ *  - Allocate a mbuf and append header and data.
+ *  - Set mbuf ol_flag (offload flag) to validate fragmented headers.
+ *  - Validate if IP checksum is counted only for IPV4 packet.
+ *  - Validate if IP type is set when PKT_TX_L4_MASK is set.
+ *  - Test to confirm IP type is set when required.
+ *  - Validate if TSO segment size is non zero when TCP_SEG is set.
+ *  - Validate if IP checksum is set for TSO capability.
+ *  - Test to confirm all the TSO packet requirements are met.
+ *  - Validate if outer IP checksum set for non outer IPv4 packet.
+ *  - Test to confirm outer IP checksum is set for outer IPV4 packet.
+ *  - Confirm if packets with no PKT_TX_OFFLOAD_MASK are skipped.
+ */
+static int
+test_mbuf_validate_tx_offload(struct rte_mempool *pktmbuf_pool,
+		uint32_t test_ol_flag)
+{
+	struct rte_mbuf *m = NULL;
+	int ret = 0;
+
+	/* alloc a mbuf and do sanity check */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+	m->ol_flags = 0;
+
+	switch (test_ol_flag) {
+	case MBUF_TEST_IP_CKSUM_IPV6_SET:
+			/* set both IP checksum and IPV6 flags */
+			m->ol_flags |= PKT_TX_IP_CKSUM;
+			m->ol_flags |= PKT_TX_IPV6;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_IP_TYPE_NOT_SET:
+			/* test if any IP type is set */
+			m->ol_flags |= PKT_TX_L4_MASK;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_IP_TYPE_SET:
+			/* test to confirm IP type (IPV4/IPV6) is set */
+			m->ol_flags |= PKT_TX_IPV6;
+			m->ol_flags |= PKT_TX_L4_MASK;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_NULL_TSO_SEGSZ:
+			/* test to check TSO segment size is non-zero */
+			m->ol_flags |= PKT_TX_IPV4;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			/* set 0 tso segment size */
+			m->tso_segsz = 0;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_TSO_IP_CKSUM_NOT_SET:
+			/* test to check if IP checksum is not set for TSO */
+			m->ol_flags |= PKT_TX_IPV4;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			/* set valid tso segment size */
+			m->tso_segsz = 512;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_TSO_IPV6_SET:
+			/* test to confirm TSO for IPV6 type */
+			m->ol_flags |= PKT_TX_IPV6;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			m->tso_segsz = 512;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_TSO_IP_CKSUM_SET:
+			/* test to confirm all TSO requirements met */
+			m->ol_flags |= PKT_TX_IPV4;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			m->tso_segsz = 512;
+			/* set IP checksum flag */
+			m->ol_flags |= PKT_TX_IP_CKSUM;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_OUTER_IPV4_NOT_SET:
+			m->ol_flags |= PKT_TX_IPV6;
+			/* set outer IP checksum for non outer IPv4 pkt */
+			m->ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val:%d; recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_OUTER_IPV4_SET:
+			/* set outer IP checksum for outer IPv4 packet */
+			m->ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+			m->ol_flags |= PKT_TX_OUTER_IPV4;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_OL_MASK_NOT_SET:
+			/* test if packet has no offload capability */
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	default:
+		GOTO_FAIL("%s: Invalid test flag for tx_offload!\n", __func__);
+		break;
+	}
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test for allocating a bulk of mbufs
+ * define an array with positive sizes for mbufs allocations.
+ */
+static int
+test_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int ret = 0;
+	unsigned int idx, loop;
+	unsigned int alloc_counts[] = {
+		0,
+		MEMPOOL_CACHE_SIZE - 1,
+		MEMPOOL_CACHE_SIZE,
+		MEMPOOL_CACHE_SIZE + 1,
+		MEMPOOL_CACHE_SIZE * 1.5,
+		MEMPOOL_CACHE_SIZE * 2,
+		MEMPOOL_CACHE_SIZE * 2 - 1,
+		MEMPOOL_CACHE_SIZE * 2 + 1,
+		89,                         /* random number */
+		MEMPOOL_CACHE_SIZE          /* repeat cache size */
+	};
+	/* allocate a large array of mbuf pointers */
+	struct rte_mbuf *mbufs[NB_MBUF];
+	for (loop = 0; loop < NB_MBUF; loop++)
+		mbufs[loop] = (void *)NULL;
+
+	for (idx = 0; idx < RTE_DIM(alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				alloc_counts[idx]);
+		if (ret == 0) {
+			for (loop = 0; loop < alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+		} else if (ret != 0) {
+			printf("%s: Bulk alloc failed count(%u); ret val(%d)\n",
+					__func__, alloc_counts[idx], ret);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Negative testing for allocating a bulk of mbufs
+ * define an array including negative sizes for mbufs allocations.
+ */
+static int
+test_neg_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int loop, ret = 0;
+	unsigned int idx;
+	int neg_alloc_counts[] = {
+		MEMPOOL_CACHE_SIZE - NB_MBUF,
+		-1,
+		NB_MBUF - 2,
+		NB_MBUF,
+		NB_MBUF + 1,
+		NB_MBUF * 8,
+	};
+	struct rte_mbuf *mbufs[NB_MBUF * 8];
+	for (loop = 0; loop < NB_MBUF * 8; loop++)
+		mbufs[loop] = (void *)NULL;
+
+	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				neg_alloc_counts[idx]);
+		if (ret == 0) {
+			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
+					__func__, neg_alloc_counts[idx], ret);
+			for (loop = 0; loop < neg_alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Test to read mbuf packet using rte_pktmbuf_read
+ */
+static int
+test_rte_pktmbuf_read(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	int off;
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	memset(data, 0xfe, MBUF_TEST_DATA_LEN2);
+
+	/* read the data from mbuf */
+	data_copy = rte_pktmbuf_read(m, 0, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read mbuf packet data from offset
+ */
+static int
+test_rte_pktmbuf_read_from_offset(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct ether_hdr *hdr = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	unsigned int off;
+	unsigned int hdr_len = sizeof(struct ether_hdr);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	/* prepend an ethernet header */
+	hdr = (struct ether_hdr *)rte_pktmbuf_prepend(m, hdr_len);
+	if (hdr == NULL)
+		GOTO_FAIL("%s: Cannot prepend header\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad pkt length", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad data length", __func__);
+	memset(hdr, 0xde, hdr_len);
+
+	/* read mbuf header info from 0 offset */
+	data_copy = rte_pktmbuf_read(m, 0, hdr_len, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header!\n", __func__);
+	for (off = 0; off < hdr_len; off++) {
+		if (data_copy[off] != (char)0xde)
+			GOTO_FAIL("Header info corrupted at offset %u", off);
+	}
+
+	/* append sample data after ethernet header */
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad data length\n", __func__);
+	memset(data, 0xcc, MBUF_TEST_DATA_LEN2);
+
+	/* read mbuf data after header info */
+	data_copy = rte_pktmbuf_read(m, hdr_len, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* partial reading of mbuf data */
+	data_copy = rte_pktmbuf_read(m, hdr_len + 5, MBUF_TEST_DATA_LEN2 - 5,
+			NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2 - 5)
+		GOTO_FAIL("%s: Incorrect data length!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2 - 5; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read length greater than mbuf data_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n",
+				__func__);
+
+	/* read length greater than mbuf pkt_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n",
+				__func__);
+
+	/* read data of zero len from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Corrupted data content!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of zero length from zero offset */
+	data_copy = rte_pktmbuf_read(m, 0, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of header info */
+	if (hdr != (const struct ether_hdr *)data_copy)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* read data of negative size length from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, -1, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of data segment */
+	if (data_copy != data)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* try to read from mbuf with negative size offset */
+	data_copy = rte_pktmbuf_read(m, -1, 0, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	/* try to read from mbuf with negative size offset and len */
+	data_copy = rte_pktmbuf_read(m, -1, -1, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read data from chain of mbufs with data segments.
+ */
+static int
+test_rte_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *pkt = NULL;
+	struct rte_mbuf *pkt_seg = NULL;
+	struct rte_mbuf *pkt_burst[MBUF_TEST_BURST];
+	char *data = NULL;
+	const char *read_data = NULL;
+	char data_buf[EXT_BUF_TEST_DATA_LEN];
+	uint32_t seg, i, total_pkt_len;
+	uint16_t nb_pkt, off;
+	uint32_t nb_segs = MBUF_TEST_DATA_LEN3 / MBUF_TEST_SEG_SIZE;
+	memset(data_buf, 0, EXT_BUF_TEST_DATA_LEN);
+
+	/* allocate pkts in a burst */
+	for (nb_pkt = 0; nb_pkt < MBUF_TEST_BURST; nb_pkt++) {
+		/* alloc a mbuf */
+		pkt = rte_pktmbuf_alloc(pktmbuf_pool);
+		if (pkt == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt) != 0)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		rte_mbuf_sanity_check(pkt, 0);
+
+		data = rte_pktmbuf_append(pkt, MBUF_TEST_DATA_LEN3);
+		if (data == NULL)
+			GOTO_FAIL("%s: Cannot append data\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt) != MBUF_TEST_DATA_LEN3)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		if (rte_pktmbuf_data_len(pkt) != MBUF_TEST_DATA_LEN3)
+			GOTO_FAIL("%s: Bad data length\n", __func__);
+		memset(data, 0xfe, MBUF_TEST_DATA_LEN3);
+		total_pkt_len = pkt->data_len;
+		/* allocate mbuf segments for each pkt */
+		for (seg = 0; seg < nb_segs; seg++) {
+			pkt_seg = rte_pktmbuf_alloc(pktmbuf_pool);
+			if (pkt_seg == NULL)
+				GOTO_FAIL("%s: mbuf allocation failed!\n",
+						__func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) != 0)
+				GOTO_FAIL("%s: Bad packet length\n", __func__);
+			rte_mbuf_sanity_check(pkt_seg, 0);
+			data = rte_pktmbuf_append(pkt_seg,
+					MBUF_TEST_SEG_SIZE);
+			if (data == NULL)
+				GOTO_FAIL("%s: Cannot append data\n", __func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) !=
+					MBUF_TEST_SEG_SIZE)
+				GOTO_FAIL("%s: Bad packet length\n", __func__);
+			if (rte_pktmbuf_data_len(pkt_seg) !=
+					MBUF_TEST_SEG_SIZE)
+				GOTO_FAIL("%s: Bad data length\n", __func__);
+			memset(data, (seg + nb_pkt + 0xaa) % 0x0ff,
+					MBUF_TEST_SEG_SIZE);
+
+			/* create chained mbufs */
+			rte_pktmbuf_chain(pkt, pkt_seg);
+			total_pkt_len += rte_pktmbuf_data_len(pkt_seg);
+			pkt_seg = pkt_seg->next;
+		}
+		pkt_burst[nb_pkt] = pkt;
+		if (rte_pktmbuf_pkt_len(pkt) != total_pkt_len)
+			GOTO_FAIL("%s: Incorrect mbuf packet length!\n",
+					__func__);
+	}
+	/* point to the first chained mbufs burst */
+	pkt = pkt_burst[0];
+	if (rte_pktmbuf_is_contiguous(pkt))
+		GOTO_FAIL("Buffer should be non contiguous!");
+	/* read data of first mbuf segment */
+	read_data = rte_pktmbuf_read(pkt, 0, MBUF_TEST_DATA_LEN3, NULL);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN3; off++) {
+		if (read_data[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data after first mbuf segment */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len, MBUF_TEST_SEG_SIZE,
+			&data_buf);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE; off++) {
+		if (read_data[off] != (char)0xaa)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data with offset into second mbuf segment */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len + 5,
+			MBUF_TEST_SEG_SIZE - 5, NULL);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE - 5; off++) {
+		if (read_data[off] != (char)0xaa)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data with offset into fourth segment of 5th mbuf packet burst */
+	pkt = pkt_burst[4];
+	read_data = rte_pktmbuf_read(pkt,
+			pkt->data_len + (MBUF_TEST_SEG_SIZE * 2) + 3,
+			MBUF_TEST_SEG_SIZE - 3, NULL);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE - 3; off++) {
+		/* mbuf array index = 4, seg index = 2; index starts from 0 */
+		if (read_data[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data beyond one mbuf segment length */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len + MBUF_TEST_SEG_SIZE,
+			MBUF_TEST_SEG_SIZE + 2, &data_buf);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (read_data != data_buf)
+		GOTO_FAIL("%s: Invalid data address!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE + 2; off++) {
+		if (off < MBUF_TEST_SEG_SIZE &&
+				data_buf[off] != (char)(4 + 1 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if (off >= MBUF_TEST_SEG_SIZE &&
+				data_buf[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of all mbuf segments after the initial data offset */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len,
+			MBUF_TEST_SEG_SIZE * nb_segs, &data_buf);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (read_data != data_buf)
+		GOTO_FAIL("%s: Invalid data address!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE * nb_segs; off++) {
+		if (off < MBUF_TEST_SEG_SIZE &&
+				data_buf[off] != (char)(4 + 0 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if ((off >= MBUF_TEST_SEG_SIZE && off < MBUF_TEST_SEG_SIZE * 2)
+				&& data_buf[off] !=
+				(char)(4 + 1 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if ((off >= MBUF_TEST_SEG_SIZE * 2 &&
+					off < MBUF_TEST_SEG_SIZE * 3) &&
+				data_buf[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if (off >= MBUF_TEST_SEG_SIZE * 4 &&
+				data_buf[off] != (char)(4 + 3 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	for (i = 0; i < nb_pkt && pkt_burst[i] != NULL; i++)
+		rte_pktmbuf_dump(stdout, pkt_burst[i],
+				rte_pktmbuf_pkt_len(pkt_burst[i]));
+
+	for (i = 0; i < nb_pkt && pkt_burst[i] != NULL; i++) {
+		rte_pktmbuf_free(pkt_burst[i]);
+		pkt_burst[i] = NULL;
+	}
+	return 0;
+
+fail:
+	for (i = 0; i < nb_pkt && pkt_burst[i] != NULL; i++) {
+		rte_pktmbuf_free(pkt_burst[i]);
+		pkt_burst[i] = NULL;
+	}
+	return -1;
+}
+
+/* Define a free call back function to be used for external buffer */
+static void
+ext_buf_free_callback_fn(void *addr __rte_unused, void *opaque)
+{
+	void *ext_buf_addr = opaque;
+	if (ext_buf_addr == NULL) {
+		printf("External buffer address is invalid\n");
+		return;
+	}
+	rte_free(ext_buf_addr);
+	ext_buf_addr = NULL;
+	printf("External buffer freed via callback\n");
+}
+
+/*
+ * Test to initialize shared data in external buffer before attaching to mbuf
+ *  - Allocate mbuf with no data.
+ *  - Allocate external buffer with size should be large enough to accommodate
+ *     rte_mbuf_ext_shared_info.
+ *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
+ *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
+ *  - Clone another mbuf and attach the same external buffer to it.
+ *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from mbuf.
+ */
+static int
+test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct rte_mbuf *clone = NULL;
+	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
+	rte_iova_t buf_iova;
+	void *ext_buf_addr = NULL;
+	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
+				sizeof(struct rte_mbuf_ext_shared_info);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	ext_buf_addr = rte_malloc("External buffer", buf_len,
+			RTE_CACHE_LINE_SIZE);
+	if (ext_buf_addr == NULL)
+		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
+
+	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr, &buf_len,
+		ext_buf_free_callback_fn, ext_buf_addr);
+	if (ret_shinfo == NULL)
+		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
+
+	if (rte_mbuf_refcnt_read(m) != 1)
+		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
+
+	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
+	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
+		ret_shinfo);
+	if (m->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	/* allocate one more mbuf */
+	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
+	if (clone == NULL)
+		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(clone) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+
+	/* attach the same external buffer to the cloned mbuf */
+	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
+			ret_shinfo);
+	if (clone->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	/* test to manually update ext_buf_ref_cnt from 2 to 3*/
+	rte_mbuf_ext_refcnt_update(ret_shinfo, 1);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 3)
+		GOTO_FAIL("%s: Update ext_buf ref_cnt failed\n", __func__);
+
+	/* reset the ext_refcnt before freeing the external buffer */
+	rte_mbuf_ext_refcnt_set(ret_shinfo, 2);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: set ext_buf ref_cnt failed\n", __func__);
+
+	/* detach the external buffer from mbufs */
+	rte_pktmbuf_detach_extbuf(m);
+	/* check if ref cnt is decremented */
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_detach_extbuf(clone);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 0)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	rte_pktmbuf_free(clone);
+	clone = NULL;
+
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	if (clone) {
+		rte_pktmbuf_free(clone);
+		clone = NULL;
+	}
+	if (ext_buf_addr != NULL) {
+		rte_free(ext_buf_addr);
+		ext_buf_addr = NULL;
+	}
+	return -1;
+}
+
 static int
 test_mbuf(void)
 {
@@ -1134,7 +1856,8 @@ test_mbuf(void)
 
 	/* create pktmbuf pool if it does not exist */
 	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
-			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1144,7 +1867,8 @@ test_mbuf(void)
 	/* create a specific pktmbuf pool with a priv_size != 0 and no data
 	 * room size */
 	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
-			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool2 == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1226,7 +1950,96 @@ test_mbuf(void)
 		goto err;
 	}
 
+	/* test to validate tx offload flags */
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_IP_CKSUM_IPV6_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_IP_TYPE_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_IP_TYPE_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_NULL_TSO_SEGSZ) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_TSO_IP_CKSUM_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_TSO_IPV6_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_TSO_IP_CKSUM_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_OUTER_IPV4_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_OUTER_IPV4_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_OL_MASK_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_rte_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_neg_rte_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_neg_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet */
+	if (test_rte_pktmbuf_read(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet from offset */
+	if (test_rte_pktmbuf_read_from_offset(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_offset() failed\n");
+		goto err;
+	}
+
+	/* test to read data from chain of mbufs with data segments */
+	if (test_rte_pktmbuf_read_from_chain(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_chain() failed\n");
+		goto err;
+	}
+
+	/* test to initialize shared info. at the end of external buffer */
+	if (test_pktmbuf_ext_shinfo_init_helper(pktmbuf_pool) < 0) {
+		printf("test_pktmbuf_ext_shinfo_init_helper() failed\n");
+		goto err;
+	}
+
 	ret = 0;
+
 err:
 	rte_mempool_free(pktmbuf_pool);
 	rte_mempool_free(pktmbuf_pool2);
@@ -1234,3 +2047,4 @@ test_mbuf(void)
 }
 
 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);
+#undef GOTO_FAIL
-- 
2.17.2

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs
  2019-04-15 12:40 [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
@ 2019-04-15 12:40 ` Lavanya Govindarajan
  2019-05-31 10:45 ` Pattan, Reshma
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-04-15 12:40 UTC (permalink / raw)
  To: dev; +Cc: reshma.pattan, olivier.matz, bruce.richardson, Lavanya Govindarajan

added new unit test cases for
rte_validate_tx_offload,
rte_pktmbuf_alloc_bulk,
rte_pktmbuf_read,
rte_pktmbuf_ext_shinfo_init_helper,
rte_pktmbuf_attach_extbuf,
rte_mbuf_ext_refcnt_read,
rte_mbuf_ext_refcnt_update,
rte_mbuf_ext_refcnt_set,
rte_pktmbuf_detach_extbuf

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
---
 app/test/test_mbuf.c | 820 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 817 insertions(+), 3 deletions(-)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 030385ec5..74259b313 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -28,16 +28,24 @@
 #include <rte_random.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
 
 #include "test.h"
 
+#define MEMPOOL_CACHE_SIZE      32
 #define MBUF_DATA_SIZE          2048
 #define NB_MBUF                 128
 #define MBUF_TEST_DATA_LEN      1464
 #define MBUF_TEST_DATA_LEN2     50
+#define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
+#define MBUF_TEST_SEG_SIZE      64
+#define MBUF_TEST_BURST         8
+#define EXT_BUF_TEST_DATA_LEN   1024
 
 /* size of private data for mbuf in pktmbuf_pool2 */
 #define MBUF2_PRIV_SIZE         128
@@ -59,6 +67,21 @@ static unsigned refcnt_lcore[RTE_MAX_LCORE];
 
 #endif
 
+/* Test flags for tx_offload capacity */
+enum test_mbuf_tx_ol_flag {
+	MBUF_TEST_INVALID_FLAG = 0,
+	MBUF_TEST_IP_CKSUM_IPV6_SET,
+	MBUF_TEST_IP_TYPE_NOT_SET,
+	MBUF_TEST_IP_TYPE_SET,
+	MBUF_TEST_NULL_TSO_SEGSZ,
+	MBUF_TEST_TSO_IP_CKSUM_NOT_SET,
+	MBUF_TEST_TSO_IPV6_SET,
+	MBUF_TEST_TSO_IP_CKSUM_SET,
+	MBUF_TEST_OUTER_IPV4_NOT_SET,
+	MBUF_TEST_OUTER_IPV4_SET,
+	MBUF_TEST_OL_MASK_NOT_SET
+};
+
 /*
  * MBUF
  * ====
@@ -502,7 +525,6 @@ test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,
 		rte_pktmbuf_free(clone2);
 	return -1;
 }
-#undef GOTO_FAIL
 
 /*
  * test allocation and free of mbufs
@@ -1122,6 +1144,706 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+/*
+ * Test to validate tx offload flags in a packet
+ *  - Allocate a mbuf and append header and data.
+ *  - Set mbuf ol_flag (offload flag) to validate fragmented headers.
+ *  - Validate if IP checksum is counted only for IPV4 packet.
+ *  - Validate if IP type is set when PKT_TX_L4_MASK is set.
+ *  - Test to confirm IP type is set when required.
+ *  - Validate if TSO segment size is non zero when TCP_SEG is set.
+ *  - Validate if IP checksum is set for TSO capability.
+ *  - Test to confirm all the TSO packet requirements are met.
+ *  - Validate if outer IP checksum set for non outer IPv4 packet.
+ *  - Test to confirm outer IP checksum is set for outer IPV4 packet.
+ *  - Confirm if packets with no PKT_TX_OFFLOAD_MASK are skipped.
+ */
+static int
+test_mbuf_validate_tx_offload(struct rte_mempool *pktmbuf_pool,
+		uint32_t test_ol_flag)
+{
+	struct rte_mbuf *m = NULL;
+	int ret = 0;
+
+	/* alloc a mbuf and do sanity check */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+	m->ol_flags = 0;
+
+	switch (test_ol_flag) {
+	case MBUF_TEST_IP_CKSUM_IPV6_SET:
+			/* set both IP checksum and IPV6 flags */
+			m->ol_flags |= PKT_TX_IP_CKSUM;
+			m->ol_flags |= PKT_TX_IPV6;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_IP_TYPE_NOT_SET:
+			/* test if any IP type is set */
+			m->ol_flags |= PKT_TX_L4_MASK;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_IP_TYPE_SET:
+			/* test to confirm IP type (IPV4/IPV6) is set */
+			m->ol_flags |= PKT_TX_IPV6;
+			m->ol_flags |= PKT_TX_L4_MASK;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_NULL_TSO_SEGSZ:
+			/* test to check TSO segment size is non-zero */
+			m->ol_flags |= PKT_TX_IPV4;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			/* set 0 tso segment size */
+			m->tso_segsz = 0;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_TSO_IP_CKSUM_NOT_SET:
+			/* test to check if IP checksum is not set for TSO */
+			m->ol_flags |= PKT_TX_IPV4;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			/* set valid tso segment size */
+			m->tso_segsz = 512;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val: %d;recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_TSO_IPV6_SET:
+			/* test to confirm TSO for IPV6 type */
+			m->ol_flags |= PKT_TX_IPV6;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			m->tso_segsz = 512;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_TSO_IP_CKSUM_SET:
+			/* test to confirm all TSO requirements met */
+			m->ol_flags |= PKT_TX_IPV4;
+			m->ol_flags |= PKT_TX_TCP_SEG;
+			m->tso_segsz = 512;
+			/* set IP checksum flag */
+			m->ol_flags |= PKT_TX_IP_CKSUM;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_OUTER_IPV4_NOT_SET:
+			m->ol_flags |= PKT_TX_IPV6;
+			/* set outer IP checksum for non outer IPv4 pkt */
+			m->ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+			ret = rte_validate_tx_offload(m);
+			if (ret != -EINVAL)
+				GOTO_FAIL("%s:Expected ret val:%d; recvd: %d\n",
+						__func__, -EINVAL, ret);
+		break;
+	case MBUF_TEST_OUTER_IPV4_SET:
+			/* set outer IP checksum for outer IPv4 packet */
+			m->ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+			m->ol_flags |= PKT_TX_OUTER_IPV4;
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	case MBUF_TEST_OL_MASK_NOT_SET:
+			/* test if packet has no offload capability */
+			ret = rte_validate_tx_offload(m);
+			if (ret != 0)
+				GOTO_FAIL("%s:Expected ret val: 0; recvd: %d\n",
+						__func__, ret);
+		break;
+	default:
+		GOTO_FAIL("%s: Invalid test flag for tx_offload!\n", __func__);
+		break;
+	}
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test for allocating a bulk of mbufs
+ * define an array with positive sizes for mbufs allocations.
+ */
+static int
+test_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int ret = 0;
+	unsigned int idx, loop;
+	unsigned int alloc_counts[] = {
+		0,
+		MEMPOOL_CACHE_SIZE - 1,
+		MEMPOOL_CACHE_SIZE,
+		MEMPOOL_CACHE_SIZE + 1,
+		MEMPOOL_CACHE_SIZE * 1.5,
+		MEMPOOL_CACHE_SIZE * 2,
+		MEMPOOL_CACHE_SIZE * 2 - 1,
+		MEMPOOL_CACHE_SIZE * 2 + 1,
+		89,                         /* random number */
+		MEMPOOL_CACHE_SIZE          /* repeat cache size */
+	};
+	/* allocate a large array of mbuf pointers */
+	struct rte_mbuf *mbufs[NB_MBUF];
+	for (loop = 0; loop < NB_MBUF; loop++)
+		mbufs[loop] = (void *)NULL;
+
+	for (idx = 0; idx < RTE_DIM(alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				alloc_counts[idx]);
+		if (ret == 0) {
+			for (loop = 0; loop < alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+		} else if (ret != 0) {
+			printf("%s: Bulk alloc failed count(%u); ret val(%d)\n",
+					__func__, alloc_counts[idx], ret);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Negative testing for allocating a bulk of mbufs
+ * define an array including negative sizes for mbufs allocations.
+ */
+static int
+test_neg_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int loop, ret = 0;
+	unsigned int idx;
+	int neg_alloc_counts[] = {
+		MEMPOOL_CACHE_SIZE - NB_MBUF,
+		-1,
+		NB_MBUF - 2,
+		NB_MBUF,
+		NB_MBUF + 1,
+		NB_MBUF * 8,
+	};
+	struct rte_mbuf *mbufs[NB_MBUF * 8];
+	for (loop = 0; loop < NB_MBUF * 8; loop++)
+		mbufs[loop] = (void *)NULL;
+
+	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				neg_alloc_counts[idx]);
+		if (ret == 0) {
+			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
+					__func__, neg_alloc_counts[idx], ret);
+			for (loop = 0; loop < neg_alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Test to read mbuf packet using rte_pktmbuf_read
+ */
+static int
+test_rte_pktmbuf_read(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	int off;
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	memset(data, 0xfe, MBUF_TEST_DATA_LEN2);
+
+	/* read the data from mbuf */
+	data_copy = rte_pktmbuf_read(m, 0, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read mbuf packet data from offset
+ */
+static int
+test_rte_pktmbuf_read_from_offset(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct ether_hdr *hdr = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	unsigned int off;
+	unsigned int hdr_len = sizeof(struct ether_hdr);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	/* prepend an ethernet header */
+	hdr = (struct ether_hdr *)rte_pktmbuf_prepend(m, hdr_len);
+	if (hdr == NULL)
+		GOTO_FAIL("%s: Cannot prepend header\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad pkt length", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad data length", __func__);
+	memset(hdr, 0xde, hdr_len);
+
+	/* read mbuf header info from 0 offset */
+	data_copy = rte_pktmbuf_read(m, 0, hdr_len, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header!\n", __func__);
+	for (off = 0; off < hdr_len; off++) {
+		if (data_copy[off] != (char)0xde)
+			GOTO_FAIL("Header info corrupted at offset %u", off);
+	}
+
+	/* append sample data after ethernet header */
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad data length\n", __func__);
+	memset(data, 0xcc, MBUF_TEST_DATA_LEN2);
+
+	/* read mbuf data after header info */
+	data_copy = rte_pktmbuf_read(m, hdr_len, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* partial reading of mbuf data */
+	data_copy = rte_pktmbuf_read(m, hdr_len + 5, MBUF_TEST_DATA_LEN2 - 5,
+			NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2 - 5)
+		GOTO_FAIL("%s: Incorrect data length!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2 - 5; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read length greater than mbuf data_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n",
+				__func__);
+
+	/* read length greater than mbuf pkt_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n",
+				__func__);
+
+	/* read data of zero len from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Corrupted data content!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of zero length from zero offset */
+	data_copy = rte_pktmbuf_read(m, 0, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of header info */
+	if (hdr != (const struct ether_hdr *)data_copy)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* read data of negative size length from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, -1, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of data segment */
+	if (data_copy != data)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* try to read from mbuf with negative size offset */
+	data_copy = rte_pktmbuf_read(m, -1, 0, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	/* try to read from mbuf with negative size offset and len */
+	data_copy = rte_pktmbuf_read(m, -1, -1, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read data from chain of mbufs with data segments.
+ */
+static int
+test_rte_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *pkt = NULL;
+	struct rte_mbuf *pkt_seg = NULL;
+	struct rte_mbuf *pkt_burst[MBUF_TEST_BURST];
+	char *data = NULL;
+	const char *read_data = NULL;
+	char data_buf[EXT_BUF_TEST_DATA_LEN];
+	uint32_t seg, i, total_pkt_len;
+	uint16_t nb_pkt, off;
+	uint32_t nb_segs = MBUF_TEST_DATA_LEN3 / MBUF_TEST_SEG_SIZE;
+	memset(data_buf, 0, EXT_BUF_TEST_DATA_LEN);
+
+	/* allocate pkts in a burst */
+	for (nb_pkt = 0; nb_pkt < MBUF_TEST_BURST; nb_pkt++) {
+		/* alloc a mbuf */
+		pkt = rte_pktmbuf_alloc(pktmbuf_pool);
+		if (pkt == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt) != 0)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		rte_mbuf_sanity_check(pkt, 0);
+
+		data = rte_pktmbuf_append(pkt, MBUF_TEST_DATA_LEN3);
+		if (data == NULL)
+			GOTO_FAIL("%s: Cannot append data\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt) != MBUF_TEST_DATA_LEN3)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		if (rte_pktmbuf_data_len(pkt) != MBUF_TEST_DATA_LEN3)
+			GOTO_FAIL("%s: Bad data length\n", __func__);
+		memset(data, 0xfe, MBUF_TEST_DATA_LEN3);
+		total_pkt_len = pkt->data_len;
+		/* allocate mbuf segments for each pkt */
+		for (seg = 0; seg < nb_segs; seg++) {
+			pkt_seg = rte_pktmbuf_alloc(pktmbuf_pool);
+			if (pkt_seg == NULL)
+				GOTO_FAIL("%s: mbuf allocation failed!\n",
+						__func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) != 0)
+				GOTO_FAIL("%s: Bad packet length\n", __func__);
+			rte_mbuf_sanity_check(pkt_seg, 0);
+			data = rte_pktmbuf_append(pkt_seg,
+					MBUF_TEST_SEG_SIZE);
+			if (data == NULL)
+				GOTO_FAIL("%s: Cannot append data\n", __func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) !=
+					MBUF_TEST_SEG_SIZE)
+				GOTO_FAIL("%s: Bad packet length\n", __func__);
+			if (rte_pktmbuf_data_len(pkt_seg) !=
+					MBUF_TEST_SEG_SIZE)
+				GOTO_FAIL("%s: Bad data length\n", __func__);
+			memset(data, (seg + nb_pkt + 0xaa) % 0x0ff,
+					MBUF_TEST_SEG_SIZE);
+
+			/* create chained mbufs */
+			rte_pktmbuf_chain(pkt, pkt_seg);
+			total_pkt_len += rte_pktmbuf_data_len(pkt_seg);
+			pkt_seg = pkt_seg->next;
+		}
+		pkt_burst[nb_pkt] = pkt;
+		if (rte_pktmbuf_pkt_len(pkt) != total_pkt_len)
+			GOTO_FAIL("%s: Incorrect mbuf packet length!\n",
+					__func__);
+	}
+	/* point to the first chained mbufs burst */
+	pkt = pkt_burst[0];
+	if (rte_pktmbuf_is_contiguous(pkt))
+		GOTO_FAIL("Buffer should be non contiguous!");
+	/* read data of first mbuf segment */
+	read_data = rte_pktmbuf_read(pkt, 0, MBUF_TEST_DATA_LEN3, NULL);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN3; off++) {
+		if (read_data[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data after first mbuf segment */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len, MBUF_TEST_SEG_SIZE,
+			&data_buf);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE; off++) {
+		if (read_data[off] != (char)0xaa)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data with offset into second mbuf segment */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len + 5,
+			MBUF_TEST_SEG_SIZE - 5, NULL);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE - 5; off++) {
+		if (read_data[off] != (char)0xaa)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data with offset into fourth segment of 5th mbuf packet burst */
+	pkt = pkt_burst[4];
+	read_data = rte_pktmbuf_read(pkt,
+			pkt->data_len + (MBUF_TEST_SEG_SIZE * 2) + 3,
+			MBUF_TEST_SEG_SIZE - 3, NULL);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE - 3; off++) {
+		/* mbuf array index = 4, seg index = 2; index starts from 0 */
+		if (read_data[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data beyond one mbuf segment length */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len + MBUF_TEST_SEG_SIZE,
+			MBUF_TEST_SEG_SIZE + 2, &data_buf);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (read_data != data_buf)
+		GOTO_FAIL("%s: Invalid data address!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE + 2; off++) {
+		if (off < MBUF_TEST_SEG_SIZE &&
+				data_buf[off] != (char)(4 + 1 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if (off >= MBUF_TEST_SEG_SIZE &&
+				data_buf[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of all mbuf segments after the initial data offset */
+	read_data = rte_pktmbuf_read(pkt, pkt->data_len,
+			MBUF_TEST_SEG_SIZE * nb_segs, &data_buf);
+	if (read_data == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (read_data != data_buf)
+		GOTO_FAIL("%s: Invalid data address!\n", __func__);
+	for (off = 0; off < MBUF_TEST_SEG_SIZE * nb_segs; off++) {
+		if (off < MBUF_TEST_SEG_SIZE &&
+				data_buf[off] != (char)(4 + 0 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if ((off >= MBUF_TEST_SEG_SIZE && off < MBUF_TEST_SEG_SIZE * 2)
+				&& data_buf[off] !=
+				(char)(4 + 1 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if ((off >= MBUF_TEST_SEG_SIZE * 2 &&
+					off < MBUF_TEST_SEG_SIZE * 3) &&
+				data_buf[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+		if (off >= MBUF_TEST_SEG_SIZE * 4 &&
+				data_buf[off] != (char)(4 + 3 + 0xaa) % 0x0ff)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	for (i = 0; i < nb_pkt && pkt_burst[i] != NULL; i++)
+		rte_pktmbuf_dump(stdout, pkt_burst[i],
+				rte_pktmbuf_pkt_len(pkt_burst[i]));
+
+	for (i = 0; i < nb_pkt && pkt_burst[i] != NULL; i++) {
+		rte_pktmbuf_free(pkt_burst[i]);
+		pkt_burst[i] = NULL;
+	}
+	return 0;
+
+fail:
+	for (i = 0; i < nb_pkt && pkt_burst[i] != NULL; i++) {
+		rte_pktmbuf_free(pkt_burst[i]);
+		pkt_burst[i] = NULL;
+	}
+	return -1;
+}
+
+/* Define a free call back function to be used for external buffer */
+static void
+ext_buf_free_callback_fn(void *addr __rte_unused, void *opaque)
+{
+	void *ext_buf_addr = opaque;
+	if (ext_buf_addr == NULL) {
+		printf("External buffer address is invalid\n");
+		return;
+	}
+	rte_free(ext_buf_addr);
+	ext_buf_addr = NULL;
+	printf("External buffer freed via callback\n");
+}
+
+/*
+ * Test to initialize shared data in external buffer before attaching to mbuf
+ *  - Allocate mbuf with no data.
+ *  - Allocate external buffer with size should be large enough to accommodate
+ *     rte_mbuf_ext_shared_info.
+ *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
+ *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
+ *  - Clone another mbuf and attach the same external buffer to it.
+ *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from mbuf.
+ */
+static int
+test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct rte_mbuf *clone = NULL;
+	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
+	rte_iova_t buf_iova;
+	void *ext_buf_addr = NULL;
+	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
+				sizeof(struct rte_mbuf_ext_shared_info);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	ext_buf_addr = rte_malloc("External buffer", buf_len,
+			RTE_CACHE_LINE_SIZE);
+	if (ext_buf_addr == NULL)
+		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
+
+	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr, &buf_len,
+		ext_buf_free_callback_fn, ext_buf_addr);
+	if (ret_shinfo == NULL)
+		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
+
+	if (rte_mbuf_refcnt_read(m) != 1)
+		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
+
+	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
+	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
+		ret_shinfo);
+	if (m->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	/* allocate one more mbuf */
+	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
+	if (clone == NULL)
+		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(clone) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+
+	/* attach the same external buffer to the cloned mbuf */
+	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
+			ret_shinfo);
+	if (clone->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	/* test to manually update ext_buf_ref_cnt from 2 to 3*/
+	rte_mbuf_ext_refcnt_update(ret_shinfo, 1);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 3)
+		GOTO_FAIL("%s: Update ext_buf ref_cnt failed\n", __func__);
+
+	/* reset the ext_refcnt before freeing the external buffer */
+	rte_mbuf_ext_refcnt_set(ret_shinfo, 2);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: set ext_buf ref_cnt failed\n", __func__);
+
+	/* detach the external buffer from mbufs */
+	rte_pktmbuf_detach_extbuf(m);
+	/* check if ref cnt is decremented */
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_detach_extbuf(clone);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 0)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	rte_pktmbuf_free(clone);
+	clone = NULL;
+
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	if (clone) {
+		rte_pktmbuf_free(clone);
+		clone = NULL;
+	}
+	if (ext_buf_addr != NULL) {
+		rte_free(ext_buf_addr);
+		ext_buf_addr = NULL;
+	}
+	return -1;
+}
+
 static int
 test_mbuf(void)
 {
@@ -1134,7 +1856,8 @@ test_mbuf(void)
 
 	/* create pktmbuf pool if it does not exist */
 	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
-			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1144,7 +1867,8 @@ test_mbuf(void)
 	/* create a specific pktmbuf pool with a priv_size != 0 and no data
 	 * room size */
 	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
-			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool2 == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1226,7 +1950,96 @@ test_mbuf(void)
 		goto err;
 	}
 
+	/* test to validate tx offload flags */
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_IP_CKSUM_IPV6_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_IP_TYPE_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_IP_TYPE_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_NULL_TSO_SEGSZ) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_TSO_IP_CKSUM_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_TSO_IPV6_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_TSO_IP_CKSUM_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_OUTER_IPV4_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_OUTER_IPV4_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
+				MBUF_TEST_OL_MASK_NOT_SET) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_rte_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_neg_rte_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_neg_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet */
+	if (test_rte_pktmbuf_read(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet from offset */
+	if (test_rte_pktmbuf_read_from_offset(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_offset() failed\n");
+		goto err;
+	}
+
+	/* test to read data from chain of mbufs with data segments */
+	if (test_rte_pktmbuf_read_from_chain(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_chain() failed\n");
+		goto err;
+	}
+
+	/* test to initialize shared info. at the end of external buffer */
+	if (test_pktmbuf_ext_shinfo_init_helper(pktmbuf_pool) < 0) {
+		printf("test_pktmbuf_ext_shinfo_init_helper() failed\n");
+		goto err;
+	}
+
 	ret = 0;
+
 err:
 	rte_mempool_free(pktmbuf_pool);
 	rte_mempool_free(pktmbuf_pool2);
@@ -1234,3 +2047,4 @@ test_mbuf(void)
 }
 
 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);
+#undef GOTO_FAIL
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs
  2019-04-15 12:40 [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-04-15 12:40 ` Lavanya Govindarajan
@ 2019-05-31 10:45 ` Pattan, Reshma
  2019-06-03  8:39 ` Olivier Matz
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 22+ messages in thread
From: Pattan, Reshma @ 2019-05-31 10:45 UTC (permalink / raw)
  To: Govindarajan, LavanyaX, dev; +Cc: olivier.matz, Richardson, Bruce



> -----Original Message-----
> From: Govindarajan, LavanyaX
> Sent: Monday, April 15, 2019 1:40 PM
> To: dev@dpdk.org
> Cc: Pattan, Reshma <reshma.pattan@intel.com>; olivier.matz@6wind.com;
> Richardson, Bruce <bruce.richardson@intel.com>; Govindarajan, LavanyaX
> <lavanyax.govindarajan@intel.com>
> Subject: [PATCH] app/test: add unit test cases for mbuf library APIs
> 

<snip>

> __func__);
> +			if (rte_pktmbuf_data_len(pkt_seg) !=
> +					MBUF_TEST_SEG_SIZE)
> +				GOTO_FAIL("%s: Bad data length\n",
> __func__);
> +			memset(data, (seg + nb_pkt + 0xaa) % 0x0ff,
> +					MBUF_TEST_SEG_SIZE);
> +

Also nb_pkt+0xaa is common for all segments, so  doing the addition for each segments waste of cycles, so move to addition out for segments for loop.

Other than that, please keep reviewed-by in next versions.

Reviewed-By: Reshma Pattan <reshma.pattan@intel.com>

Thanks,
Reshma

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs
  2019-04-15 12:40 [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-04-15 12:40 ` Lavanya Govindarajan
  2019-05-31 10:45 ` Pattan, Reshma
@ 2019-06-03  8:39 ` Olivier Matz
  2019-07-22 13:32   ` Govindarajan, LavanyaX
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 0/2] add unit test cases for mbuf library Lavanya Govindarajan
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 22+ messages in thread
From: Olivier Matz @ 2019-06-03  8:39 UTC (permalink / raw)
  To: Lavanya Govindarajan; +Cc: dev, reshma.pattan, bruce.richardson

Hi Lavanya,

Please find some comments inline.

On Mon, Apr 15, 2019 at 01:40:15PM +0100, Lavanya Govindarajan wrote:
> added new unit test cases for
> rte_validate_tx_offload,
> rte_pktmbuf_alloc_bulk,
> rte_pktmbuf_read,
> rte_pktmbuf_ext_shinfo_init_helper,
> rte_pktmbuf_attach_extbuf,
> rte_mbuf_ext_refcnt_read,
> rte_mbuf_ext_refcnt_update,
> rte_mbuf_ext_refcnt_set,
> rte_pktmbuf_detach_extbuf
> 
> Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
> ---
>  app/test/test_mbuf.c | 820 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 817 insertions(+), 3 deletions(-)
> 
> diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
> index 030385ec5..74259b313 100644
> --- a/app/test/test_mbuf.c
> +++ b/app/test/test_mbuf.c

[...]

> +/* Test flags for tx_offload capacity */
> +enum test_mbuf_tx_ol_flag {
> +	MBUF_TEST_INVALID_FLAG = 0,
> +	MBUF_TEST_IP_CKSUM_IPV6_SET,
> +	MBUF_TEST_IP_TYPE_NOT_SET,
> +	MBUF_TEST_IP_TYPE_SET,
> +	MBUF_TEST_NULL_TSO_SEGSZ,
> +	MBUF_TEST_TSO_IP_CKSUM_NOT_SET,
> +	MBUF_TEST_TSO_IPV6_SET,
> +	MBUF_TEST_TSO_IP_CKSUM_SET,
> +	MBUF_TEST_OUTER_IPV4_NOT_SET,
> +	MBUF_TEST_OUTER_IPV4_SET,
> +	MBUF_TEST_OL_MASK_NOT_SET
> +};

[...]

> +/*
> + * Test to validate tx offload flags in a packet
> + *  - Allocate a mbuf and append header and data.
> + *  - Set mbuf ol_flag (offload flag) to validate fragmented headers.
> + *  - Validate if IP checksum is counted only for IPV4 packet.
> + *  - Validate if IP type is set when PKT_TX_L4_MASK is set.
> + *  - Test to confirm IP type is set when required.
> + *  - Validate if TSO segment size is non zero when TCP_SEG is set.
> + *  - Validate if IP checksum is set for TSO capability.
> + *  - Test to confirm all the TSO packet requirements are met.
> + *  - Validate if outer IP checksum set for non outer IPv4 packet.
> + *  - Test to confirm outer IP checksum is set for outer IPV4 packet.
> + *  - Confirm if packets with no PKT_TX_OFFLOAD_MASK are skipped.
> + */
> +static int
> +test_mbuf_validate_tx_offload(struct rte_mempool *pktmbuf_pool,
> +		uint32_t test_ol_flag)
> +{
> +	struct rte_mbuf *m = NULL;
> +	int ret = 0;
> +
> +	/* alloc a mbuf and do sanity check */
> +	m = rte_pktmbuf_alloc(pktmbuf_pool);
> +	if (m == NULL)
> +		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
> +	if (rte_pktmbuf_pkt_len(m) != 0)
> +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> +	rte_mbuf_sanity_check(m, 0);
> +	m->ol_flags = 0;
> +
> +	switch (test_ol_flag) {

Not sure I'm seeing why we need an enum. It results in something like this:

	enum {
		...
	}

	test(num)
	{
		switch (num) {
		case 0: ...
		case 1: ...
		case 2: ...
		}
	}

	test(0);
	test(1);
	test(2);

Instead, what about having a generic function like below:

	test_mbuf_validate_tx_offload(const char *test_name,
		struct rte_mempool *pktmbuf_pool,
		uint64_t ol_flags,
		uint16_t segsize,
		int expected_retval)
	{
		...

		m->ol_flags ol_flags;
		m->tso_segsz = segsize;
		ret = rte_validate_tx_offload(m);
		if (ret != expected_retval)
			GOTO_FAIL("%s(%s): expected ret val: %d; recvd: %d\n",
					__func__, test_name, expected, ret);
		...
	}


> +/*
> + * Test for allocating a bulk of mbufs
> + * define an array with positive sizes for mbufs allocations.
> + */
> +static int
> +test_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
> +{
> +	int ret = 0;
> +	unsigned int idx, loop;
> +	unsigned int alloc_counts[] = {
> +		0,
> +		MEMPOOL_CACHE_SIZE - 1,
> +		MEMPOOL_CACHE_SIZE,
> +		MEMPOOL_CACHE_SIZE + 1,
> +		MEMPOOL_CACHE_SIZE * 1.5,
> +		MEMPOOL_CACHE_SIZE * 2,
> +		MEMPOOL_CACHE_SIZE * 2 - 1,
> +		MEMPOOL_CACHE_SIZE * 2 + 1,
> +		89,                         /* random number */
> +		MEMPOOL_CACHE_SIZE          /* repeat cache size */
> +	};

instead of testing these particular values, why not testing every
values between 0 and NB_MBUF ?

> +	/* allocate a large array of mbuf pointers */
> +	struct rte_mbuf *mbufs[NB_MBUF];
> +	for (loop = 0; loop < NB_MBUF; loop++)
> +		mbufs[loop] = (void *)NULL;

you can use memset() or struct rte_mbuf *mbufs[NB_MBUF] = { 0 };

> +
> +	for (idx = 0; idx < RTE_DIM(alloc_counts); idx++) {
> +		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
> +				alloc_counts[idx]);
> +		if (ret == 0) {
> +			for (loop = 0; loop < alloc_counts[idx] &&
> +					mbufs[loop] != NULL; loop++)
> +				rte_pktmbuf_free(mbufs[loop]);
> +		} else if (ret != 0) {
> +			printf("%s: Bulk alloc failed count(%u); ret val(%d)\n",
> +					__func__, alloc_counts[idx], ret);
> +			return -1;
> +		}
> +	}
> +	return 0;
> +}
> +
> +/*
> + * Negative testing for allocating a bulk of mbufs
> + * define an array including negative sizes for mbufs allocations.
> + */
> +static int
> +test_neg_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
> +{
> +	int loop, ret = 0;
> +	unsigned int idx;
> +	int neg_alloc_counts[] = {
> +		MEMPOOL_CACHE_SIZE - NB_MBUF,
> +		-1,
> +		NB_MBUF - 2,
> +		NB_MBUF,
> +		NB_MBUF + 1,
> +		NB_MBUF * 8,
> +	};

The count parameter of rte_pktmbuf_alloc_bulk() is unsigned, so it is
not necessary to test negative values. Instead, you can eventually test
UINT_MAX.

Also, I feel that the (NB_MBUF - 2) and (NB_MBUF) cases are invalid: they
depend on the amount of mbuf in cache. If the cache is empty, the test will
fail.

> +	struct rte_mbuf *mbufs[NB_MBUF * 8];
> +	for (loop = 0; loop < NB_MBUF * 8; loop++)
> +		mbufs[loop] = (void *)NULL;
> +
> +	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
> +		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
> +				neg_alloc_counts[idx]);
> +		if (ret == 0) {
> +			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
> +					__func__, neg_alloc_counts[idx], ret);
> +			for (loop = 0; loop < neg_alloc_counts[idx] &&
> +					mbufs[loop] != NULL; loop++)
> +				rte_pktmbuf_free(mbufs[loop]);
> +			return -1;
> +		}
> +	}
> +	return 0;
> +}
> +

[...]

> +/*
> + * Test to read mbuf packet data from offset
> + */
> +static int
> +test_rte_pktmbuf_read_from_offset(struct rte_mempool *pktmbuf_pool)
> +{
> +	struct rte_mbuf *m = NULL;
> +	struct ether_hdr *hdr = NULL;
> +	char *data = NULL;
> +	const char *data_copy = NULL;
> +	unsigned int off;
> +	unsigned int hdr_len = sizeof(struct ether_hdr);
> +
> +	/* alloc a mbuf */
> +	m = rte_pktmbuf_alloc(pktmbuf_pool);
> +	if (m == NULL)
> +		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
> +
> +	if (rte_pktmbuf_pkt_len(m) != 0)
> +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> +	rte_mbuf_sanity_check(m, 0);
> +
> +	/* prepend an ethernet header */
> +	hdr = (struct ether_hdr *)rte_pktmbuf_prepend(m, hdr_len);
> +	if (hdr == NULL)
> +		GOTO_FAIL("%s: Cannot prepend header\n", __func__);
> +	if (rte_pktmbuf_pkt_len(m) != hdr_len)
> +		GOTO_FAIL("%s: Bad pkt length", __func__);
> +	if (rte_pktmbuf_data_len(m) != hdr_len)
> +		GOTO_FAIL("%s: Bad data length", __func__);
> +	memset(hdr, 0xde, hdr_len);
> +
> +	/* read mbuf header info from 0 offset */
> +	data_copy = rte_pktmbuf_read(m, 0, hdr_len, NULL);
> +	if (data_copy == NULL)
> +		GOTO_FAIL("%s: Error in reading header!\n", __func__);
> +	for (off = 0; off < hdr_len; off++) {
> +		if (data_copy[off] != (char)0xde)
> +			GOTO_FAIL("Header info corrupted at offset %u", off);
> +	}
> +
> +	/* append sample data after ethernet header */
> +	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
> +	if (data == NULL)
> +		GOTO_FAIL("%s: Cannot append data\n", __func__);
> +	if (rte_pktmbuf_pkt_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
> +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> +	if (rte_pktmbuf_data_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
> +		GOTO_FAIL("%s: Bad data length\n", __func__);
> +	memset(data, 0xcc, MBUF_TEST_DATA_LEN2);
> +
> +	/* read mbuf data after header info */
> +	data_copy = rte_pktmbuf_read(m, hdr_len, MBUF_TEST_DATA_LEN2, NULL);
> +	if (data_copy == NULL)
> +		GOTO_FAIL("%s: Error in reading header data!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
> +		if (data_copy[off] != (char)0xcc)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* partial reading of mbuf data */
> +	data_copy = rte_pktmbuf_read(m, hdr_len + 5, MBUF_TEST_DATA_LEN2 - 5,
> +			NULL);
> +	if (data_copy == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2 - 5)
> +		GOTO_FAIL("%s: Incorrect data length!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_DATA_LEN2 - 5; off++) {
> +		if (data_copy[off] != (char)0xcc)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* read length greater than mbuf data_len */
> +	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1,
> +				NULL) != NULL)
> +		GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n",
> +				__func__);
> +
> +	/* read length greater than mbuf pkt_len */
> +	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1,
> +				NULL) != NULL)
> +		GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n",
> +				__func__);
> +
> +	/* read data of zero len from valid offset */
> +	data_copy = rte_pktmbuf_read(m, hdr_len, 0, NULL);
> +	if (data_copy == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2)
> +		GOTO_FAIL("%s: Corrupted data content!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
> +		if (data_copy[off] != (char)0xcc)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* read data of zero length from zero offset */
> +	data_copy = rte_pktmbuf_read(m, 0, 0, NULL);
> +	if (data_copy == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	/* check if the received address is the beginning of header info */
> +	if (hdr != (const struct ether_hdr *)data_copy)
> +		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
> +
> +	/* read data of negative size length from valid offset */
> +	data_copy = rte_pktmbuf_read(m, hdr_len, -1, NULL);
> +	if (data_copy == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	/* check if the received address is the beginning of data segment */
> +	if (data_copy != data)
> +		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
> +
> +	/* try to read from mbuf with negative size offset */
> +	data_copy = rte_pktmbuf_read(m, -1, 0, NULL);
> +	if (data_copy != NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +
> +	/* try to read from mbuf with negative size offset and len */
> +	data_copy = rte_pktmbuf_read(m, -1, -1, NULL);
> +	if (data_copy != NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);

I'm not sure it makes sense to test negative values, since arguments
are unsigned. If we really want to check that case, I'd prefer to test
UINT32_MAX (which is equivalent).

> +
> +	rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
> +
> +	rte_pktmbuf_free(m);
> +	m = NULL;
> +
> +	return 0;
> +fail:
> +	if (m) {
> +		rte_pktmbuf_free(m);
> +		m = NULL;
> +	}
> +	return -1;
> +}
> +
> +/*
> + * Test to read data from chain of mbufs with data segments.
> + */
> +static int
> +test_rte_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
> +{
> +	struct rte_mbuf *pkt = NULL;
> +	struct rte_mbuf *pkt_seg = NULL;
> +	struct rte_mbuf *pkt_burst[MBUF_TEST_BURST];
> +	char *data = NULL;
> +	const char *read_data = NULL;
> +	char data_buf[EXT_BUF_TEST_DATA_LEN];
> +	uint32_t seg, i, total_pkt_len;
> +	uint16_t nb_pkt, off;
> +	uint32_t nb_segs = MBUF_TEST_DATA_LEN3 / MBUF_TEST_SEG_SIZE;
> +	memset(data_buf, 0, EXT_BUF_TEST_DATA_LEN);
> +
> +	/* allocate pkts in a burst */
> +	for (nb_pkt = 0; nb_pkt < MBUF_TEST_BURST; nb_pkt++) {
> +		/* alloc a mbuf */
> +		pkt = rte_pktmbuf_alloc(pktmbuf_pool);
> +		if (pkt == NULL)
> +			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
> +		if (rte_pktmbuf_pkt_len(pkt) != 0)
> +			GOTO_FAIL("%s: Bad packet length\n", __func__);
> +		rte_mbuf_sanity_check(pkt, 0);
> +
> +		data = rte_pktmbuf_append(pkt, MBUF_TEST_DATA_LEN3);
> +		if (data == NULL)
> +			GOTO_FAIL("%s: Cannot append data\n", __func__);
> +		if (rte_pktmbuf_pkt_len(pkt) != MBUF_TEST_DATA_LEN3)
> +			GOTO_FAIL("%s: Bad packet length\n", __func__);
> +		if (rte_pktmbuf_data_len(pkt) != MBUF_TEST_DATA_LEN3)
> +			GOTO_FAIL("%s: Bad data length\n", __func__);
> +		memset(data, 0xfe, MBUF_TEST_DATA_LEN3);
> +		total_pkt_len = pkt->data_len;
> +		/* allocate mbuf segments for each pkt */
> +		for (seg = 0; seg < nb_segs; seg++) {
> +			pkt_seg = rte_pktmbuf_alloc(pktmbuf_pool);
> +			if (pkt_seg == NULL)
> +				GOTO_FAIL("%s: mbuf allocation failed!\n",
> +						__func__);
> +			if (rte_pktmbuf_pkt_len(pkt_seg) != 0)
> +				GOTO_FAIL("%s: Bad packet length\n", __func__);
> +			rte_mbuf_sanity_check(pkt_seg, 0);
> +			data = rte_pktmbuf_append(pkt_seg,
> +					MBUF_TEST_SEG_SIZE);
> +			if (data == NULL)
> +				GOTO_FAIL("%s: Cannot append data\n", __func__);

If a failure happens in this area, there is a mbuf leak.

> +			if (rte_pktmbuf_pkt_len(pkt_seg) !=
> +					MBUF_TEST_SEG_SIZE)
> +				GOTO_FAIL("%s: Bad packet length\n", __func__);
> +			if (rte_pktmbuf_data_len(pkt_seg) !=
> +					MBUF_TEST_SEG_SIZE)
> +				GOTO_FAIL("%s: Bad data length\n", __func__);
> +			memset(data, (seg + nb_pkt + 0xaa) % 0x0ff,
> +					MBUF_TEST_SEG_SIZE);
> +
> +			/* create chained mbufs */
> +			rte_pktmbuf_chain(pkt, pkt_seg);
> +			total_pkt_len += rte_pktmbuf_data_len(pkt_seg);
> +			pkt_seg = pkt_seg->next;
> +		}
> +		pkt_burst[nb_pkt] = pkt;
> +		if (rte_pktmbuf_pkt_len(pkt) != total_pkt_len)
> +			GOTO_FAIL("%s: Incorrect mbuf packet length!\n",
> +					__func__);
> +	}
> +	/* point to the first chained mbufs burst */
> +	pkt = pkt_burst[0];
> +	if (rte_pktmbuf_is_contiguous(pkt))
> +		GOTO_FAIL("Buffer should be non contiguous!");
> +	/* read data of first mbuf segment */
> +	read_data = rte_pktmbuf_read(pkt, 0, MBUF_TEST_DATA_LEN3, NULL);
> +	if (read_data == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_DATA_LEN3; off++) {
> +		if (read_data[off] != (char)0xfe)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* read data after first mbuf segment */
> +	read_data = rte_pktmbuf_read(pkt, pkt->data_len, MBUF_TEST_SEG_SIZE,
> +			&data_buf);
> +	if (read_data == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_SEG_SIZE; off++) {
> +		if (read_data[off] != (char)0xaa)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* read data with offset into second mbuf segment */
> +	read_data = rte_pktmbuf_read(pkt, pkt->data_len + 5,
> +			MBUF_TEST_SEG_SIZE - 5, NULL);
> +	if (read_data == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_SEG_SIZE - 5; off++) {
> +		if (read_data[off] != (char)0xaa)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* read data with offset into fourth segment of 5th mbuf packet burst */
> +	pkt = pkt_burst[4];
> +	read_data = rte_pktmbuf_read(pkt,
> +			pkt->data_len + (MBUF_TEST_SEG_SIZE * 2) + 3,
> +			MBUF_TEST_SEG_SIZE - 3, NULL);
> +	if (read_data == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_SEG_SIZE - 3; off++) {
> +		/* mbuf array index = 4, seg index = 2; index starts from 0 */
> +		if (read_data[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* read data beyond one mbuf segment length */
> +	read_data = rte_pktmbuf_read(pkt, pkt->data_len + MBUF_TEST_SEG_SIZE,
> +			MBUF_TEST_SEG_SIZE + 2, &data_buf);
> +	if (read_data == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	if (read_data != data_buf)
> +		GOTO_FAIL("%s: Invalid data address!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_SEG_SIZE + 2; off++) {
> +		if (off < MBUF_TEST_SEG_SIZE &&
> +				data_buf[off] != (char)(4 + 1 + 0xaa) % 0x0ff)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +		if (off >= MBUF_TEST_SEG_SIZE &&
> +				data_buf[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}
> +
> +	/* read data of all mbuf segments after the initial data offset */
> +	read_data = rte_pktmbuf_read(pkt, pkt->data_len,
> +			MBUF_TEST_SEG_SIZE * nb_segs, &data_buf);
> +	if (read_data == NULL)
> +		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
> +	if (read_data != data_buf)
> +		GOTO_FAIL("%s: Invalid data address!\n", __func__);
> +	for (off = 0; off < MBUF_TEST_SEG_SIZE * nb_segs; off++) {
> +		if (off < MBUF_TEST_SEG_SIZE &&
> +				data_buf[off] != (char)(4 + 0 + 0xaa) % 0x0ff)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +		if ((off >= MBUF_TEST_SEG_SIZE && off < MBUF_TEST_SEG_SIZE * 2)
> +				&& data_buf[off] !=
> +				(char)(4 + 1 + 0xaa) % 0x0ff)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +		if ((off >= MBUF_TEST_SEG_SIZE * 2 &&
> +					off < MBUF_TEST_SEG_SIZE * 3) &&
> +				data_buf[off] != (char)(4 + 2 + 0xaa) % 0x0ff)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +		if (off >= MBUF_TEST_SEG_SIZE * 4 &&
> +				data_buf[off] != (char)(4 + 3 + 0xaa) % 0x0ff)
> +			GOTO_FAIL("Data corrupted at offset %u", off);
> +	}

I feel it's a bit unfortunate to have a long function that mixes the
creation of a mbuf chain (that could be factorized for other tests) and
the test itself. Also, I don't see the reason to have a burst of packet.
finally, it would be better to have data containing [0x00 0x01 0x02 ...]
instead of a fixed value. It would help to detect shifts. This last
comment applies for every tests.

For instance, something like this:

static struct rte_mbuf *
create_packet(uint16_t *seg_lengths, unsigned int flags)
{
	/* create a mbuf with several segments, filled with data
	 * [0x00 0x01 0x02 ...]
	 * The flags can provide different behaviors. */
}

#define MAX_SEG 16
struct test_case {
	uint16_t seg_lengths[MAX_SEG];
	unsigned int flags;
	uint32_t read_off;
	uint32_t read_len;
};

int my_test(void)
{
	struct rte_mbuf *m;
	struct test_case test_cases[] = {
		{ .seg_lengths = { 1000, 100 }, .flags = 0, .read_off = 0, .read_len = 1000 },
		{ .seg_lengths = { 1000, 100 }, .flags = 0, .read_off = 0, .read_len = 1001 },
		{ .seg_lengths = { 1000, 100 }, .flags = 0, .read_off = 0, .read_len = 1100 },
		{ .seg_lengths = { 1000, 100 }, .flags = 0, .read_off = 100, .read_len = 1000 },
		{ .seg_lengths = { 1000, 100 }, .flags = NO_HEADER, .read_off = 0, .read_len = 1000 },
		{ .seg_lengths = { 100, 100, 100 }, .flags = 0, .read_off = 0, .read_len = 300 },
		{ .seg_lengths = { 100, 100, 100 }, .flags = 0, .read_off = 99, .read_len = 201 },
		{ .seg_lengths = { 1000, 1, 1000 }, .flags = 0, .read_off = 1000, .read_len = 2 },
		/* ... */
	};
	unsigned int i;

	for (i = 0; i < RTE_DIM(test_cases); i++) {
		m = create_packet(test_cases[i].seg_lengths, test_cases[i].flags);
		if (m == NULL) {
			/* ... */
		}

		/* call rte_pktmbuf_read() in buffer
		 * check that buffer[0] == read_off % 256
		 * check that buffer[1] == (read_off + 1) % 256
		 * check that buffer[2] == (read_off + 2) % 256
		 * ...
		 * check that buffer[read_len] == (read_off + read_len) % 256
		 */
	}

	return 0;
}

That's just an example of course, but I feel it can provide a better
coverage of corner cases, and is more easily extensible. Note that what
you did is still better than no test.


> +/* Define a free call back function to be used for external buffer */
> +static void
> +ext_buf_free_callback_fn(void *addr __rte_unused, void *opaque)
> +{
> +	void *ext_buf_addr = opaque;
> +	if (ext_buf_addr == NULL) {
> +		printf("External buffer address is invalid\n");
> +		return;
> +	}
> +	rte_free(ext_buf_addr);
> +	ext_buf_addr = NULL;
> +	printf("External buffer freed via callback\n");
> +}
> +
> +/*
> + * Test to initialize shared data in external buffer before attaching to mbuf
> + *  - Allocate mbuf with no data.
> + *  - Allocate external buffer with size should be large enough to accommodate
> + *     rte_mbuf_ext_shared_info.
> + *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
> + *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
> + *  - Clone another mbuf and attach the same external buffer to it.
> + *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from mbuf.
> + */
> +static int
> +test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
> +{
> +	struct rte_mbuf *m = NULL;
> +	struct rte_mbuf *clone = NULL;
> +	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
> +	rte_iova_t buf_iova;
> +	void *ext_buf_addr = NULL;
> +	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
> +				sizeof(struct rte_mbuf_ext_shared_info);
> +
> +	/* alloc a mbuf */
> +	m = rte_pktmbuf_alloc(pktmbuf_pool);
> +	if (m == NULL)
> +		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
> +	if (rte_pktmbuf_pkt_len(m) != 0)
> +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> +	rte_mbuf_sanity_check(m, 0);
> +
> +	ext_buf_addr = rte_malloc("External buffer", buf_len,
> +			RTE_CACHE_LINE_SIZE);
> +	if (ext_buf_addr == NULL)
> +		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
> +
> +	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr, &buf_len,
> +		ext_buf_free_callback_fn, ext_buf_addr);
> +	if (ret_shinfo == NULL)
> +		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
> +
> +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
> +		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
> +
> +	if (rte_mbuf_refcnt_read(m) != 1)
> +		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
> +
> +	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
> +	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
> +		ret_shinfo);
> +	if (m->ol_flags != EXT_ATTACHED_MBUF)
> +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> +				__func__);
> +
> +	/* allocate one more mbuf */
> +	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> +	if (clone == NULL)
> +		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
> +	if (rte_pktmbuf_pkt_len(clone) != 0)
> +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> +
> +	/* attach the same external buffer to the cloned mbuf */
> +	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> +			ret_shinfo);

Instead of:

  clone = rte_pktmbuf_clone(m, pktmbuf_pool);
  rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
                 ret_shinfo);     /*  << useless */

I'd prefer:
  m2 = rte_pktmbuf_alloc(pktmbuf_pool);
  rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
                 ret_shinfo);

Or just:
  clone = rte_pktmbuf_clone(m, pktmbuf_pool);



> +	if (clone->ol_flags != EXT_ATTACHED_MBUF)
> +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> +				__func__);
> +
> +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
> +		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
> +
> +	/* test to manually update ext_buf_ref_cnt from 2 to 3*/
> +	rte_mbuf_ext_refcnt_update(ret_shinfo, 1);
> +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 3)
> +		GOTO_FAIL("%s: Update ext_buf ref_cnt failed\n", __func__);
> +
> +	/* reset the ext_refcnt before freeing the external buffer */
> +	rte_mbuf_ext_refcnt_set(ret_shinfo, 2);
> +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
> +		GOTO_FAIL("%s: set ext_buf ref_cnt failed\n", __func__);
> +
> +	/* detach the external buffer from mbufs */
> +	rte_pktmbuf_detach_extbuf(m);
> +	/* check if ref cnt is decremented */
> +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
> +		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
> +
> +	rte_pktmbuf_detach_extbuf(clone);
> +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 0)
> +		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
> +
> +	rte_pktmbuf_free(m);
> +	m = NULL;
> +	rte_pktmbuf_free(clone);
> +	clone = NULL;
> +
> +	return 0;
> +
> +fail:
> +	if (m) {
> +		rte_pktmbuf_free(m);
> +		m = NULL;
> +	}
> +	if (clone) {
> +		rte_pktmbuf_free(clone);
> +		clone = NULL;
> +	}
> +	if (ext_buf_addr != NULL) {
> +		rte_free(ext_buf_addr);
> +		ext_buf_addr = NULL;
> +	}
> +	return -1;
> +}
> +
>  static int
>  test_mbuf(void)
>  {
> @@ -1134,7 +1856,8 @@ test_mbuf(void)
>  
>  	/* create pktmbuf pool if it does not exist */
>  	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
> -			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
> +			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
> +			SOCKET_ID_ANY);
>  
>  	if (pktmbuf_pool == NULL) {
>  		printf("cannot allocate mbuf pool\n");
> @@ -1144,7 +1867,8 @@ test_mbuf(void)
>  	/* create a specific pktmbuf pool with a priv_size != 0 and no data
>  	 * room size */
>  	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
> -			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
> +			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
> +			SOCKET_ID_ANY);
>  
>  	if (pktmbuf_pool2 == NULL) {
>  		printf("cannot allocate mbuf pool\n");
> @@ -1226,7 +1950,96 @@ test_mbuf(void)
>  		goto err;
>  	}
>  
> +	/* test to validate tx offload flags */
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_IP_CKSUM_IPV6_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_IP_TYPE_NOT_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_IP_TYPE_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_NULL_TSO_SEGSZ) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_TSO_IP_CKSUM_NOT_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_TSO_IPV6_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_TSO_IP_CKSUM_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_OUTER_IPV4_NOT_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_OUTER_IPV4_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	if (test_mbuf_validate_tx_offload(pktmbuf_pool,
> +				MBUF_TEST_OL_MASK_NOT_SET) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +
> +	/* test for allocating a bulk of mbufs with various sizes */
> +	if (test_rte_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
> +		printf("test_rte_pktmbuf_alloc_bulk() failed\n");
> +		goto err;
> +	}
> +
> +	/* test for allocating a bulk of mbufs with various sizes */
> +	if (test_neg_rte_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
> +		printf("test_neg_rte_pktmbuf_alloc_bulk() failed\n");
> +		goto err;
> +	}
> +
> +	/* test to read mbuf packet */
> +	if (test_rte_pktmbuf_read(pktmbuf_pool) < 0) {
> +		printf("test_rte_pktmbuf_read() failed\n");
> +		goto err;
> +	}
> +
> +	/* test to read mbuf packet from offset */
> +	if (test_rte_pktmbuf_read_from_offset(pktmbuf_pool) < 0) {
> +		printf("test_rte_pktmbuf_read_from_offset() failed\n");
> +		goto err;
> +	}
> +
> +	/* test to read data from chain of mbufs with data segments */
> +	if (test_rte_pktmbuf_read_from_chain(pktmbuf_pool) < 0) {
> +		printf("test_rte_pktmbuf_read_from_chain() failed\n");
> +		goto err;
> +	}
> +
> +	/* test to initialize shared info. at the end of external buffer */
> +	if (test_pktmbuf_ext_shinfo_init_helper(pktmbuf_pool) < 0) {
> +		printf("test_pktmbuf_ext_shinfo_init_helper() failed\n");
> +		goto err;
> +	}
> +
>  	ret = 0;
> +
>  err:
>  	rte_mempool_free(pktmbuf_pool);
>  	rte_mempool_free(pktmbuf_pool2);
> @@ -1234,3 +2047,4 @@ test_mbuf(void)
>  }
>  
>  REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);
> +#undef GOTO_FAIL
> -- 
> 2.17.2
> 

Thanks for this work!

Olivier

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs
  2019-06-03  8:39 ` Olivier Matz
@ 2019-07-22 13:32   ` Govindarajan, LavanyaX
  2019-08-13 10:26     ` Govindarajan, LavanyaX
  0 siblings, 1 reply; 22+ messages in thread
From: Govindarajan, LavanyaX @ 2019-07-22 13:32 UTC (permalink / raw)
  To: Olivier Matz; +Cc: dev, Pattan, Reshma, Richardson, Bruce

Hi

> -----Original Message-----
> From: Olivier Matz [mailto:olivier.matz@6wind.com]
> Sent: Monday, June 3, 2019 2:10 PM
> To: Govindarajan, LavanyaX <lavanyax.govindarajan@intel.com>
> Cc: dev@dpdk.org; Pattan, Reshma <reshma.pattan@intel.com>; Richardson,
> Bruce <bruce.richardson@intel.com>
> Subject: Re: [PATCH] app/test: add unit test cases for mbuf library APIs
> 
> Hi Lavanya,
> 
> Please find some comments inline.
> 
> On Mon, Apr 15, 2019 at 01:40:15PM +0100, Lavanya Govindarajan wrote:
> > added new unit test cases for
> > rte_validate_tx_offload,
> > rte_pktmbuf_alloc_bulk,
> > rte_pktmbuf_read,
> > rte_pktmbuf_ext_shinfo_init_helper,
> > rte_pktmbuf_attach_extbuf,
> > rte_mbuf_ext_refcnt_read,
> > rte_mbuf_ext_refcnt_update,
> > rte_mbuf_ext_refcnt_set,
> > rte_pktmbuf_detach_extbuf
> >
> > Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
> > ---
> >  app/test/test_mbuf.c | 820
> > ++++++++++++++++++++++++++++++++++++++++++-
> >  1 file changed, 817 insertions(+), 3 deletions(-)
> >
> > diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c index
> > 030385ec5..74259b313 100644
> > --- a/app/test/test_mbuf.c
> > +++ b/app/test/test_mbuf.c
>

<snip>
 
> > +/*
> > + * Test for allocating a bulk of mbufs
> > + * define an array with positive sizes for mbufs allocations.
> > + */
> > +static int
> > +test_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool) {
> > +	int ret = 0;
> > +	unsigned int idx, loop;
> > +	unsigned int alloc_counts[] = {
> > +		0,
> > +		MEMPOOL_CACHE_SIZE - 1,
> > +		MEMPOOL_CACHE_SIZE,
> > +		MEMPOOL_CACHE_SIZE + 1,
> > +		MEMPOOL_CACHE_SIZE * 1.5,
> > +		MEMPOOL_CACHE_SIZE * 2,
> > +		MEMPOOL_CACHE_SIZE * 2 - 1,
> > +		MEMPOOL_CACHE_SIZE * 2 + 1,
> > +		89,                         /* random number */
> > +		MEMPOOL_CACHE_SIZE          /* repeat cache size */
> > +	};
> 
> instead of testing these particular values, why not testing every values between
> 0 and NB_MBUF ?

Testing every value from 0, 1, 2.. NB_MBUF(128 here)  dilutes the purpose of testing bulk allocation of mbufs from the same pool.
Boundary conditions and some random values are targeted which will cover major cases.

The behavior is different for different set of values
based on the availability of free mbufs in the cache or from the ring. 

<snip>

> > +/*
> > + * Test to initialize shared data in external buffer before attaching
> > +to mbuf
> > + *  - Allocate mbuf with no data.
> > + *  - Allocate external buffer with size should be large enough to
> accommodate
> > + *     rte_mbuf_ext_shared_info.
> > + *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
> > + *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
> > + *  - Clone another mbuf and attach the same external buffer to it.
> > + *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from
> mbuf.
> > + */
> > +static int
> > +test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
> > +{
> > +	struct rte_mbuf *m = NULL;
> > +	struct rte_mbuf *clone = NULL;
> > +	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
> > +	rte_iova_t buf_iova;
> > +	void *ext_buf_addr = NULL;
> > +	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
> > +				sizeof(struct rte_mbuf_ext_shared_info);
> > +
> > +	/* alloc a mbuf */
> > +	m = rte_pktmbuf_alloc(pktmbuf_pool);
> > +	if (m == NULL)
> > +		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
> > +	if (rte_pktmbuf_pkt_len(m) != 0)
> > +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> > +	rte_mbuf_sanity_check(m, 0);
> > +
> > +	ext_buf_addr = rte_malloc("External buffer", buf_len,
> > +			RTE_CACHE_LINE_SIZE);
> > +	if (ext_buf_addr == NULL)
> > +		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
> > +
> > +	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr,
> &buf_len,
> > +		ext_buf_free_callback_fn, ext_buf_addr);
> > +	if (ret_shinfo == NULL)
> > +		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
> > +
> > +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
> > +		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
> > +
> > +	if (rte_mbuf_refcnt_read(m) != 1)
> > +		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
> > +
> > +	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
> > +	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
> > +		ret_shinfo);
> > +	if (m->ol_flags != EXT_ATTACHED_MBUF)
> > +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> > +				__func__);
> > +
> > +	/* allocate one more mbuf */
> > +	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> > +	if (clone == NULL)
> > +		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
> > +	if (rte_pktmbuf_pkt_len(clone) != 0)
> > +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> > +
> > +	/* attach the same external buffer to the cloned mbuf */
> > +	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> > +			ret_shinfo);
> 
> Instead of:
> 
>   clone = rte_pktmbuf_clone(m, pktmbuf_pool);
>   rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
>                  ret_shinfo);     /*  << useless */
> 
The purpose of the above lines is to test if external buffer can be attached to the
cloned mbuf or not.

> I'd prefer:
>   m2 = rte_pktmbuf_alloc(pktmbuf_pool);
>   rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
>                  ret_shinfo);
Do you mean, m2 in the above line?

> 
> Or just:
>   clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> 
Can you please provide more clarity in the above suggestion.

> 
> 
> > +	if (clone->ol_flags != EXT_ATTACHED_MBUF)
> > +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> > +				__func__);
> > +

<snip>

Regards
Lavanya G

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v2 0/2] add unit test cases for mbuf library
  2019-04-15 12:40 [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
                   ` (2 preceding siblings ...)
  2019-06-03  8:39 ` Olivier Matz
@ 2019-07-22 13:42 ` Lavanya Govindarajan
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
  5 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-07-22 13:42 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	pallantlax.poornima, Lavanya Govindarajan

This patchset contains unit testcases added to increase the
functional and decision coverage for the library functions 
defined in rte_mbuf.h and rte_mbuf.c

1/2: unit test cases added for rte_mbuf.h
2/2: unit test cases added for rte_mbuf.c

Patch 2/2 depends on 1/2

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
---
v2: Addressed v1's comments
Removed rte prefix from the test function names.
Fixed comments given for the below test functions
test_mbuf_validate_tx_offload
test_neg_pktmbuf_alloc_bulk
test_pktmbuf_read_from_offset
test_pktmbuf_read_from_chain
---
Lavanya Govindarajan (1):
  app/test: add unit test cases for mbuf library APIs

Pallantla Poornima (1):
  app/test: add unit test cases to mbuf

 app/test/test_mbuf.c | 1019 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 1016 insertions(+), 3 deletions(-)

-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v2 1/2] app/test: add unit test cases for mbuf library APIs
  2019-04-15 12:40 [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
                   ` (3 preceding siblings ...)
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 0/2] add unit test cases for mbuf library Lavanya Govindarajan
@ 2019-07-22 13:42 ` Lavanya Govindarajan
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
  5 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-07-22 13:42 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	pallantlax.poornima, Lavanya Govindarajan

Added new unit test cases to cover the below
functions defined in rte_mbuf.h
rte_validate_tx_offload,
rte_pktmbuf_alloc_bulk,
rte_pktmbuf_read,
rte_pktmbuf_ext_shinfo_init_helper,
rte_pktmbuf_attach_extbuf,
rte_mbuf_ext_refcnt_read,
rte_mbuf_ext_refcnt_update,
rte_mbuf_ext_refcnt_set,
rte_pktmbuf_detach_extbuf

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
---
 app/test/test_mbuf.c | 759 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 756 insertions(+), 3 deletions(-)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 2a97afe20..623453d57 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -28,16 +28,28 @@
 #include <rte_random.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
 
 #include "test.h"
 
+#define MEMPOOL_CACHE_SIZE      32
 #define MBUF_DATA_SIZE          2048
 #define NB_MBUF                 128
 #define MBUF_TEST_DATA_LEN      1464
 #define MBUF_TEST_DATA_LEN2     50
+#define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
+#define MBUF_TEST_SEG_SIZE      64
+#define MBUF_TEST_BURST         8
+#define EXT_BUF_TEST_DATA_LEN   1024
+#define MBUF_MAX_SEG            16
+#define MBUF_NO_HEADER		0
+#define MBUF_HEADER		1
+#define MBUF_NEG_TEST_READ	2
 
 /* size of private data for mbuf in pktmbuf_pool2 */
 #define MBUF2_PRIV_SIZE         128
@@ -502,7 +514,6 @@ test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,
 		rte_pktmbuf_free(clone2);
 	return -1;
 }
-#undef GOTO_FAIL
 
 /*
  * test allocation and free of mbufs
@@ -1121,6 +1132,601 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+static int
+test_mbuf_validate_tx_offload(const char *test_name,
+		struct rte_mempool *pktmbuf_pool,
+		uint64_t ol_flags,
+		uint16_t segsize,
+		int expected_retval)
+{
+	struct rte_mbuf *m = NULL;
+	int ret = 0;
+	/* alloc a mbuf and do sanity check */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+	m->ol_flags = ol_flags;
+	m->tso_segsz = segsize;
+	ret = rte_validate_tx_offload(m);
+	if (ret != expected_retval)
+		GOTO_FAIL("%s(%s): expected ret val: %d; received: %d\n",
+				__func__, test_name, expected_retval, ret);
+	rte_pktmbuf_free(m);
+	m = NULL;
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test for allocating a bulk of mbufs
+ * define an array with positive sizes for mbufs allocations.
+ */
+static int
+test_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int ret = 0;
+	unsigned int idx, loop;
+	unsigned int alloc_counts[] = {
+		0,
+		MEMPOOL_CACHE_SIZE - 1,
+		MEMPOOL_CACHE_SIZE,
+		MEMPOOL_CACHE_SIZE + 1,
+		MEMPOOL_CACHE_SIZE * 1.5,
+		MEMPOOL_CACHE_SIZE * 2,
+		MEMPOOL_CACHE_SIZE * 2 - 1,
+		MEMPOOL_CACHE_SIZE * 2 + 1,
+		89,                         /* random number */
+		MEMPOOL_CACHE_SIZE          /* repeat cache size */
+	};
+
+	/* allocate a large array of mbuf pointers */
+	struct rte_mbuf *mbufs[NB_MBUF] = { 0 };
+	for (idx = 0; idx < RTE_DIM(alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				alloc_counts[idx]);
+		if (ret == 0) {
+			for (loop = 0; loop < alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+		} else if (ret != 0) {
+			printf("%s: Bulk alloc failed count(%u); ret val(%d)\n",
+					__func__, alloc_counts[idx], ret);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Negative testing for allocating a bulk of mbufs
+ */
+static int
+test_neg_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int loop, ret = 0;
+	unsigned int idx;
+	int neg_alloc_counts[] = {
+		MEMPOOL_CACHE_SIZE - NB_MBUF,
+		NB_MBUF + 1,
+		NB_MBUF * 8,
+		UINT_MAX
+	};
+	struct rte_mbuf *mbufs[NB_MBUF * 8] = { 0 };
+
+	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				neg_alloc_counts[idx]);
+		if (ret == 0) {
+			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
+					__func__, neg_alloc_counts[idx], ret);
+			for (loop = 0; loop < neg_alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Test to read mbuf packet using rte_pktmbuf_read
+ */
+static int
+test_pktmbuf_read(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	int off;
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	memset(data, 0xfe, MBUF_TEST_DATA_LEN2);
+
+	/* read the data from mbuf */
+	data_copy = rte_pktmbuf_read(m, 0, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read mbuf packet data from offset
+ */
+static int
+test_pktmbuf_read_from_offset(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct ether_hdr *hdr = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	unsigned int off;
+	unsigned int hdr_len = sizeof(struct rte_ether_hdr);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	/* prepend an ethernet header */
+	hdr = (struct ether_hdr *)rte_pktmbuf_prepend(m, hdr_len);
+	if (hdr == NULL)
+		GOTO_FAIL("%s: Cannot prepend header\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad pkt length", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad data length", __func__);
+	memset(hdr, 0xde, hdr_len);
+
+	/* read mbuf header info from 0 offset */
+	data_copy = rte_pktmbuf_read(m, 0, hdr_len, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header!\n", __func__);
+	for (off = 0; off < hdr_len; off++) {
+		if (data_copy[off] != (char)0xde)
+			GOTO_FAIL("Header info corrupted at offset %u", off);
+	}
+
+	/* append sample data after ethernet header */
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad data length\n", __func__);
+	memset(data, 0xcc, MBUF_TEST_DATA_LEN2);
+
+	/* read mbuf data after header info */
+	data_copy = rte_pktmbuf_read(m, hdr_len, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* partial reading of mbuf data */
+	data_copy = rte_pktmbuf_read(m, hdr_len + 5, MBUF_TEST_DATA_LEN2 - 5,
+			NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2 - 5)
+		GOTO_FAIL("%s: Incorrect data length!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2 - 5; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read length greater than mbuf data_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n",
+				__func__);
+
+	/* read length greater than mbuf pkt_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n",
+				__func__);
+
+	/* read data of zero len from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Corrupted data content!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of zero length from zero offset */
+	data_copy = rte_pktmbuf_read(m, 0, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of header info */
+	if (hdr != (const struct ether_hdr *)data_copy)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* read data of max length from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, UINT_MAX, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of data segment */
+	if (data_copy != data)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* try to read from mbuf with max size offset */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, 0, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	/* try to read from mbuf with max size offset and len */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, UINT_MAX, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+struct test_case {
+	unsigned int seg_count;
+	unsigned int flags;
+	uint32_t read_off;
+	uint32_t read_len;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+};
+
+/* create a mbuf with different sized segments
+ *  and fill with data [0x00 0x01 0x02 ...]
+ */
+static struct rte_mbuf *
+create_packet(struct rte_mempool *pktmbuf_pool,
+		struct test_case *test_data)
+		//unsigned int *seg_lengths_ptr, unsigned int flags)
+{
+	uint16_t i, ret, seg, seg_len = 0;
+	uint32_t last_index = 0;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+	unsigned int hdr_len;
+	struct rte_mbuf *pkt = NULL;
+	struct rte_mbuf	*pkt_seg = NULL;
+	char *hdr = NULL;
+	char *data = NULL;
+	memcpy(seg_lengths, test_data->seg_lengths,
+			sizeof(unsigned int)*test_data->seg_count);
+	for (seg = 0; seg < test_data->seg_count; seg++) {
+		hdr_len = 0;
+		seg_len =  seg_lengths[seg];
+		pkt_seg = rte_pktmbuf_alloc(pktmbuf_pool);
+		if (pkt_seg == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != 0)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		rte_mbuf_sanity_check(pkt_seg, 0);
+		/* Add header only for the first segment */
+		if (test_data->flags == MBUF_HEADER && seg == 0) {
+			hdr_len = sizeof(struct rte_ether_hdr);
+			/* prepend a header and fill with dummy data */
+			hdr = (char *)rte_pktmbuf_prepend(pkt_seg, hdr_len);
+			if (hdr == NULL)
+				GOTO_FAIL("%s: Cannot prepend header\n",
+						__func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad pkt length", __func__);
+			if (rte_pktmbuf_data_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad data length", __func__);
+			for (i = 0; i < hdr_len; i++)
+				hdr[i] = (last_index + i) % 0xffff;
+			last_index += hdr_len;
+		}
+		/* skip appending segment with 0 length */
+		if (seg_len == 0)
+			continue;
+		data = rte_pktmbuf_append(pkt_seg, seg_len);
+		if (data == NULL)
+			GOTO_FAIL("%s: Cannot append data segment\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad packet segment length: %d\n",
+					__func__, rte_pktmbuf_pkt_len(pkt_seg));
+		if (rte_pktmbuf_data_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad data length\n", __func__);
+		for (i = 0; i < seg_len; i++)
+			data[i] = (last_index + i) % 0xffff;
+		/* to fill continuous data from one seg to another */
+		last_index += i;
+		/* create chained mbufs */
+		if (seg == 0)
+			pkt = pkt_seg;
+		else {
+			ret = rte_pktmbuf_chain(pkt, pkt_seg);
+			if (ret != 0)
+				GOTO_FAIL("%s:FAIL: Chained mbuf creation %d\n",
+						__func__, ret);
+		}
+
+		pkt_seg = pkt_seg->next;
+	}
+	return pkt;
+fail:
+	if (pkt != NULL) {
+		rte_pktmbuf_free(pkt);
+		pkt = NULL;
+	}
+	if (pkt_seg != NULL) {
+		rte_pktmbuf_free(pkt_seg);
+		pkt_seg = NULL;
+	}
+	return NULL;
+}
+
+static int
+test_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m;
+	/* add testcases with different segments len, offset and read len */
+	struct test_case test_cases[] = {
+		{ .seg_lengths = { 100, 100, 100 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0, .read_len = 300 },
+		{ .seg_lengths = { 100, 125, 150 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 99, .read_len = 201 },
+		{ .seg_lengths = { 100, 100 },
+	    .seg_count = 2,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0,
+	    .read_len = 100 },
+		{ .seg_lengths = { 100, 200 },
+	    .seg_count = 2,
+	    .flags = MBUF_HEADER,
+	    .read_off = sizeof(struct rte_ether_hdr),
+	    .read_len = 150 },
+		{ .seg_lengths = { 1000, 100 },
+	    .seg_count = 2,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0,
+	    .read_len = 1000 },
+		{ .seg_lengths = { 1024, 0, 100 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 100,
+	    .read_len = 1001 },
+		{ .seg_lengths = { 1000, 1, 1000 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 1000,
+	    .read_len = 2 },
+		{ .seg_lengths = { MBUF_TEST_DATA_LEN, MBUF_TEST_DATA_LEN2,
+			     MBUF_TEST_DATA_LEN3, 800, 10 },
+		.seg_count = 5,
+		.flags = MBUF_NEG_TEST_READ,
+		.read_off = 1000,
+			.read_len = MBUF_DATA_SIZE },
+	};
+
+	uint32_t i, pos;
+	const char *data_copy = NULL;
+	char data_buf[MBUF_DATA_SIZE];
+	memset(data_buf, 0, MBUF_DATA_SIZE);
+
+	for (i = 0; i < RTE_DIM(test_cases); i++) {
+		m = create_packet(pktmbuf_pool, &test_cases[i]);
+		if (m == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+		data_copy = rte_pktmbuf_read(m, test_cases[i].read_off,
+				test_cases[i].read_len, data_buf);
+		if (test_cases[i].flags == MBUF_NEG_TEST_READ) {
+			if (data_copy != NULL)
+				GOTO_FAIL("%s: mbuf data read should fail!\n",
+						__func__);
+			else {
+				rte_pktmbuf_free(m);
+				m = NULL;
+				continue;
+			}
+		}
+		if (data_copy == NULL)
+			GOTO_FAIL("%s: Error in reading packet data!\n",
+					__func__);
+		for (pos = 0; pos < test_cases[i].read_len; pos++) {
+			if (data_copy[pos] !=
+					(char)((test_cases[i].read_off + pos)
+						% 0xffff))
+				GOTO_FAIL("Data corrupted at offset %u is %2X",
+						pos, data_copy[pos]);
+		}
+		rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return 0;
+
+fail:
+	if (m != NULL) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/* Define a free call back function to be used for external buffer */
+static void
+ext_buf_free_callback_fn(void *addr __rte_unused, void *opaque)
+{
+	void *ext_buf_addr = opaque;
+	if (ext_buf_addr == NULL) {
+		printf("External buffer address is invalid\n");
+		return;
+	}
+	rte_free(ext_buf_addr);
+	ext_buf_addr = NULL;
+	printf("External buffer freed via callback\n");
+}
+
+/*
+ * Test to initialize shared data in external buffer before attaching to mbuf
+ *  - Allocate mbuf with no data.
+ *  - Allocate external buffer with size should be large enough to accommodate
+ *     rte_mbuf_ext_shared_info.
+ *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
+ *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
+ *  - Clone another mbuf and attach the same external buffer to it.
+ *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from mbuf.
+ */
+static int
+test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct rte_mbuf *clone = NULL;
+	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
+	rte_iova_t buf_iova;
+	void *ext_buf_addr = NULL;
+	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
+				sizeof(struct rte_mbuf_ext_shared_info);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	ext_buf_addr = rte_malloc("External buffer", buf_len,
+			RTE_CACHE_LINE_SIZE);
+	if (ext_buf_addr == NULL)
+		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
+
+	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr, &buf_len,
+		ext_buf_free_callback_fn, ext_buf_addr);
+	if (ret_shinfo == NULL)
+		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
+
+	if (rte_mbuf_refcnt_read(m) != 1)
+		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
+
+	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
+	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
+		ret_shinfo);
+	if (m->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	/* allocate one more mbuf */
+	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
+	if (clone == NULL)
+		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(clone) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+
+	/* attach the same external buffer to the cloned mbuf */
+	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
+			ret_shinfo);
+	if (clone->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	/* test to manually update ext_buf_ref_cnt from 2 to 3*/
+	rte_mbuf_ext_refcnt_update(ret_shinfo, 1);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 3)
+		GOTO_FAIL("%s: Update ext_buf ref_cnt failed\n", __func__);
+
+	/* reset the ext_refcnt before freeing the external buffer */
+	rte_mbuf_ext_refcnt_set(ret_shinfo, 2);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: set ext_buf ref_cnt failed\n", __func__);
+
+	/* detach the external buffer from mbufs */
+	rte_pktmbuf_detach_extbuf(m);
+	/* check if ref cnt is decremented */
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_detach_extbuf(clone);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 0)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	rte_pktmbuf_free(clone);
+	clone = NULL;
+
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	if (clone) {
+		rte_pktmbuf_free(clone);
+		clone = NULL;
+	}
+	if (ext_buf_addr != NULL) {
+		rte_free(ext_buf_addr);
+		ext_buf_addr = NULL;
+	}
+	return -1;
+}
+
 static int
 test_mbuf(void)
 {
@@ -1133,7 +1739,8 @@ test_mbuf(void)
 
 	/* create pktmbuf pool if it does not exist */
 	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
-			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1143,7 +1750,8 @@ test_mbuf(void)
 	/* create a specific pktmbuf pool with a priv_size != 0 and no data
 	 * room size */
 	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
-			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool2 == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1225,6 +1833,150 @@ test_mbuf(void)
 		goto err;
 	}
 
+	/* test to validate tx offload flags */
+	uint64_t ol_flags = 0;
+	/* test to validate if IP checksum is counted only for IPV4 packet */
+	/* set both IP checksum and IPV6 flags */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_CKSUM_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* resetting ol_flags for next testcase */
+	ol_flags = 0;
+
+	/* test to validate if IP type is set when required */
+	ol_flags |= PKT_TX_L4_MASK;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test if IP type is set when TCP SEG is on */
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm IP type (IPV4/IPV6) is set */
+	ol_flags = PKT_TX_L4_MASK;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_SET",
+				pktmbuf_pool,
+				ol_flags, 0, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to check TSO segment size is non-zero */
+	ol_flags |= PKT_TX_IPV4;
+	ol_flags |= PKT_TX_TCP_SEG;
+	/* set 0 tso segment size */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_NULL_TSO_SEGSZ",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* retain IPV4 and PKT_TX_TCP_SEG mask */
+	/* set valid tso segment size but IP CKSUM not set */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test to validate if IP checksum is set for TSO capability */
+	/* retain IPV4, TCP_SEG, tso_seg size */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test to confirm TSO for IPV6 type */
+	ol_flags = 0;
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test if outer IP checksum set for non outer IPv4 packet */
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm outer IP checksum is set for outer IPV4 packet */
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	ol_flags |= PKT_TX_OUTER_IPV4;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm if packets with no TX_OFFLOAD_MASK are skipped */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OL_MASK_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_neg_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_neg_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet */
+	if (test_pktmbuf_read(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet from offset */
+	if (test_pktmbuf_read_from_offset(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_offset() failed\n");
+		goto err;
+	}
+
+	/* test to read data from chain of mbufs with data segments */
+	if (test_pktmbuf_read_from_chain(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_chain() failed\n");
+		goto err;
+	}
+
+	/* test to initialize shared info. at the end of external buffer */
+	if (test_pktmbuf_ext_shinfo_init_helper(pktmbuf_pool) < 0) {
+		printf("test_pktmbuf_ext_shinfo_init_helper() failed\n");
+		goto err;
+	}
+
 	ret = 0;
 err:
 	rte_mempool_free(pktmbuf_pool);
@@ -1233,3 +1985,4 @@ test_mbuf(void)
 }
 
 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);
+#undef GOTO_FAIL
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v2 2/2] app/test: add unit test cases to mbuf
  2019-04-15 12:40 [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
                   ` (4 preceding siblings ...)
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
@ 2019-07-22 13:42 ` Lavanya Govindarajan
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 0/2] add unit test cases for mbuf library Lavanya Govindarajan
                     ` (2 more replies)
  5 siblings, 3 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-07-22 13:42 UTC (permalink / raw)
  To: dev; +Cc: reshma.pattan, olivier.matz, bruce.richardson, pallantlax.poornima

From: Pallantla Poornima <pallantlax.poornima@intel.com>

Added UT for the below four functions in test_mbuf.c
rte_get_rx_ol_flag_list
rte_get_tx_ol_flag_list
rte_get_rx_ol_flag_name
rte_get_tx_ol_flag_name

Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
---
 app/test/test_mbuf.c | 260 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 260 insertions(+)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 623453d57..1b3879c96 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -42,6 +42,7 @@
 #define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
+#define MBUF_TEST_LEN           250
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
 #define MBUF_TEST_SEG_SIZE      64
 #define MBUF_TEST_BURST         8
@@ -1132,6 +1133,245 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+
+static int
+test_get_rx_ol_flag_list(void)
+{
+	int ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_rx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received =%d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_L4_CKSUM_MASK, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0)
+		GOTO_FAIL("%s buffer should be empty, expected: 0, received =%d\n",
+				__func__, buflen);
+
+	/* Test case to check with reduced buffer len */
+	int32_t len = sizeof(buf) - MBUF_TEST_LEN;
+	ret = rte_get_rx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received =%d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_rx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received =%d\n", __func__,
+				"non-zero, buffer should not be empty", buflen);
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_SEC_OFFLOAD, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received =%d\n", __func__,
+				"non-zero, buffer should not be empty", buflen);
+
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_list(void)
+{
+	int ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_tx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received =%d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_IP_CKSUM, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0) {
+		GOTO_FAIL("%s buffer should be empty, expected: 0, received =%d\n",
+				__func__, buflen);
+	}
+
+	/* Test case to check with reduced buffer len */
+	int32_t len = sizeof(buf) - MBUF_TEST_LEN;
+	ret = rte_get_tx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received =%d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_tx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received =%d\n", __func__,
+				"non-zero, buffer should not be empty", buflen);
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_UDP_CKSUM, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received =%d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received =%d\n", __func__,
+				"non-zero, buffer should not be empty", buflen);
+
+	return 0;
+fail:
+	return -1;
+
+}
+
+struct flag_name {
+	uint64_t flag;
+	const char *name;
+};
+
+static int
+test_get_rx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name rx_flags[] = {
+		{ PKT_RX_VLAN, "PKT_RX_VLAN" },
+		{ PKT_RX_RSS_HASH, "PKT_RX_RSS_HASH" },
+		{ PKT_RX_FDIR, "PKT_RX_FDIR"},
+		{ PKT_RX_L4_CKSUM_BAD, "PKT_RX_L4_CKSUM_BAD"},
+		{ PKT_RX_L4_CKSUM_GOOD, "PKT_RX_L4_CKSUM_GOOD"},
+		{ PKT_RX_L4_CKSUM_NONE, "PKT_RX_L4_CKSUM_NONE"},
+		{ PKT_RX_IP_CKSUM_BAD, "PKT_RX_IP_CKSUM_BAD"},
+		{ PKT_RX_IP_CKSUM_GOOD, "PKT_RX_IP_CKSUM_GOOD"},
+		{ PKT_RX_IP_CKSUM_NONE, "PKT_RX_IP_CKSUM_NONE"},
+		{ PKT_RX_EIP_CKSUM_BAD, "PKT_RX_EIP_CKSUM_BAD" },
+		{ PKT_RX_VLAN_STRIPPED, "PKT_RX_VLAN_STRIPPED" },
+		{ PKT_RX_IEEE1588_PTP, "PKT_RX_IEEE1588_PTP"},
+		{ PKT_RX_IEEE1588_TMST, "PKT_RX_IEEE1588_TMST"},
+		{ PKT_RX_FDIR_ID, "PKT_RX_FDIR_ID"},
+		{ PKT_RX_FDIR_FLX, "PKT_RX_FDIR_FLX"},
+		{ PKT_RX_QINQ_STRIPPED, "PKT_RX_QINQ_STRIPPED" },
+		{ PKT_RX_LRO, "PKT_RX_LRO" },
+		{ PKT_RX_TIMESTAMP, "PKT_RX_TIMESTAMP"},
+		{ PKT_RX_SEC_OFFLOAD, "PKT_RX_SEC_OFFLOAD" },
+		{ PKT_RX_SEC_OFFLOAD_FAILED, "PKT_RX_SEC_OFFLOAD_FAILED" },
+		{ PKT_RX_OUTER_L4_CKSUM_BAD, "PKT_RX_OUTER_L4_CKSUM_BAD" },
+		{ PKT_RX_OUTER_L4_CKSUM_GOOD, "PKT_RX_OUTER_L4_CKSUM_GOOD"},
+		{ PKT_RX_OUTER_L4_CKSUM_INVALID,
+			"PKT_RX_OUTER_L4_CKSUM_INVALID" },
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(rx_flags); i++) {
+		flag_str = rte_get_rx_ol_flag_name(rx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s:  Expected flag name= %s; received = %s\n",
+				__func__, rx_flags[i].name, flag_str);
+		if (strcmp(flag_str, rx_flags[i].name) != 0)
+			GOTO_FAIL("%s Expected flag name = %s; received = %s\n",
+				__func__, rx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_rx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s Expected : NULL; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name tx_flags[] = {
+
+	{ PKT_TX_VLAN, "PKT_TX_VLAN" },
+	{ PKT_TX_IP_CKSUM, "PKT_TX_IP_CKSUM" },
+	{ PKT_TX_TCP_CKSUM, "PKT_TX_TCP_CKSUM" },
+	{ PKT_TX_SCTP_CKSUM, "PKT_TX_SCTP_CKSUM" },
+	{ PKT_TX_UDP_CKSUM, "PKT_TX_UDP_CKSUM" },
+	{ PKT_TX_IEEE1588_TMST, "PKT_TX_IEEE1588_TMST" },
+	{ PKT_TX_TCP_SEG, "PKT_TX_TCP_SEG" },
+	{ PKT_TX_IPV4, "PKT_TX_IPV4" },
+	{ PKT_TX_IPV6, "PKT_TX_IPV6" },
+	{ PKT_TX_OUTER_IP_CKSUM, "PKT_TX_OUTER_IP_CKSUM" },
+	{ PKT_TX_OUTER_IPV4, "PKT_TX_OUTER_IPV4" },
+	{ PKT_TX_OUTER_IPV6, "PKT_TX_OUTER_IPV6" },
+	{ PKT_TX_TUNNEL_VXLAN, "PKT_TX_TUNNEL_VXLAN" },
+	{ PKT_TX_TUNNEL_GRE,  "PKT_TX_TUNNEL_GRE" },
+	{ PKT_TX_TUNNEL_IPIP, "PKT_TX_TUNNEL_IPIP" },
+	{ PKT_TX_TUNNEL_GENEVE,  "PKT_TX_TUNNEL_GENEVE" },
+	{ PKT_TX_TUNNEL_MPLSINUDP, "PKT_TX_TUNNEL_MPLSINUDP" },
+	{ PKT_TX_TUNNEL_VXLAN_GPE, "PKT_TX_TUNNEL_VXLAN_GPE" },
+	{ PKT_TX_TUNNEL_IP, "PKT_TX_TUNNEL_IP" },
+	{ PKT_TX_TUNNEL_UDP, "PKT_TX_TUNNEL_UDP" },
+	{ PKT_TX_QINQ, "PKT_TX_QINQ" },
+	{ PKT_TX_MACSEC, "PKT_TX_MACSEC" },
+	{ PKT_TX_SEC_OFFLOAD, "PKT_TX_SEC_OFFLOAD" },
+	{ PKT_TX_UDP_SEG, "PKT_TX_UDP_SEG" },
+	{ PKT_TX_OUTER_UDP_CKSUM, "PKT_TX_OUTER_UDP_CKSUM" },
+	{ PKT_TX_METADATA, "PKT_TX_METADATA" },
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(tx_flags); i++) {
+		flag_str = rte_get_tx_ol_flag_name(tx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s:  Expected flag name= %s; received = %s\n",
+				__func__, tx_flags[i].name, flag_str);
+		if (strcmp(flag_str, tx_flags[i].name) != 0)
+			GOTO_FAIL("%s Expected flag name = %s; received = %s\n",
+				__func__, tx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_tx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s Expected : NULL; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+
+}
+
 static int
 test_mbuf_validate_tx_offload(const char *test_name,
 		struct rte_mempool *pktmbuf_pool,
@@ -1833,6 +2073,26 @@ test_mbuf(void)
 		goto err;
 	}
 
+	if (test_get_rx_ol_flag_list() < 0) {
+		printf("test_rte_get_rx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_list() < 0) {
+		printf("test_rte_get_tx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_rx_ol_flag_name() < 0) {
+		printf("test_rte_get_rx_ol_flag_name() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_name() < 0) {
+		printf("test_rte_get_tx_ol_flag_name() failed\n");
+		goto err;
+	}
+
 	/* test to validate tx offload flags */
 	uint64_t ol_flags = 0;
 	/* test to validate if IP checksum is counted only for IPV4 packet */
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v3 0/2] add unit test cases for mbuf library
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
@ 2019-07-23 12:14   ` Lavanya Govindarajan
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 " Lavanya Govindarajan
  2 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-07-23 12:14 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	pallantlax.poornima, Lavanya Govindarajan

This patchset contains unit testcases added to increase the
functional and decision coverage for the library functions 
defined in rte_mbuf.h and rte_mbuf.c

1/2: unit test cases added for rte_mbuf.h
2/2: unit test cases added for rte_mbuf.c

Patch 2/2 depends on 1/2

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
---
v3: Fixed build issue for environment FD30-64.
Improvised error log messages.

v2: Addressed v1's comments.
Removed rte prefix from the test function names.
Fixed comments given for the below test functions
test_mbuf_validate_tx_offload
test_neg_pktmbuf_alloc_bulk
test_pktmbuf_read_from_offset
test_pktmbuf_read_from_chain
---
Lavanya Govindarajan (1):
  app/test: add unit test cases for mbuf library APIs

Pallantla Poornima (1):
  app/test: add unit test cases to mbuf

 app/test/test_mbuf.c | 1019 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 1016 insertions(+), 3 deletions(-)

-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v3 1/2] app/test: add unit test cases for mbuf library APIs
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 0/2] add unit test cases for mbuf library Lavanya Govindarajan
@ 2019-07-23 12:14   ` Lavanya Govindarajan
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 0/2] add unit test cases for mbuf library Lavanya Govindarajan
                       ` (2 more replies)
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 " Lavanya Govindarajan
  2 siblings, 3 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-07-23 12:14 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	pallantlax.poornima, Lavanya Govindarajan

Added new unit test cases to cover the below
functions defined in rte_mbuf.h
rte_validate_tx_offload,
rte_pktmbuf_alloc_bulk,
rte_pktmbuf_read,
rte_pktmbuf_ext_shinfo_init_helper,
rte_pktmbuf_attach_extbuf,
rte_mbuf_ext_refcnt_read,
rte_mbuf_ext_refcnt_update,
rte_mbuf_ext_refcnt_set,
rte_pktmbuf_detach_extbuf

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
---
 app/test/test_mbuf.c | 759 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 756 insertions(+), 3 deletions(-)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 2a97afe20..623453d57 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -28,16 +28,28 @@
 #include <rte_random.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
 
 #include "test.h"
 
+#define MEMPOOL_CACHE_SIZE      32
 #define MBUF_DATA_SIZE          2048
 #define NB_MBUF                 128
 #define MBUF_TEST_DATA_LEN      1464
 #define MBUF_TEST_DATA_LEN2     50
+#define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
+#define MBUF_TEST_SEG_SIZE      64
+#define MBUF_TEST_BURST         8
+#define EXT_BUF_TEST_DATA_LEN   1024
+#define MBUF_MAX_SEG            16
+#define MBUF_NO_HEADER		0
+#define MBUF_HEADER		1
+#define MBUF_NEG_TEST_READ	2
 
 /* size of private data for mbuf in pktmbuf_pool2 */
 #define MBUF2_PRIV_SIZE         128
@@ -502,7 +514,6 @@ test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,
 		rte_pktmbuf_free(clone2);
 	return -1;
 }
-#undef GOTO_FAIL
 
 /*
  * test allocation and free of mbufs
@@ -1121,6 +1132,601 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+static int
+test_mbuf_validate_tx_offload(const char *test_name,
+		struct rte_mempool *pktmbuf_pool,
+		uint64_t ol_flags,
+		uint16_t segsize,
+		int expected_retval)
+{
+	struct rte_mbuf *m = NULL;
+	int ret = 0;
+	/* alloc a mbuf and do sanity check */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+	m->ol_flags = ol_flags;
+	m->tso_segsz = segsize;
+	ret = rte_validate_tx_offload(m);
+	if (ret != expected_retval)
+		GOTO_FAIL("%s(%s): expected ret val: %d; received: %d\n",
+				__func__, test_name, expected_retval, ret);
+	rte_pktmbuf_free(m);
+	m = NULL;
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test for allocating a bulk of mbufs
+ * define an array with positive sizes for mbufs allocations.
+ */
+static int
+test_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int ret = 0;
+	unsigned int idx, loop;
+	unsigned int alloc_counts[] = {
+		0,
+		MEMPOOL_CACHE_SIZE - 1,
+		MEMPOOL_CACHE_SIZE,
+		MEMPOOL_CACHE_SIZE + 1,
+		MEMPOOL_CACHE_SIZE * 1.5,
+		MEMPOOL_CACHE_SIZE * 2,
+		MEMPOOL_CACHE_SIZE * 2 - 1,
+		MEMPOOL_CACHE_SIZE * 2 + 1,
+		89,                         /* random number */
+		MEMPOOL_CACHE_SIZE          /* repeat cache size */
+	};
+
+	/* allocate a large array of mbuf pointers */
+	struct rte_mbuf *mbufs[NB_MBUF] = { 0 };
+	for (idx = 0; idx < RTE_DIM(alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				alloc_counts[idx]);
+		if (ret == 0) {
+			for (loop = 0; loop < alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+		} else if (ret != 0) {
+			printf("%s: Bulk alloc failed count(%u); ret val(%d)\n",
+					__func__, alloc_counts[idx], ret);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Negative testing for allocating a bulk of mbufs
+ */
+static int
+test_neg_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int loop, ret = 0;
+	unsigned int idx;
+	int neg_alloc_counts[] = {
+		MEMPOOL_CACHE_SIZE - NB_MBUF,
+		NB_MBUF + 1,
+		NB_MBUF * 8,
+		UINT_MAX
+	};
+	struct rte_mbuf *mbufs[NB_MBUF * 8] = { 0 };
+
+	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				neg_alloc_counts[idx]);
+		if (ret == 0) {
+			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
+					__func__, neg_alloc_counts[idx], ret);
+			for (loop = 0; loop < neg_alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Test to read mbuf packet using rte_pktmbuf_read
+ */
+static int
+test_pktmbuf_read(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	int off;
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	memset(data, 0xfe, MBUF_TEST_DATA_LEN2);
+
+	/* read the data from mbuf */
+	data_copy = rte_pktmbuf_read(m, 0, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read mbuf packet data from offset
+ */
+static int
+test_pktmbuf_read_from_offset(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct ether_hdr *hdr = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	unsigned int off;
+	unsigned int hdr_len = sizeof(struct rte_ether_hdr);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	/* prepend an ethernet header */
+	hdr = (struct ether_hdr *)rte_pktmbuf_prepend(m, hdr_len);
+	if (hdr == NULL)
+		GOTO_FAIL("%s: Cannot prepend header\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad pkt length", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad data length", __func__);
+	memset(hdr, 0xde, hdr_len);
+
+	/* read mbuf header info from 0 offset */
+	data_copy = rte_pktmbuf_read(m, 0, hdr_len, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header!\n", __func__);
+	for (off = 0; off < hdr_len; off++) {
+		if (data_copy[off] != (char)0xde)
+			GOTO_FAIL("Header info corrupted at offset %u", off);
+	}
+
+	/* append sample data after ethernet header */
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad data length\n", __func__);
+	memset(data, 0xcc, MBUF_TEST_DATA_LEN2);
+
+	/* read mbuf data after header info */
+	data_copy = rte_pktmbuf_read(m, hdr_len, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* partial reading of mbuf data */
+	data_copy = rte_pktmbuf_read(m, hdr_len + 5, MBUF_TEST_DATA_LEN2 - 5,
+			NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2 - 5)
+		GOTO_FAIL("%s: Incorrect data length!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2 - 5; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read length greater than mbuf data_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n",
+				__func__);
+
+	/* read length greater than mbuf pkt_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n",
+				__func__);
+
+	/* read data of zero len from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Corrupted data content!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of zero length from zero offset */
+	data_copy = rte_pktmbuf_read(m, 0, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of header info */
+	if (hdr != (const struct ether_hdr *)data_copy)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* read data of max length from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, UINT_MAX, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of data segment */
+	if (data_copy != data)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* try to read from mbuf with max size offset */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, 0, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	/* try to read from mbuf with max size offset and len */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, UINT_MAX, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+struct test_case {
+	unsigned int seg_count;
+	unsigned int flags;
+	uint32_t read_off;
+	uint32_t read_len;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+};
+
+/* create a mbuf with different sized segments
+ *  and fill with data [0x00 0x01 0x02 ...]
+ */
+static struct rte_mbuf *
+create_packet(struct rte_mempool *pktmbuf_pool,
+		struct test_case *test_data)
+		//unsigned int *seg_lengths_ptr, unsigned int flags)
+{
+	uint16_t i, ret, seg, seg_len = 0;
+	uint32_t last_index = 0;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+	unsigned int hdr_len;
+	struct rte_mbuf *pkt = NULL;
+	struct rte_mbuf	*pkt_seg = NULL;
+	char *hdr = NULL;
+	char *data = NULL;
+	memcpy(seg_lengths, test_data->seg_lengths,
+			sizeof(unsigned int)*test_data->seg_count);
+	for (seg = 0; seg < test_data->seg_count; seg++) {
+		hdr_len = 0;
+		seg_len =  seg_lengths[seg];
+		pkt_seg = rte_pktmbuf_alloc(pktmbuf_pool);
+		if (pkt_seg == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != 0)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		rte_mbuf_sanity_check(pkt_seg, 0);
+		/* Add header only for the first segment */
+		if (test_data->flags == MBUF_HEADER && seg == 0) {
+			hdr_len = sizeof(struct rte_ether_hdr);
+			/* prepend a header and fill with dummy data */
+			hdr = (char *)rte_pktmbuf_prepend(pkt_seg, hdr_len);
+			if (hdr == NULL)
+				GOTO_FAIL("%s: Cannot prepend header\n",
+						__func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad pkt length", __func__);
+			if (rte_pktmbuf_data_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad data length", __func__);
+			for (i = 0; i < hdr_len; i++)
+				hdr[i] = (last_index + i) % 0xffff;
+			last_index += hdr_len;
+		}
+		/* skip appending segment with 0 length */
+		if (seg_len == 0)
+			continue;
+		data = rte_pktmbuf_append(pkt_seg, seg_len);
+		if (data == NULL)
+			GOTO_FAIL("%s: Cannot append data segment\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad packet segment length: %d\n",
+					__func__, rte_pktmbuf_pkt_len(pkt_seg));
+		if (rte_pktmbuf_data_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad data length\n", __func__);
+		for (i = 0; i < seg_len; i++)
+			data[i] = (last_index + i) % 0xffff;
+		/* to fill continuous data from one seg to another */
+		last_index += i;
+		/* create chained mbufs */
+		if (seg == 0)
+			pkt = pkt_seg;
+		else {
+			ret = rte_pktmbuf_chain(pkt, pkt_seg);
+			if (ret != 0)
+				GOTO_FAIL("%s:FAIL: Chained mbuf creation %d\n",
+						__func__, ret);
+		}
+
+		pkt_seg = pkt_seg->next;
+	}
+	return pkt;
+fail:
+	if (pkt != NULL) {
+		rte_pktmbuf_free(pkt);
+		pkt = NULL;
+	}
+	if (pkt_seg != NULL) {
+		rte_pktmbuf_free(pkt_seg);
+		pkt_seg = NULL;
+	}
+	return NULL;
+}
+
+static int
+test_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m;
+	/* add testcases with different segments len, offset and read len */
+	struct test_case test_cases[] = {
+		{ .seg_lengths = { 100, 100, 100 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0, .read_len = 300 },
+		{ .seg_lengths = { 100, 125, 150 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 99, .read_len = 201 },
+		{ .seg_lengths = { 100, 100 },
+	    .seg_count = 2,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0,
+	    .read_len = 100 },
+		{ .seg_lengths = { 100, 200 },
+	    .seg_count = 2,
+	    .flags = MBUF_HEADER,
+	    .read_off = sizeof(struct rte_ether_hdr),
+	    .read_len = 150 },
+		{ .seg_lengths = { 1000, 100 },
+	    .seg_count = 2,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0,
+	    .read_len = 1000 },
+		{ .seg_lengths = { 1024, 0, 100 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 100,
+	    .read_len = 1001 },
+		{ .seg_lengths = { 1000, 1, 1000 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 1000,
+	    .read_len = 2 },
+		{ .seg_lengths = { MBUF_TEST_DATA_LEN, MBUF_TEST_DATA_LEN2,
+			     MBUF_TEST_DATA_LEN3, 800, 10 },
+		.seg_count = 5,
+		.flags = MBUF_NEG_TEST_READ,
+		.read_off = 1000,
+			.read_len = MBUF_DATA_SIZE },
+	};
+
+	uint32_t i, pos;
+	const char *data_copy = NULL;
+	char data_buf[MBUF_DATA_SIZE];
+	memset(data_buf, 0, MBUF_DATA_SIZE);
+
+	for (i = 0; i < RTE_DIM(test_cases); i++) {
+		m = create_packet(pktmbuf_pool, &test_cases[i]);
+		if (m == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+		data_copy = rte_pktmbuf_read(m, test_cases[i].read_off,
+				test_cases[i].read_len, data_buf);
+		if (test_cases[i].flags == MBUF_NEG_TEST_READ) {
+			if (data_copy != NULL)
+				GOTO_FAIL("%s: mbuf data read should fail!\n",
+						__func__);
+			else {
+				rte_pktmbuf_free(m);
+				m = NULL;
+				continue;
+			}
+		}
+		if (data_copy == NULL)
+			GOTO_FAIL("%s: Error in reading packet data!\n",
+					__func__);
+		for (pos = 0; pos < test_cases[i].read_len; pos++) {
+			if (data_copy[pos] !=
+					(char)((test_cases[i].read_off + pos)
+						% 0xffff))
+				GOTO_FAIL("Data corrupted at offset %u is %2X",
+						pos, data_copy[pos]);
+		}
+		rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return 0;
+
+fail:
+	if (m != NULL) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/* Define a free call back function to be used for external buffer */
+static void
+ext_buf_free_callback_fn(void *addr __rte_unused, void *opaque)
+{
+	void *ext_buf_addr = opaque;
+	if (ext_buf_addr == NULL) {
+		printf("External buffer address is invalid\n");
+		return;
+	}
+	rte_free(ext_buf_addr);
+	ext_buf_addr = NULL;
+	printf("External buffer freed via callback\n");
+}
+
+/*
+ * Test to initialize shared data in external buffer before attaching to mbuf
+ *  - Allocate mbuf with no data.
+ *  - Allocate external buffer with size should be large enough to accommodate
+ *     rte_mbuf_ext_shared_info.
+ *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
+ *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
+ *  - Clone another mbuf and attach the same external buffer to it.
+ *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from mbuf.
+ */
+static int
+test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct rte_mbuf *clone = NULL;
+	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
+	rte_iova_t buf_iova;
+	void *ext_buf_addr = NULL;
+	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
+				sizeof(struct rte_mbuf_ext_shared_info);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	ext_buf_addr = rte_malloc("External buffer", buf_len,
+			RTE_CACHE_LINE_SIZE);
+	if (ext_buf_addr == NULL)
+		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
+
+	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr, &buf_len,
+		ext_buf_free_callback_fn, ext_buf_addr);
+	if (ret_shinfo == NULL)
+		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
+
+	if (rte_mbuf_refcnt_read(m) != 1)
+		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
+
+	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
+	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
+		ret_shinfo);
+	if (m->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	/* allocate one more mbuf */
+	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
+	if (clone == NULL)
+		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(clone) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+
+	/* attach the same external buffer to the cloned mbuf */
+	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
+			ret_shinfo);
+	if (clone->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	/* test to manually update ext_buf_ref_cnt from 2 to 3*/
+	rte_mbuf_ext_refcnt_update(ret_shinfo, 1);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 3)
+		GOTO_FAIL("%s: Update ext_buf ref_cnt failed\n", __func__);
+
+	/* reset the ext_refcnt before freeing the external buffer */
+	rte_mbuf_ext_refcnt_set(ret_shinfo, 2);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: set ext_buf ref_cnt failed\n", __func__);
+
+	/* detach the external buffer from mbufs */
+	rte_pktmbuf_detach_extbuf(m);
+	/* check if ref cnt is decremented */
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_detach_extbuf(clone);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 0)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	rte_pktmbuf_free(clone);
+	clone = NULL;
+
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	if (clone) {
+		rte_pktmbuf_free(clone);
+		clone = NULL;
+	}
+	if (ext_buf_addr != NULL) {
+		rte_free(ext_buf_addr);
+		ext_buf_addr = NULL;
+	}
+	return -1;
+}
+
 static int
 test_mbuf(void)
 {
@@ -1133,7 +1739,8 @@ test_mbuf(void)
 
 	/* create pktmbuf pool if it does not exist */
 	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
-			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1143,7 +1750,8 @@ test_mbuf(void)
 	/* create a specific pktmbuf pool with a priv_size != 0 and no data
 	 * room size */
 	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
-			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool2 == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1225,6 +1833,150 @@ test_mbuf(void)
 		goto err;
 	}
 
+	/* test to validate tx offload flags */
+	uint64_t ol_flags = 0;
+	/* test to validate if IP checksum is counted only for IPV4 packet */
+	/* set both IP checksum and IPV6 flags */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_CKSUM_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* resetting ol_flags for next testcase */
+	ol_flags = 0;
+
+	/* test to validate if IP type is set when required */
+	ol_flags |= PKT_TX_L4_MASK;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test if IP type is set when TCP SEG is on */
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm IP type (IPV4/IPV6) is set */
+	ol_flags = PKT_TX_L4_MASK;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_SET",
+				pktmbuf_pool,
+				ol_flags, 0, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to check TSO segment size is non-zero */
+	ol_flags |= PKT_TX_IPV4;
+	ol_flags |= PKT_TX_TCP_SEG;
+	/* set 0 tso segment size */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_NULL_TSO_SEGSZ",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* retain IPV4 and PKT_TX_TCP_SEG mask */
+	/* set valid tso segment size but IP CKSUM not set */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test to validate if IP checksum is set for TSO capability */
+	/* retain IPV4, TCP_SEG, tso_seg size */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test to confirm TSO for IPV6 type */
+	ol_flags = 0;
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test if outer IP checksum set for non outer IPv4 packet */
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm outer IP checksum is set for outer IPV4 packet */
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	ol_flags |= PKT_TX_OUTER_IPV4;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm if packets with no TX_OFFLOAD_MASK are skipped */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OL_MASK_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_neg_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_neg_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet */
+	if (test_pktmbuf_read(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet from offset */
+	if (test_pktmbuf_read_from_offset(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_offset() failed\n");
+		goto err;
+	}
+
+	/* test to read data from chain of mbufs with data segments */
+	if (test_pktmbuf_read_from_chain(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_chain() failed\n");
+		goto err;
+	}
+
+	/* test to initialize shared info. at the end of external buffer */
+	if (test_pktmbuf_ext_shinfo_init_helper(pktmbuf_pool) < 0) {
+		printf("test_pktmbuf_ext_shinfo_init_helper() failed\n");
+		goto err;
+	}
+
 	ret = 0;
 err:
 	rte_mempool_free(pktmbuf_pool);
@@ -1233,3 +1985,4 @@ test_mbuf(void)
 }
 
 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);
+#undef GOTO_FAIL
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v3 2/2] app/test: add unit test cases to mbuf
  2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 0/2] add unit test cases for mbuf library Lavanya Govindarajan
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
@ 2019-07-23 12:14   ` Lavanya Govindarajan
  2 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-07-23 12:14 UTC (permalink / raw)
  To: dev; +Cc: reshma.pattan, olivier.matz, bruce.richardson, pallantlax.poornima

From: Pallantla Poornima <pallantlax.poornima@intel.com>

Added UT for the below four functions in test_mbuf.c
rte_get_rx_ol_flag_list
rte_get_tx_ol_flag_list
rte_get_rx_ol_flag_name
rte_get_tx_ol_flag_name

Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
---
 app/test/test_mbuf.c | 260 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 260 insertions(+)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 623453d57..381949d70 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -42,6 +42,7 @@
 #define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
+#define MBUF_TEST_LEN           250
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
 #define MBUF_TEST_SEG_SIZE      64
 #define MBUF_TEST_BURST         8
@@ -1132,6 +1133,245 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+
+static int
+test_get_rx_ol_flag_list(void)
+{
+	int len, ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_rx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_L4_CKSUM_MASK, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0)
+		GOTO_FAIL("%s buffer should be empty, received = %d\n",
+				__func__, buflen);
+
+	/* Test case to check with reduced buffer len */
+	len = sizeof(buf) - MBUF_TEST_LEN;
+	ret = rte_get_rx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received = %d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_rx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_SEC_OFFLOAD, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_list(void)
+{
+	int len, ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_tx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_IP_CKSUM, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0) {
+		GOTO_FAIL("%s buffer should be empty, received = %d\n",
+				__func__, buflen);
+	}
+
+	/* Test case to check with reduced buffer len */
+	len = sizeof(buf) - MBUF_TEST_LEN;
+	ret = rte_get_tx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received = %d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_tx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_UDP_CKSUM, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	return 0;
+fail:
+	return -1;
+
+}
+
+struct flag_name {
+	uint64_t flag;
+	const char *name;
+};
+
+static int
+test_get_rx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name rx_flags[] = {
+		{ PKT_RX_VLAN, "PKT_RX_VLAN" },
+		{ PKT_RX_RSS_HASH, "PKT_RX_RSS_HASH" },
+		{ PKT_RX_FDIR, "PKT_RX_FDIR"},
+		{ PKT_RX_L4_CKSUM_BAD, "PKT_RX_L4_CKSUM_BAD"},
+		{ PKT_RX_L4_CKSUM_GOOD, "PKT_RX_L4_CKSUM_GOOD"},
+		{ PKT_RX_L4_CKSUM_NONE, "PKT_RX_L4_CKSUM_NONE"},
+		{ PKT_RX_IP_CKSUM_BAD, "PKT_RX_IP_CKSUM_BAD"},
+		{ PKT_RX_IP_CKSUM_GOOD, "PKT_RX_IP_CKSUM_GOOD"},
+		{ PKT_RX_IP_CKSUM_NONE, "PKT_RX_IP_CKSUM_NONE"},
+		{ PKT_RX_EIP_CKSUM_BAD, "PKT_RX_EIP_CKSUM_BAD" },
+		{ PKT_RX_VLAN_STRIPPED, "PKT_RX_VLAN_STRIPPED" },
+		{ PKT_RX_IEEE1588_PTP, "PKT_RX_IEEE1588_PTP"},
+		{ PKT_RX_IEEE1588_TMST, "PKT_RX_IEEE1588_TMST"},
+		{ PKT_RX_FDIR_ID, "PKT_RX_FDIR_ID"},
+		{ PKT_RX_FDIR_FLX, "PKT_RX_FDIR_FLX"},
+		{ PKT_RX_QINQ_STRIPPED, "PKT_RX_QINQ_STRIPPED" },
+		{ PKT_RX_LRO, "PKT_RX_LRO" },
+		{ PKT_RX_TIMESTAMP, "PKT_RX_TIMESTAMP"},
+		{ PKT_RX_SEC_OFFLOAD, "PKT_RX_SEC_OFFLOAD" },
+		{ PKT_RX_SEC_OFFLOAD_FAILED, "PKT_RX_SEC_OFFLOAD_FAILED" },
+		{ PKT_RX_OUTER_L4_CKSUM_BAD, "PKT_RX_OUTER_L4_CKSUM_BAD" },
+		{ PKT_RX_OUTER_L4_CKSUM_GOOD, "PKT_RX_OUTER_L4_CKSUM_GOOD"},
+		{ PKT_RX_OUTER_L4_CKSUM_INVALID,
+			"PKT_RX_OUTER_L4_CKSUM_INVALID" },
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(rx_flags); i++) {
+		flag_str = rte_get_rx_ol_flag_name(rx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s: Expected flagname = %s; received null\n",
+					__func__, rx_flags[i].name);
+		if (strcmp(flag_str, rx_flags[i].name) != 0)
+			GOTO_FAIL("%s: Expected flagname = %s; received = %s\n",
+				__func__, rx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_rx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s: Expected flag name = null; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name tx_flags[] = {
+
+	{ PKT_TX_VLAN, "PKT_TX_VLAN" },
+	{ PKT_TX_IP_CKSUM, "PKT_TX_IP_CKSUM" },
+	{ PKT_TX_TCP_CKSUM, "PKT_TX_TCP_CKSUM" },
+	{ PKT_TX_SCTP_CKSUM, "PKT_TX_SCTP_CKSUM" },
+	{ PKT_TX_UDP_CKSUM, "PKT_TX_UDP_CKSUM" },
+	{ PKT_TX_IEEE1588_TMST, "PKT_TX_IEEE1588_TMST" },
+	{ PKT_TX_TCP_SEG, "PKT_TX_TCP_SEG" },
+	{ PKT_TX_IPV4, "PKT_TX_IPV4" },
+	{ PKT_TX_IPV6, "PKT_TX_IPV6" },
+	{ PKT_TX_OUTER_IP_CKSUM, "PKT_TX_OUTER_IP_CKSUM" },
+	{ PKT_TX_OUTER_IPV4, "PKT_TX_OUTER_IPV4" },
+	{ PKT_TX_OUTER_IPV6, "PKT_TX_OUTER_IPV6" },
+	{ PKT_TX_TUNNEL_VXLAN, "PKT_TX_TUNNEL_VXLAN" },
+	{ PKT_TX_TUNNEL_GRE,  "PKT_TX_TUNNEL_GRE" },
+	{ PKT_TX_TUNNEL_IPIP, "PKT_TX_TUNNEL_IPIP" },
+	{ PKT_TX_TUNNEL_GENEVE,  "PKT_TX_TUNNEL_GENEVE" },
+	{ PKT_TX_TUNNEL_MPLSINUDP, "PKT_TX_TUNNEL_MPLSINUDP" },
+	{ PKT_TX_TUNNEL_VXLAN_GPE, "PKT_TX_TUNNEL_VXLAN_GPE" },
+	{ PKT_TX_TUNNEL_IP, "PKT_TX_TUNNEL_IP" },
+	{ PKT_TX_TUNNEL_UDP, "PKT_TX_TUNNEL_UDP" },
+	{ PKT_TX_QINQ, "PKT_TX_QINQ" },
+	{ PKT_TX_MACSEC, "PKT_TX_MACSEC" },
+	{ PKT_TX_SEC_OFFLOAD, "PKT_TX_SEC_OFFLOAD" },
+	{ PKT_TX_UDP_SEG, "PKT_TX_UDP_SEG" },
+	{ PKT_TX_OUTER_UDP_CKSUM, "PKT_TX_OUTER_UDP_CKSUM" },
+	{ PKT_TX_METADATA, "PKT_TX_METADATA" },
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(tx_flags); i++) {
+		flag_str = rte_get_tx_ol_flag_name(tx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s: Expected flagname = %s; received null\n",
+				__func__, tx_flags[i].name);
+		if (strcmp(flag_str, tx_flags[i].name) != 0)
+			GOTO_FAIL("%s: Expected flagname = %s; received = %s\n",
+				__func__, tx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_tx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s: Expected flag name = null; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+
+}
+
 static int
 test_mbuf_validate_tx_offload(const char *test_name,
 		struct rte_mempool *pktmbuf_pool,
@@ -1833,6 +2073,26 @@ test_mbuf(void)
 		goto err;
 	}
 
+	if (test_get_rx_ol_flag_list() < 0) {
+		printf("test_rte_get_rx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_list() < 0) {
+		printf("test_rte_get_tx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_rx_ol_flag_name() < 0) {
+		printf("test_rte_get_rx_ol_flag_name() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_name() < 0) {
+		printf("test_rte_get_tx_ol_flag_name() failed\n");
+		goto err;
+	}
+
 	/* test to validate tx offload flags */
 	uint64_t ol_flags = 0;
 	/* test to validate if IP checksum is counted only for IPV4 packet */
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v4 0/2] add unit test cases for mbuf library
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
@ 2019-08-08 13:34     ` Lavanya Govindarajan
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
  2 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-08-08 13:34 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	pallantlax.poornima, Lavanya Govindarajan

This patchset contains unit testcases added to increase the
functional and decision coverage for the library functions
defined in rte_mbuf.h and rte_mbuf.c

1/2: unit test cases added for rte_mbuf.h
2/2: unit test cases added for rte_mbuf.c

Patch 2/2 depends on 1/2

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
---
v4: Fixed cosmetic errors.

v3: Fixed build issue for environment FD30-64.
Improvised error log messages.

v2: Addressed v1's comments.
Removed rte prefix from the test function names.
Fixed comments given for the below test functions
test_mbuf_validate_tx_offload
test_neg_pktmbuf_alloc_bulk
test_pktmbuf_read_from_offset
test_pktmbuf_read_from_chain
---
Lavanya Govindarajan (1):
  app/test: add unit test cases for mbuf library APIs

Pallantla Poornima (1):
  app/test: add unit test cases to mbuf

 app/test/test_mbuf.c | 1016 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 1013 insertions(+), 3 deletions(-)

-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 0/2] add unit test cases for mbuf library Lavanya Govindarajan
@ 2019-08-08 13:34     ` Lavanya Govindarajan
  2019-08-26  8:47       ` Olivier Matz
                         ` (3 more replies)
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
  2 siblings, 4 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-08-08 13:34 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	pallantlax.poornima, Lavanya Govindarajan

Added new unit test cases to cover the below
functions defined in rte_mbuf.h
rte_validate_tx_offload,
rte_pktmbuf_alloc_bulk,
rte_pktmbuf_read,
rte_pktmbuf_ext_shinfo_init_helper,
rte_pktmbuf_attach_extbuf,
rte_mbuf_ext_refcnt_read,
rte_mbuf_ext_refcnt_update,
rte_mbuf_ext_refcnt_set,
rte_pktmbuf_detach_extbuf

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
---
 app/test/test_mbuf.c | 756 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 753 insertions(+), 3 deletions(-)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 2a97afe20..28f3216c0 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -28,16 +28,28 @@
 #include <rte_random.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
 
 #include "test.h"
 
+#define MEMPOOL_CACHE_SIZE      32
 #define MBUF_DATA_SIZE          2048
 #define NB_MBUF                 128
 #define MBUF_TEST_DATA_LEN      1464
 #define MBUF_TEST_DATA_LEN2     50
+#define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
+#define MBUF_TEST_SEG_SIZE      64
+#define MBUF_TEST_BURST         8
+#define EXT_BUF_TEST_DATA_LEN   1024
+#define MBUF_MAX_SEG            16
+#define MBUF_NO_HEADER		0
+#define MBUF_HEADER		1
+#define MBUF_NEG_TEST_READ	2
 
 /* size of private data for mbuf in pktmbuf_pool2 */
 #define MBUF2_PRIV_SIZE         128
@@ -502,7 +514,6 @@ test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,
 		rte_pktmbuf_free(clone2);
 	return -1;
 }
-#undef GOTO_FAIL
 
 /*
  * test allocation and free of mbufs
@@ -1121,6 +1132,598 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+static int
+test_mbuf_validate_tx_offload(const char *test_name,
+		struct rte_mempool *pktmbuf_pool,
+		uint64_t ol_flags,
+		uint16_t segsize,
+		int expected_retval)
+{
+	struct rte_mbuf *m = NULL;
+	int ret = 0;
+	/* alloc a mbuf and do sanity check */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+	m->ol_flags = ol_flags;
+	m->tso_segsz = segsize;
+	ret = rte_validate_tx_offload(m);
+	if (ret != expected_retval)
+		GOTO_FAIL("%s(%s): expected ret val: %d; received: %d\n",
+				__func__, test_name, expected_retval, ret);
+	rte_pktmbuf_free(m);
+	m = NULL;
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test for allocating a bulk of mbufs
+ * define an array with positive sizes for mbufs allocations.
+ */
+static int
+test_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int ret = 0;
+	unsigned int idx, loop;
+	unsigned int alloc_counts[] = {
+		0,
+		MEMPOOL_CACHE_SIZE - 1,
+		MEMPOOL_CACHE_SIZE + 1,
+		MEMPOOL_CACHE_SIZE * 1.5,
+		MEMPOOL_CACHE_SIZE * 2,
+		MEMPOOL_CACHE_SIZE * 2 - 1,
+		MEMPOOL_CACHE_SIZE * 2 + 1,
+		MEMPOOL_CACHE_SIZE,
+	};
+
+	/* allocate a large array of mbuf pointers */
+	struct rte_mbuf *mbufs[NB_MBUF] = { 0 };
+	for (idx = 0; idx < RTE_DIM(alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				alloc_counts[idx]);
+		if (ret == 0) {
+			for (loop = 0; loop < alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+		} else if (ret != 0) {
+			printf("%s: Bulk alloc failed count(%u); ret val(%d)\n",
+					__func__, alloc_counts[idx], ret);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Negative testing for allocating a bulk of mbufs
+ */
+static int
+test_neg_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int loop, ret = 0;
+	unsigned int idx;
+	int neg_alloc_counts[] = {
+		MEMPOOL_CACHE_SIZE - NB_MBUF,
+		NB_MBUF + 1,
+		NB_MBUF * 8,
+		UINT_MAX
+	};
+	struct rte_mbuf *mbufs[NB_MBUF * 8] = { 0 };
+
+	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				neg_alloc_counts[idx]);
+		if (ret == 0) {
+			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
+					__func__, neg_alloc_counts[idx], ret);
+			for (loop = 0; loop < neg_alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Test to read mbuf packet using rte_pktmbuf_read
+ */
+static int
+test_pktmbuf_read(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	int off;
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	memset(data, 0xfe, MBUF_TEST_DATA_LEN2);
+
+	/* read the data from mbuf */
+	data_copy = rte_pktmbuf_read(m, 0, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read mbuf packet data from offset
+ */
+static int
+test_pktmbuf_read_from_offset(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct ether_hdr *hdr = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	unsigned int off;
+	unsigned int hdr_len = sizeof(struct rte_ether_hdr);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	/* prepend an ethernet header */
+	hdr = (struct ether_hdr *)rte_pktmbuf_prepend(m, hdr_len);
+	if (hdr == NULL)
+		GOTO_FAIL("%s: Cannot prepend header\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad pkt length", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad data length", __func__);
+	memset(hdr, 0xde, hdr_len);
+
+	/* read mbuf header info from 0 offset */
+	data_copy = rte_pktmbuf_read(m, 0, hdr_len, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header!\n", __func__);
+	for (off = 0; off < hdr_len; off++) {
+		if (data_copy[off] != (char)0xde)
+			GOTO_FAIL("Header info corrupted at offset %u", off);
+	}
+
+	/* append sample data after ethernet header */
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad data length\n", __func__);
+	memset(data, 0xcc, MBUF_TEST_DATA_LEN2);
+
+	/* read mbuf data after header info */
+	data_copy = rte_pktmbuf_read(m, hdr_len, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* partial reading of mbuf data */
+	data_copy = rte_pktmbuf_read(m, hdr_len + 5, MBUF_TEST_DATA_LEN2 - 5,
+			NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2 - 5)
+		GOTO_FAIL("%s: Incorrect data length!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2 - 5; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read length greater than mbuf data_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n",
+				__func__);
+
+	/* read length greater than mbuf pkt_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n",
+				__func__);
+
+	/* read data of zero len from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Corrupted data content!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of zero length from zero offset */
+	data_copy = rte_pktmbuf_read(m, 0, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of header info */
+	if (hdr != (const struct ether_hdr *)data_copy)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* read data of max length from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, UINT_MAX, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of data segment */
+	if (data_copy != data)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* try to read from mbuf with max size offset */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, 0, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	/* try to read from mbuf with max size offset and len */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, UINT_MAX, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+struct test_case {
+	unsigned int seg_count;
+	unsigned int flags;
+	uint32_t read_off;
+	uint32_t read_len;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+};
+
+/* create a mbuf with different sized segments
+ *  and fill with data [0x00 0x01 0x02 ...]
+ */
+static struct rte_mbuf *
+create_packet(struct rte_mempool *pktmbuf_pool,
+		struct test_case *test_data)
+{
+	uint16_t i, ret, seg, seg_len = 0;
+	uint32_t last_index = 0;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+	unsigned int hdr_len;
+	struct rte_mbuf *pkt = NULL;
+	struct rte_mbuf	*pkt_seg = NULL;
+	char *hdr = NULL;
+	char *data = NULL;
+	memcpy(seg_lengths, test_data->seg_lengths,
+			sizeof(unsigned int)*test_data->seg_count);
+	for (seg = 0; seg < test_data->seg_count; seg++) {
+		hdr_len = 0;
+		seg_len =  seg_lengths[seg];
+		pkt_seg = rte_pktmbuf_alloc(pktmbuf_pool);
+		if (pkt_seg == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != 0)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		rte_mbuf_sanity_check(pkt_seg, 0);
+		/* Add header only for the first segment */
+		if (test_data->flags == MBUF_HEADER && seg == 0) {
+			hdr_len = sizeof(struct rte_ether_hdr);
+			/* prepend a header and fill with dummy data */
+			hdr = (char *)rte_pktmbuf_prepend(pkt_seg, hdr_len);
+			if (hdr == NULL)
+				GOTO_FAIL("%s: Cannot prepend header\n",
+						__func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad pkt length", __func__);
+			if (rte_pktmbuf_data_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad data length", __func__);
+			for (i = 0; i < hdr_len; i++)
+				hdr[i] = (last_index + i) % 0xffff;
+			last_index += hdr_len;
+		}
+		/* skip appending segment with 0 length */
+		if (seg_len == 0)
+			continue;
+		data = rte_pktmbuf_append(pkt_seg, seg_len);
+		if (data == NULL)
+			GOTO_FAIL("%s: Cannot append data segment\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad packet segment length: %d\n",
+					__func__, rte_pktmbuf_pkt_len(pkt_seg));
+		if (rte_pktmbuf_data_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad data length\n", __func__);
+		for (i = 0; i < seg_len; i++)
+			data[i] = (last_index + i) % 0xffff;
+		/* to fill continuous data from one seg to another */
+		last_index += i;
+		/* create chained mbufs */
+		if (seg == 0)
+			pkt = pkt_seg;
+		else {
+			ret = rte_pktmbuf_chain(pkt, pkt_seg);
+			if (ret != 0)
+				GOTO_FAIL("%s:FAIL: Chained mbuf creation %d\n",
+						__func__, ret);
+		}
+
+		pkt_seg = pkt_seg->next;
+	}
+	return pkt;
+fail:
+	if (pkt != NULL) {
+		rte_pktmbuf_free(pkt);
+		pkt = NULL;
+	}
+	if (pkt_seg != NULL) {
+		rte_pktmbuf_free(pkt_seg);
+		pkt_seg = NULL;
+	}
+	return NULL;
+}
+
+static int
+test_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m;
+	/* add testcases with different segments len, offset and read len */
+	struct test_case test_cases[] = {
+		{ .seg_lengths = { 100, 100, 100 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0, .read_len = 300 },
+		{ .seg_lengths = { 100, 125, 150 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 99, .read_len = 201 },
+		{ .seg_lengths = { 100, 100 },
+	    .seg_count = 2,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0,
+	    .read_len = 100 },
+		{ .seg_lengths = { 100, 200 },
+	    .seg_count = 2,
+	    .flags = MBUF_HEADER,
+	    .read_off = sizeof(struct rte_ether_hdr),
+	    .read_len = 150 },
+		{ .seg_lengths = { 1000, 100 },
+	    .seg_count = 2,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 0,
+	    .read_len = 1000 },
+		{ .seg_lengths = { 1024, 0, 100 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 100,
+	    .read_len = 1001 },
+		{ .seg_lengths = { 1000, 1, 1000 },
+	    .seg_count = 3,
+	    .flags = MBUF_NO_HEADER,
+	    .read_off = 1000,
+	    .read_len = 2 },
+		{ .seg_lengths = { MBUF_TEST_DATA_LEN, MBUF_TEST_DATA_LEN2,
+			     MBUF_TEST_DATA_LEN3, 800, 10 },
+		.seg_count = 5,
+		.flags = MBUF_NEG_TEST_READ,
+		.read_off = 1000,
+			.read_len = MBUF_DATA_SIZE },
+	};
+
+	uint32_t i, pos;
+	const char *data_copy = NULL;
+	char data_buf[MBUF_DATA_SIZE];
+	memset(data_buf, 0, MBUF_DATA_SIZE);
+
+	for (i = 0; i < RTE_DIM(test_cases); i++) {
+		m = create_packet(pktmbuf_pool, &test_cases[i]);
+		if (m == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+		data_copy = rte_pktmbuf_read(m, test_cases[i].read_off,
+				test_cases[i].read_len, data_buf);
+		if (test_cases[i].flags == MBUF_NEG_TEST_READ) {
+			if (data_copy != NULL)
+				GOTO_FAIL("%s: mbuf data read should fail!\n",
+						__func__);
+			else {
+				rte_pktmbuf_free(m);
+				m = NULL;
+				continue;
+			}
+		}
+		if (data_copy == NULL)
+			GOTO_FAIL("%s: Error in reading packet data!\n",
+					__func__);
+		for (pos = 0; pos < test_cases[i].read_len; pos++) {
+			if (data_copy[pos] !=
+					(char)((test_cases[i].read_off + pos)
+						% 0xffff))
+				GOTO_FAIL("Data corrupted at offset %u is %2X",
+						pos, data_copy[pos]);
+		}
+		rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return 0;
+
+fail:
+	if (m != NULL) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/* Define a free call back function to be used for external buffer */
+static void
+ext_buf_free_callback_fn(void *addr __rte_unused, void *opaque)
+{
+	void *ext_buf_addr = opaque;
+	if (ext_buf_addr == NULL) {
+		printf("External buffer address is invalid\n");
+		return;
+	}
+	rte_free(ext_buf_addr);
+	ext_buf_addr = NULL;
+	printf("External buffer freed via callback\n");
+}
+
+/*
+ * Test to initialize shared data in external buffer before attaching to mbuf
+ *  - Allocate mbuf with no data.
+ *  - Allocate external buffer with size should be large enough to accommodate
+ *     rte_mbuf_ext_shared_info.
+ *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
+ *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
+ *  - Clone another mbuf and attach the same external buffer to it.
+ *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from mbuf.
+ */
+static int
+test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct rte_mbuf *clone = NULL;
+	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
+	rte_iova_t buf_iova;
+	void *ext_buf_addr = NULL;
+	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
+				sizeof(struct rte_mbuf_ext_shared_info);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	ext_buf_addr = rte_malloc("External buffer", buf_len,
+			RTE_CACHE_LINE_SIZE);
+	if (ext_buf_addr == NULL)
+		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
+
+	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr, &buf_len,
+		ext_buf_free_callback_fn, ext_buf_addr);
+	if (ret_shinfo == NULL)
+		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
+
+	if (rte_mbuf_refcnt_read(m) != 1)
+		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
+
+	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
+	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
+		ret_shinfo);
+	if (m->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	/* allocate one more mbuf */
+	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
+	if (clone == NULL)
+		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(clone) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+
+	/* attach the same external buffer to the cloned mbuf */
+	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
+			ret_shinfo);
+	if (clone->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	/* test to manually update ext_buf_ref_cnt from 2 to 3*/
+	rte_mbuf_ext_refcnt_update(ret_shinfo, 1);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 3)
+		GOTO_FAIL("%s: Update ext_buf ref_cnt failed\n", __func__);
+
+	/* reset the ext_refcnt before freeing the external buffer */
+	rte_mbuf_ext_refcnt_set(ret_shinfo, 2);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: set ext_buf ref_cnt failed\n", __func__);
+
+	/* detach the external buffer from mbufs */
+	rte_pktmbuf_detach_extbuf(m);
+	/* check if ref cnt is decremented */
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_detach_extbuf(clone);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 0)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	rte_pktmbuf_free(clone);
+	clone = NULL;
+
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	if (clone) {
+		rte_pktmbuf_free(clone);
+		clone = NULL;
+	}
+	if (ext_buf_addr != NULL) {
+		rte_free(ext_buf_addr);
+		ext_buf_addr = NULL;
+	}
+	return -1;
+}
+
 static int
 test_mbuf(void)
 {
@@ -1133,7 +1736,8 @@ test_mbuf(void)
 
 	/* create pktmbuf pool if it does not exist */
 	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
-			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1143,7 +1747,8 @@ test_mbuf(void)
 	/* create a specific pktmbuf pool with a priv_size != 0 and no data
 	 * room size */
 	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
-			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool2 == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1225,6 +1830,150 @@ test_mbuf(void)
 		goto err;
 	}
 
+	/* test to validate tx offload flags */
+	uint64_t ol_flags = 0;
+	/* test to validate if IP checksum is counted only for IPV4 packet */
+	/* set both IP checksum and IPV6 flags */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_CKSUM_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* resetting ol_flags for next testcase */
+	ol_flags = 0;
+
+	/* test to validate if IP type is set when required */
+	ol_flags |= PKT_TX_L4_MASK;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test if IP type is set when TCP SEG is on */
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm IP type (IPV4/IPV6) is set */
+	ol_flags = PKT_TX_L4_MASK;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_SET",
+				pktmbuf_pool,
+				ol_flags, 0, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to check TSO segment size is non-zero */
+	ol_flags |= PKT_TX_IPV4;
+	ol_flags |= PKT_TX_TCP_SEG;
+	/* set 0 tso segment size */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_NULL_TSO_SEGSZ",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* retain IPV4 and PKT_TX_TCP_SEG mask */
+	/* set valid tso segment size but IP CKSUM not set */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test to validate if IP checksum is set for TSO capability */
+	/* retain IPV4, TCP_SEG, tso_seg size */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	/* test to confirm TSO for IPV6 type */
+	ol_flags = 0;
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test if outer IP checksum set for non outer IPv4 packet */
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm outer IP checksum is set for outer IPV4 packet */
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	ol_flags |= PKT_TX_OUTER_IPV4;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+	ol_flags = 0;
+	/* test to confirm if packets with no TX_OFFLOAD_MASK are skipped */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OL_MASK_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0) {
+		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_neg_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_neg_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet */
+	if (test_pktmbuf_read(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet from offset */
+	if (test_pktmbuf_read_from_offset(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_offset() failed\n");
+		goto err;
+	}
+
+	/* test to read data from chain of mbufs with data segments */
+	if (test_pktmbuf_read_from_chain(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_chain() failed\n");
+		goto err;
+	}
+
+	/* test to initialize shared info. at the end of external buffer */
+	if (test_pktmbuf_ext_shinfo_init_helper(pktmbuf_pool) < 0) {
+		printf("test_pktmbuf_ext_shinfo_init_helper() failed\n");
+		goto err;
+	}
+
 	ret = 0;
 err:
 	rte_mempool_free(pktmbuf_pool);
@@ -1233,3 +1982,4 @@ test_mbuf(void)
 }
 
 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);
+#undef GOTO_FAIL
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v4 2/2] app/test: add unit test cases to mbuf
  2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 0/2] add unit test cases for mbuf library Lavanya Govindarajan
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
@ 2019-08-08 13:34     ` Lavanya Govindarajan
  2019-08-26  9:09       ` Olivier Matz
  2 siblings, 1 reply; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-08-08 13:34 UTC (permalink / raw)
  To: dev; +Cc: reshma.pattan, olivier.matz, bruce.richardson, pallantlax.poornima

From: Pallantla Poornima <pallantlax.poornima@intel.com@intel.com>

Added UT for the below four functions in test_mbuf.c
rte_get_rx_ol_flag_list
rte_get_tx_ol_flag_list
rte_get_rx_ol_flag_name
rte_get_tx_ol_flag_name

Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com@intel.com>
---
 app/test/test_mbuf.c | 260 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 260 insertions(+)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 28f3216c0..1a943518d 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -42,6 +42,7 @@
 #define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
+#define MBUF_TEST_LEN           250
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
 #define MBUF_TEST_SEG_SIZE      64
 #define MBUF_TEST_BURST         8
@@ -1132,6 +1133,245 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+
+static int
+test_get_rx_ol_flag_list(void)
+{
+	int len, ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_rx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_L4_CKSUM_MASK, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0)
+		GOTO_FAIL("%s buffer should be empty, received = %d\n",
+				__func__, buflen);
+
+	/* Test case to check with reduced buffer len */
+	len = sizeof(buf) - MBUF_TEST_LEN;
+	ret = rte_get_rx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received = %d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_rx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_SEC_OFFLOAD, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_list(void)
+{
+	int len, ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_tx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_IP_CKSUM, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0) {
+		GOTO_FAIL("%s buffer should be empty, received = %d\n",
+				__func__, buflen);
+	}
+
+	/* Test case to check with reduced buffer len */
+	len = sizeof(buf) - MBUF_TEST_LEN;
+	ret = rte_get_tx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received = %d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_tx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_UDP_CKSUM, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	return 0;
+fail:
+	return -1;
+
+}
+
+struct flag_name {
+	uint64_t flag;
+	const char *name;
+};
+
+static int
+test_get_rx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name rx_flags[] = {
+		{ PKT_RX_VLAN, "PKT_RX_VLAN" },
+		{ PKT_RX_RSS_HASH, "PKT_RX_RSS_HASH" },
+		{ PKT_RX_FDIR, "PKT_RX_FDIR"},
+		{ PKT_RX_L4_CKSUM_BAD, "PKT_RX_L4_CKSUM_BAD"},
+		{ PKT_RX_L4_CKSUM_GOOD, "PKT_RX_L4_CKSUM_GOOD"},
+		{ PKT_RX_L4_CKSUM_NONE, "PKT_RX_L4_CKSUM_NONE"},
+		{ PKT_RX_IP_CKSUM_BAD, "PKT_RX_IP_CKSUM_BAD"},
+		{ PKT_RX_IP_CKSUM_GOOD, "PKT_RX_IP_CKSUM_GOOD"},
+		{ PKT_RX_IP_CKSUM_NONE, "PKT_RX_IP_CKSUM_NONE"},
+		{ PKT_RX_EIP_CKSUM_BAD, "PKT_RX_EIP_CKSUM_BAD" },
+		{ PKT_RX_VLAN_STRIPPED, "PKT_RX_VLAN_STRIPPED" },
+		{ PKT_RX_IEEE1588_PTP, "PKT_RX_IEEE1588_PTP"},
+		{ PKT_RX_IEEE1588_TMST, "PKT_RX_IEEE1588_TMST"},
+		{ PKT_RX_FDIR_ID, "PKT_RX_FDIR_ID"},
+		{ PKT_RX_FDIR_FLX, "PKT_RX_FDIR_FLX"},
+		{ PKT_RX_QINQ_STRIPPED, "PKT_RX_QINQ_STRIPPED" },
+		{ PKT_RX_LRO, "PKT_RX_LRO" },
+		{ PKT_RX_TIMESTAMP, "PKT_RX_TIMESTAMP"},
+		{ PKT_RX_SEC_OFFLOAD, "PKT_RX_SEC_OFFLOAD" },
+		{ PKT_RX_SEC_OFFLOAD_FAILED, "PKT_RX_SEC_OFFLOAD_FAILED" },
+		{ PKT_RX_OUTER_L4_CKSUM_BAD, "PKT_RX_OUTER_L4_CKSUM_BAD" },
+		{ PKT_RX_OUTER_L4_CKSUM_GOOD, "PKT_RX_OUTER_L4_CKSUM_GOOD"},
+		{ PKT_RX_OUTER_L4_CKSUM_INVALID,
+			"PKT_RX_OUTER_L4_CKSUM_INVALID" },
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(rx_flags); i++) {
+		flag_str = rte_get_rx_ol_flag_name(rx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s: Expected flagname = %s; received null\n",
+					__func__, rx_flags[i].name);
+		if (strcmp(flag_str, rx_flags[i].name) != 0)
+			GOTO_FAIL("%s: Expected flagname = %s; received = %s\n",
+				__func__, rx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_rx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s: Expected flag name = null; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name tx_flags[] = {
+
+	{ PKT_TX_VLAN, "PKT_TX_VLAN" },
+	{ PKT_TX_IP_CKSUM, "PKT_TX_IP_CKSUM" },
+	{ PKT_TX_TCP_CKSUM, "PKT_TX_TCP_CKSUM" },
+	{ PKT_TX_SCTP_CKSUM, "PKT_TX_SCTP_CKSUM" },
+	{ PKT_TX_UDP_CKSUM, "PKT_TX_UDP_CKSUM" },
+	{ PKT_TX_IEEE1588_TMST, "PKT_TX_IEEE1588_TMST" },
+	{ PKT_TX_TCP_SEG, "PKT_TX_TCP_SEG" },
+	{ PKT_TX_IPV4, "PKT_TX_IPV4" },
+	{ PKT_TX_IPV6, "PKT_TX_IPV6" },
+	{ PKT_TX_OUTER_IP_CKSUM, "PKT_TX_OUTER_IP_CKSUM" },
+	{ PKT_TX_OUTER_IPV4, "PKT_TX_OUTER_IPV4" },
+	{ PKT_TX_OUTER_IPV6, "PKT_TX_OUTER_IPV6" },
+	{ PKT_TX_TUNNEL_VXLAN, "PKT_TX_TUNNEL_VXLAN" },
+	{ PKT_TX_TUNNEL_GRE,  "PKT_TX_TUNNEL_GRE" },
+	{ PKT_TX_TUNNEL_IPIP, "PKT_TX_TUNNEL_IPIP" },
+	{ PKT_TX_TUNNEL_GENEVE,  "PKT_TX_TUNNEL_GENEVE" },
+	{ PKT_TX_TUNNEL_MPLSINUDP, "PKT_TX_TUNNEL_MPLSINUDP" },
+	{ PKT_TX_TUNNEL_VXLAN_GPE, "PKT_TX_TUNNEL_VXLAN_GPE" },
+	{ PKT_TX_TUNNEL_IP, "PKT_TX_TUNNEL_IP" },
+	{ PKT_TX_TUNNEL_UDP, "PKT_TX_TUNNEL_UDP" },
+	{ PKT_TX_QINQ, "PKT_TX_QINQ" },
+	{ PKT_TX_MACSEC, "PKT_TX_MACSEC" },
+	{ PKT_TX_SEC_OFFLOAD, "PKT_TX_SEC_OFFLOAD" },
+	{ PKT_TX_UDP_SEG, "PKT_TX_UDP_SEG" },
+	{ PKT_TX_OUTER_UDP_CKSUM, "PKT_TX_OUTER_UDP_CKSUM" },
+	{ PKT_TX_METADATA, "PKT_TX_METADATA" },
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(tx_flags); i++) {
+		flag_str = rte_get_tx_ol_flag_name(tx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s: Expected flagname = %s; received null\n",
+				__func__, tx_flags[i].name);
+		if (strcmp(flag_str, tx_flags[i].name) != 0)
+			GOTO_FAIL("%s: Expected flagname = %s; received = %s\n",
+				__func__, tx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_tx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s: Expected flag name = null; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+
+}
+
 static int
 test_mbuf_validate_tx_offload(const char *test_name,
 		struct rte_mempool *pktmbuf_pool,
@@ -1830,6 +2070,26 @@ test_mbuf(void)
 		goto err;
 	}
 
+	if (test_get_rx_ol_flag_list() < 0) {
+		printf("test_rte_get_rx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_list() < 0) {
+		printf("test_rte_get_tx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_rx_ol_flag_name() < 0) {
+		printf("test_rte_get_rx_ol_flag_name() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_name() < 0) {
+		printf("test_rte_get_tx_ol_flag_name() failed\n");
+		goto err;
+	}
+
 	/* test to validate tx offload flags */
 	uint64_t ol_flags = 0;
 	/* test to validate if IP checksum is counted only for IPV4 packet */
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs
  2019-07-22 13:32   ` Govindarajan, LavanyaX
@ 2019-08-13 10:26     ` Govindarajan, LavanyaX
  2019-08-22 11:21       ` Govindarajan, LavanyaX
  0 siblings, 1 reply; 22+ messages in thread
From: Govindarajan, LavanyaX @ 2019-08-13 10:26 UTC (permalink / raw)
  To: Olivier Matz; +Cc: dev, Pattan, Reshma, Richardson, Bruce

Hi,

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Govindarajan,
> LavanyaX
> Sent: Monday, July 22, 2019 7:02 PM
> To: Olivier Matz <olivier.matz@6wind.com>
> Cc: dev@dpdk.org; Pattan, Reshma <reshma.pattan@intel.com>; Richardson,
> Bruce <bruce.richardson@intel.com>
> Subject: Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library
> APIs
> 
> Hi
> 
> > -----Original Message-----
> > From: Olivier Matz [mailto:olivier.matz@6wind.com]
> > Sent: Monday, June 3, 2019 2:10 PM
> > To: Govindarajan, LavanyaX <lavanyax.govindarajan@intel.com>
> > Cc: dev@dpdk.org; Pattan, Reshma <reshma.pattan@intel.com>;
> > Richardson, Bruce <bruce.richardson@intel.com>
> > Subject: Re: [PATCH] app/test: add unit test cases for mbuf library
> > APIs
> >
> > Hi Lavanya,
> >
> > Please find some comments inline.
> >
> > On Mon, Apr 15, 2019 at 01:40:15PM +0100, Lavanya Govindarajan wrote:
> > > added new unit test cases for
> > > rte_validate_tx_offload,
> > > rte_pktmbuf_alloc_bulk,
> > > rte_pktmbuf_read,
> > > rte_pktmbuf_ext_shinfo_init_helper,
> > > rte_pktmbuf_attach_extbuf,
> > > rte_mbuf_ext_refcnt_read,
> > > rte_mbuf_ext_refcnt_update,
> > > rte_mbuf_ext_refcnt_set,
> > > rte_pktmbuf_detach_extbuf
> > >
> > > Signed-off-by: Lavanya Govindarajan
> > > <lavanyax.govindarajan@intel.com>
> > > ---
> > >  app/test/test_mbuf.c | 820
> > > ++++++++++++++++++++++++++++++++++++++++++-
> > >  1 file changed, 817 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c index
> > > 030385ec5..74259b313 100644
> > > --- a/app/test/test_mbuf.c
> > > +++ b/app/test/test_mbuf.c
> >
> 
> <snip>
> 
> > > +/*
> > > + * Test for allocating a bulk of mbufs
> > > + * define an array with positive sizes for mbufs allocations.
> > > + */
> > > +static int
> > > +test_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool) {
> > > +	int ret = 0;
> > > +	unsigned int idx, loop;
> > > +	unsigned int alloc_counts[] = {
> > > +		0,
> > > +		MEMPOOL_CACHE_SIZE - 1,
> > > +		MEMPOOL_CACHE_SIZE,
> > > +		MEMPOOL_CACHE_SIZE + 1,
> > > +		MEMPOOL_CACHE_SIZE * 1.5,
> > > +		MEMPOOL_CACHE_SIZE * 2,
> > > +		MEMPOOL_CACHE_SIZE * 2 - 1,
> > > +		MEMPOOL_CACHE_SIZE * 2 + 1,
> > > +		89,                         /* random number */
> > > +		MEMPOOL_CACHE_SIZE          /* repeat cache size */
> > > +	};
> >
> > instead of testing these particular values, why not testing every
> > values between
> > 0 and NB_MBUF ?
> 
> Testing every value from 0, 1, 2.. NB_MBUF(128 here)  dilutes the purpose of
> testing bulk allocation of mbufs from the same pool.
> Boundary conditions and some random values are targeted which will cover
> major cases.
> 
> The behavior is different for different set of values based on the availability of
> free mbufs in the cache or from the ring.
> 
> <snip>
> 
> > > +/*
> > > + * Test to initialize shared data in external buffer before
> > > +attaching to mbuf
> > > + *  - Allocate mbuf with no data.
> > > + *  - Allocate external buffer with size should be large enough to
> > accommodate
> > > + *     rte_mbuf_ext_shared_info.
> > > + *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
> > > + *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the
> mbuf.
> > > + *  - Clone another mbuf and attach the same external buffer to it.
> > > + *  - Invoke rte_pktmbuf_detach_extbuf to detach the external
> > > + buffer from
> > mbuf.
> > > + */
> > > +static int
> > > +test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool
> > > +*pktmbuf_pool) {
> > > +	struct rte_mbuf *m = NULL;
> > > +	struct rte_mbuf *clone = NULL;
> > > +	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
> > > +	rte_iova_t buf_iova;
> > > +	void *ext_buf_addr = NULL;
> > > +	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
> > > +				sizeof(struct rte_mbuf_ext_shared_info);
> > > +
> > > +	/* alloc a mbuf */
> > > +	m = rte_pktmbuf_alloc(pktmbuf_pool);
> > > +	if (m == NULL)
> > > +		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
> > > +	if (rte_pktmbuf_pkt_len(m) != 0)
> > > +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> > > +	rte_mbuf_sanity_check(m, 0);
> > > +
> > > +	ext_buf_addr = rte_malloc("External buffer", buf_len,
> > > +			RTE_CACHE_LINE_SIZE);
> > > +	if (ext_buf_addr == NULL)
> > > +		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
> > > +
> > > +	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr,
> > &buf_len,
> > > +		ext_buf_free_callback_fn, ext_buf_addr);
> > > +	if (ret_shinfo == NULL)
> > > +		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
> > > +
> > > +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
> > > +		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
> > > +
> > > +	if (rte_mbuf_refcnt_read(m) != 1)
> > > +		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
> > > +
> > > +	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
> > > +	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
> > > +		ret_shinfo);
> > > +	if (m->ol_flags != EXT_ATTACHED_MBUF)
> > > +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> > > +				__func__);
> > > +
> > > +	/* allocate one more mbuf */
> > > +	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> > > +	if (clone == NULL)
> > > +		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
> > > +	if (rte_pktmbuf_pkt_len(clone) != 0)
> > > +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> > > +
> > > +	/* attach the same external buffer to the cloned mbuf */
> > > +	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> > > +			ret_shinfo);
> >
> > Instead of:
> >
> >   clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> >   rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> >                  ret_shinfo);     /*  << useless */
> >
> The purpose of the above lines is to test if external buffer can be attached to the
> cloned mbuf or not.
> 
> > I'd prefer:
> >   m2 = rte_pktmbuf_alloc(pktmbuf_pool);
> >   rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> >                  ret_shinfo);
> Do you mean, m2 in the above line?
> 
> >
> > Or just:
> >   clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> >
> Can you please provide more clarity in the above suggestion.
> 
> >
> >
> > > +	if (clone->ol_flags != EXT_ATTACHED_MBUF)
> > > +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> > > +				__func__);
> > > +
> 
> <snip>
> 
> Regards
> Lavanya G

New patchset for mbuf UT has been raised.
1/2 - Addresses the review comments from Olivier
http://patches.dpdk.org/patch/57595/
2/2 - Added UT cases for rte_mbuf.h
http://patches.dpdk.org/patch/57596/

Could you please review the above patchset.

Thanks
Lavanya G

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs
  2019-08-13 10:26     ` Govindarajan, LavanyaX
@ 2019-08-22 11:21       ` Govindarajan, LavanyaX
  0 siblings, 0 replies; 22+ messages in thread
From: Govindarajan, LavanyaX @ 2019-08-22 11:21 UTC (permalink / raw)
  To: Olivier Matz; +Cc: dev, Pattan, Reshma, Richardson, Bruce

Hi

> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Govindarajan,
> LavanyaX
> Sent: Tuesday, August 13, 2019 3:56 PM
> To: Olivier Matz <olivier.matz@6wind.com>
> Cc: dev@dpdk.org; Pattan, Reshma <reshma.pattan@intel.com>; Richardson,
> Bruce <bruce.richardson@intel.com>
> Subject: Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library
> APIs
> 
> Hi,
> 
> > -----Original Message-----
> > From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Govindarajan,
> > LavanyaX
> > Sent: Monday, July 22, 2019 7:02 PM
> > To: Olivier Matz <olivier.matz@6wind.com>
> > Cc: dev@dpdk.org; Pattan, Reshma <reshma.pattan@intel.com>;
> > Richardson, Bruce <bruce.richardson@intel.com>
> > Subject: Re: [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf
> > library APIs
> >
> > Hi
> >
> > > -----Original Message-----
> > > From: Olivier Matz [mailto:olivier.matz@6wind.com]
> > > Sent: Monday, June 3, 2019 2:10 PM
> > > To: Govindarajan, LavanyaX <lavanyax.govindarajan@intel.com>
> > > Cc: dev@dpdk.org; Pattan, Reshma <reshma.pattan@intel.com>;
> > > Richardson, Bruce <bruce.richardson@intel.com>
> > > Subject: Re: [PATCH] app/test: add unit test cases for mbuf library
> > > APIs
> > >
> > > Hi Lavanya,
> > >
> > > Please find some comments inline.
> > >
> > > On Mon, Apr 15, 2019 at 01:40:15PM +0100, Lavanya Govindarajan wrote:
> > > > added new unit test cases for
> > > > rte_validate_tx_offload,
> > > > rte_pktmbuf_alloc_bulk,
> > > > rte_pktmbuf_read,
> > > > rte_pktmbuf_ext_shinfo_init_helper,
> > > > rte_pktmbuf_attach_extbuf,
> > > > rte_mbuf_ext_refcnt_read,
> > > > rte_mbuf_ext_refcnt_update,
> > > > rte_mbuf_ext_refcnt_set,
> > > > rte_pktmbuf_detach_extbuf
> > > >
> > > > Signed-off-by: Lavanya Govindarajan
> > > > <lavanyax.govindarajan@intel.com>
> > > > ---
> > > >  app/test/test_mbuf.c | 820
> > > > ++++++++++++++++++++++++++++++++++++++++++-
> > > >  1 file changed, 817 insertions(+), 3 deletions(-)
> > > >
> > > > diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c index
> > > > 030385ec5..74259b313 100644
> > > > --- a/app/test/test_mbuf.c
> > > > +++ b/app/test/test_mbuf.c
> > >
> >
> > <snip>
> >
> > > > +/*
> > > > + * Test for allocating a bulk of mbufs
> > > > + * define an array with positive sizes for mbufs allocations.
> > > > + */
> > > > +static int
> > > > +test_rte_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool) {
> > > > +	int ret = 0;
> > > > +	unsigned int idx, loop;
> > > > +	unsigned int alloc_counts[] = {
> > > > +		0,
> > > > +		MEMPOOL_CACHE_SIZE - 1,
> > > > +		MEMPOOL_CACHE_SIZE,
> > > > +		MEMPOOL_CACHE_SIZE + 1,
> > > > +		MEMPOOL_CACHE_SIZE * 1.5,
> > > > +		MEMPOOL_CACHE_SIZE * 2,
> > > > +		MEMPOOL_CACHE_SIZE * 2 - 1,
> > > > +		MEMPOOL_CACHE_SIZE * 2 + 1,
> > > > +		89,                         /* random number */
> > > > +		MEMPOOL_CACHE_SIZE          /* repeat cache size */
> > > > +	};
> > >
> > > instead of testing these particular values, why not testing every
> > > values between
> > > 0 and NB_MBUF ?
> >
> > Testing every value from 0, 1, 2.. NB_MBUF(128 here)  dilutes the
> > purpose of testing bulk allocation of mbufs from the same pool.
> > Boundary conditions and some random values are targeted which will
> > cover major cases.
> >
> > The behavior is different for different set of values based on the
> > availability of free mbufs in the cache or from the ring.
> >
> > <snip>
> >
> > > > +/*
> > > > + * Test to initialize shared data in external buffer before
> > > > +attaching to mbuf
> > > > + *  - Allocate mbuf with no data.
> > > > + *  - Allocate external buffer with size should be large enough
> > > > +to
> > > accommodate
> > > > + *     rte_mbuf_ext_shared_info.
> > > > + *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
> > > > + *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer
> > > > + to the
> > mbuf.
> > > > + *  - Clone another mbuf and attach the same external buffer to it.
> > > > + *  - Invoke rte_pktmbuf_detach_extbuf to detach the external
> > > > + buffer from
> > > mbuf.
> > > > + */
> > > > +static int
> > > > +test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool
> > > > +*pktmbuf_pool) {
> > > > +	struct rte_mbuf *m = NULL;
> > > > +	struct rte_mbuf *clone = NULL;
> > > > +	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
> > > > +	rte_iova_t buf_iova;
> > > > +	void *ext_buf_addr = NULL;
> > > > +	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
> > > > +				sizeof(struct rte_mbuf_ext_shared_info);
> > > > +
> > > > +	/* alloc a mbuf */
> > > > +	m = rte_pktmbuf_alloc(pktmbuf_pool);
> > > > +	if (m == NULL)
> > > > +		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
> > > > +	if (rte_pktmbuf_pkt_len(m) != 0)
> > > > +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> > > > +	rte_mbuf_sanity_check(m, 0);
> > > > +
> > > > +	ext_buf_addr = rte_malloc("External buffer", buf_len,
> > > > +			RTE_CACHE_LINE_SIZE);
> > > > +	if (ext_buf_addr == NULL)
> > > > +		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
> > > > +
> > > > +	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr,
> > > &buf_len,
> > > > +		ext_buf_free_callback_fn, ext_buf_addr);
> > > > +	if (ret_shinfo == NULL)
> > > > +		GOTO_FAIL("%s: Shared info initialization failed!\n",
> > > > +__func__);
> > > > +
> > > > +	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
> > > > +		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
> > > > +
> > > > +	if (rte_mbuf_refcnt_read(m) != 1)
> > > > +		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
> > > > +
> > > > +	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
> > > > +	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
> > > > +		ret_shinfo);
> > > > +	if (m->ol_flags != EXT_ATTACHED_MBUF)
> > > > +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> > > > +				__func__);
> > > > +
> > > > +	/* allocate one more mbuf */
> > > > +	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> > > > +	if (clone == NULL)
> > > > +		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
> > > > +	if (rte_pktmbuf_pkt_len(clone) != 0)
> > > > +		GOTO_FAIL("%s: Bad packet length\n", __func__);
> > > > +
> > > > +	/* attach the same external buffer to the cloned mbuf */
> > > > +	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> > > > +			ret_shinfo);
> > >
> > > Instead of:
> > >
> > >   clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> > >   rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> > >                  ret_shinfo);     /*  << useless */
> > >
> > The purpose of the above lines is to test if external buffer can be
> > attached to the cloned mbuf or not.
> >
> > > I'd prefer:
> > >   m2 = rte_pktmbuf_alloc(pktmbuf_pool);
> > >   rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
> > >                  ret_shinfo);
> > Do you mean, m2 in the above line?
> >
> > >
> > > Or just:
> > >   clone = rte_pktmbuf_clone(m, pktmbuf_pool);
> > >
> > Can you please provide more clarity in the above suggestion.
> >
> > >
> > >
> > > > +	if (clone->ol_flags != EXT_ATTACHED_MBUF)
> > > > +		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
> > > > +				__func__);
> > > > +
> >
> > <snip>
> >
> > Regards
> > Lavanya G
> 
> New patchset for mbuf UT has been raised.
> 1/2 - Addresses the review comments from Olivier
> http://patches.dpdk.org/patch/57595/
> 2/2 - Added UT cases for rte_mbuf.h
> http://patches.dpdk.org/patch/57596/
> 
> Could you please review the above patchset.
> 
> Thanks
> Lavanya G

Kindly review the above patchset.

Thanks in advance.
Lavanya G

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
@ 2019-08-26  8:47       ` Olivier Matz
  2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 0/2] add unit test cases for mbuf library Lavanya Govindarajan
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 22+ messages in thread
From: Olivier Matz @ 2019-08-26  8:47 UTC (permalink / raw)
  To: Lavanya Govindarajan
  Cc: dev, reshma.pattan, bruce.richardson, pallantlax.poornima

Hi,

Few minor comments below. You can add my ack in the v5 once fixed.

On Thu, Aug 08, 2019 at 02:34:19PM +0100, Lavanya Govindarajan wrote:
> Added new unit test cases to cover the below
> functions defined in rte_mbuf.h
> rte_validate_tx_offload,
> rte_pktmbuf_alloc_bulk,
> rte_pktmbuf_read,
> rte_pktmbuf_ext_shinfo_init_helper,
> rte_pktmbuf_attach_extbuf,
> rte_mbuf_ext_refcnt_read,
> rte_mbuf_ext_refcnt_update,
> rte_mbuf_ext_refcnt_set,
> rte_pktmbuf_detach_extbuf
> 
> Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
> Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
> ---
>  app/test/test_mbuf.c | 756 ++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 753 insertions(+), 3 deletions(-)

[...]

> +/*
> + * Negative testing for allocating a bulk of mbufs
> + */
> +static int
> +test_neg_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
> +{
> +	int loop, ret = 0;
> +	unsigned int idx;
> +	int neg_alloc_counts[] = {
> +		MEMPOOL_CACHE_SIZE - NB_MBUF,
> +		NB_MBUF + 1,
> +		NB_MBUF * 8,
> +		UINT_MAX
> +	};

It should be unsigned int instead of int.

> +	struct rte_mbuf *mbufs[NB_MBUF * 8] = { 0 };
> +
> +	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
> +		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
> +				neg_alloc_counts[idx]);
> +		if (ret == 0) {
> +			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
> +					__func__, neg_alloc_counts[idx], ret);
> +			for (loop = 0; loop < neg_alloc_counts[idx] &&
> +					mbufs[loop] != NULL; loop++)
> +				rte_pktmbuf_free(mbufs[loop]);
> +			return -1;
> +		}
> +	}
> +	return 0;
> +}

[...]

> +static int
> +test_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
> +{
> +	struct rte_mbuf *m;
> +	/* add testcases with different segments len, offset and read len */
> +	struct test_case test_cases[] = {
> +		{ .seg_lengths = { 100, 100, 100 },
> +	    .seg_count = 3,
> +	    .flags = MBUF_NO_HEADER,
> +	    .read_off = 0, .read_len = 300 },
> +		{ .seg_lengths = { 100, 125, 150 },
> +	    .seg_count = 3,
> +	    .flags = MBUF_NO_HEADER,
> +	    .read_off = 99, .read_len = 201 },
> +		{ .seg_lengths = { 100, 100 },
> +	    .seg_count = 2,
> +	    .flags = MBUF_NO_HEADER,
> +	    .read_off = 0,
> +	    .read_len = 100 },
> +		{ .seg_lengths = { 100, 200 },
> +	    .seg_count = 2,
> +	    .flags = MBUF_HEADER,
> +	    .read_off = sizeof(struct rte_ether_hdr),
> +	    .read_len = 150 },
> +		{ .seg_lengths = { 1000, 100 },
> +	    .seg_count = 2,
> +	    .flags = MBUF_NO_HEADER,
> +	    .read_off = 0,
> +	    .read_len = 1000 },
> +		{ .seg_lengths = { 1024, 0, 100 },
> +	    .seg_count = 3,
> +	    .flags = MBUF_NO_HEADER,
> +	    .read_off = 100,
> +	    .read_len = 1001 },
> +		{ .seg_lengths = { 1000, 1, 1000 },
> +	    .seg_count = 3,
> +	    .flags = MBUF_NO_HEADER,
> +	    .read_off = 1000,
> +	    .read_len = 2 },
> +		{ .seg_lengths = { MBUF_TEST_DATA_LEN, MBUF_TEST_DATA_LEN2,
> +			     MBUF_TEST_DATA_LEN3, 800, 10 },
> +		.seg_count = 5,
> +		.flags = MBUF_NEG_TEST_READ,
> +		.read_off = 1000,
> +			.read_len = MBUF_DATA_SIZE },
> +	};

The indentation is not very clear.

What about:

	struct test_case test_cases[] = {
		{
			.seg_lengths = { 100, 100, 100 },
			.seg_count = 3,
			.flags = MBUF_NO_HEADER,
			.read_off = 0,
			.read_len = 300,
		},
		{
			.seg_lengths = { 100, 125, 150 },
			.seg_count = 3,
			.flags = MBUF_NO_HEADER,
			.read_off = 99,
			.read_len = 201,
		},
		...

Or, if you prefer something shorter:

	struct test_case test_cases[] = {
		/* seg_lengths, seg_count, flags, read_off, read_len */
		{ { 100, 100, 100 }, 3, MBUF_NO_HEADER, 0, 300, },
		{ { 100, 125, 150 }, 3, MBUF_NO_HEADER, 99, 201, },
		...

[...]

>  test_mbuf(void)
>  {
> @@ -1133,7 +1736,8 @@ test_mbuf(void)
>  
>  	/* create pktmbuf pool if it does not exist */
>  	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
> -			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
> +			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
> +			SOCKET_ID_ANY);
>  
>  	if (pktmbuf_pool == NULL) {
>  		printf("cannot allocate mbuf pool\n");
> @@ -1143,7 +1747,8 @@ test_mbuf(void)
>  	/* create a specific pktmbuf pool with a priv_size != 0 and no data
>  	 * room size */
>  	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
> -			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
> +			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
> +			SOCKET_ID_ANY);
>  
>  	if (pktmbuf_pool2 == NULL) {
>  		printf("cannot allocate mbuf pool\n");
> @@ -1225,6 +1830,150 @@ test_mbuf(void)
>  		goto err;
>  	}
>  
> +	/* test to validate tx offload flags */
> +	uint64_t ol_flags = 0;
> +	/* test to validate if IP checksum is counted only for IPV4 packet */
> +	/* set both IP checksum and IPV6 flags */
> +	ol_flags |= PKT_TX_IP_CKSUM;
> +	ol_flags |= PKT_TX_IPV6;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_CKSUM_IPV6_SET",
> +				pktmbuf_pool,
> +				ol_flags, 0, -EINVAL) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	/* resetting ol_flags for next testcase */
> +	ol_flags = 0;
> +
> +	/* test to validate if IP type is set when required */
> +	ol_flags |= PKT_TX_L4_MASK;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
> +				pktmbuf_pool,
> +				ol_flags, 0, -EINVAL) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	/* test if IP type is set when TCP SEG is on */
> +	ol_flags |= PKT_TX_TCP_SEG;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
> +				pktmbuf_pool,
> +				ol_flags, 0, -EINVAL) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	ol_flags = 0;
> +	/* test to confirm IP type (IPV4/IPV6) is set */
> +	ol_flags = PKT_TX_L4_MASK;
> +	ol_flags |= PKT_TX_IPV6;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_SET",
> +				pktmbuf_pool,
> +				ol_flags, 0, 0) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	ol_flags = 0;
> +	/* test to check TSO segment size is non-zero */
> +	ol_flags |= PKT_TX_IPV4;
> +	ol_flags |= PKT_TX_TCP_SEG;
> +	/* set 0 tso segment size */
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_NULL_TSO_SEGSZ",
> +				pktmbuf_pool,
> +				ol_flags, 0, -EINVAL) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	/* retain IPV4 and PKT_TX_TCP_SEG mask */
> +	/* set valid tso segment size but IP CKSUM not set */
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_NOT_SET",
> +				pktmbuf_pool,
> +				ol_flags, 512, -EINVAL) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	/* test to validate if IP checksum is set for TSO capability */
> +	/* retain IPV4, TCP_SEG, tso_seg size */
> +	ol_flags |= PKT_TX_IP_CKSUM;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_SET",
> +				pktmbuf_pool,
> +				ol_flags, 512, 0) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	/* test to confirm TSO for IPV6 type */
> +	ol_flags = 0;
> +	ol_flags |= PKT_TX_IPV6;
> +	ol_flags |= PKT_TX_TCP_SEG;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IPV6_SET",
> +				pktmbuf_pool,
> +				ol_flags, 512, 0) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	ol_flags = 0;
> +	/* test if outer IP checksum set for non outer IPv4 packet */
> +	ol_flags |= PKT_TX_IPV6;
> +	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_NOT_SET",
> +				pktmbuf_pool,
> +				ol_flags, 512, -EINVAL) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	ol_flags = 0;
> +	/* test to confirm outer IP checksum is set for outer IPV4 packet */
> +	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
> +	ol_flags |= PKT_TX_OUTER_IPV4;
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_SET",
> +				pktmbuf_pool,
> +				ol_flags, 512, 0) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}
> +	ol_flags = 0;
> +	/* test to confirm if packets with no TX_OFFLOAD_MASK are skipped */
> +	if (test_mbuf_validate_tx_offload("MBUF_TEST_OL_MASK_NOT_SET",
> +				pktmbuf_pool,
> +				ol_flags, 512, 0) < 0) {
> +		printf("%d:test_mbuf_validate_tx_offload() failed\n", __LINE__);
> +		goto err;
> +	}

All the test_mbuf_validate_tx_offload() should be grouped in one function.

Maybe rename the current test_mbuf_validate_tx_offload() as
test_mbuf_validate_tx_offload_one()?


Thanks,
Olivier

^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH v4 2/2] app/test: add unit test cases to mbuf
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
@ 2019-08-26  9:09       ` Olivier Matz
  0 siblings, 0 replies; 22+ messages in thread
From: Olivier Matz @ 2019-08-26  9:09 UTC (permalink / raw)
  To: Lavanya Govindarajan
  Cc: dev, reshma.pattan, bruce.richardson, pallantlax.poornima

On Thu, Aug 08, 2019 at 02:34:20PM +0100, Lavanya Govindarajan wrote:
> From: Pallantla Poornima <pallantlax.poornima@intel.com@intel.com>
> 
> Added UT for the below four functions in test_mbuf.c
> rte_get_rx_ol_flag_list
> rte_get_tx_ol_flag_list
> rte_get_rx_ol_flag_name
> rte_get_tx_ol_flag_name
> 
> Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com@intel.com>

I suggest to change the patch title from
"app/test: add unit test cases to mbuf"
to
"app/test: add unit test for mbuf flag names"

> ---
>  app/test/test_mbuf.c | 260 +++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 260 insertions(+)
> 
> diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
> index 28f3216c0..1a943518d 100644
> --- a/app/test/test_mbuf.c
> +++ b/app/test/test_mbuf.c
> @@ -42,6 +42,7 @@
>  #define MBUF_TEST_DATA_LEN3     256
>  #define MBUF_TEST_HDR1_LEN      20
>  #define MBUF_TEST_HDR2_LEN      30
> +#define MBUF_TEST_LEN           250
>  #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
>  #define MBUF_TEST_SEG_SIZE      64
>  #define MBUF_TEST_BURST         8
> @@ -1132,6 +1133,245 @@ test_tx_offload(void)
>  	return (v1 == v2) ? 0 : -EINVAL;
>  }
>  
> +
> +static int
> +test_get_rx_ol_flag_list(void)
> +{
> +	int len, ret = 0;
> +	char buf[256] = "";
> +	int buflen = 0;
> +
> +	/* Test case to check with null buffer */
> +	ret = rte_get_rx_ol_flag_list(0, NULL, 0);
> +	if (ret != -1)
> +		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
> +
> +	/* Test case to check with zero buffer len */
> +	ret = rte_get_rx_ol_flag_list(PKT_RX_L4_CKSUM_MASK, buf, 0);
> +	if (ret != -1)
> +		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
> +
> +	buflen = strlen(buf);
> +	if (buflen != 0)
> +		GOTO_FAIL("%s buffer should be empty, received = %d\n",
> +				__func__, buflen);
> +
> +	/* Test case to check with reduced buffer len */
> +	len = sizeof(buf) - MBUF_TEST_LEN;
> +	ret = rte_get_rx_ol_flag_list(0, buf, len);

Why using a #define for MBUF_TEST_LEN and not for char buf[256]?
Also, MBUF_TEST_LEN is not a very clear name.

So, I'd prefer to have an hardcoded value:

	len = 5;
	ret = rte_get_rx_ol_flag_list(0, buf, len);


> +	if (ret != -1)
> +		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
> +
> +	buflen = strlen(buf);
> +	if (buflen != (len - 1))
> +		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
> +				"received = %d\n", __func__,
> +				(len - 1), buflen);
> +
> +	/* Test case to check with zero mask value */
> +	ret = rte_get_rx_ol_flag_list(0, buf, sizeof(buf));
> +	if (ret != 0)
> +		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
> +
> +	buflen = strlen(buf);
> +	if (buflen == 0)
> +		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
> +				"non-zero, buffer should not be empty");
> +
> +	/* Test case to check with valid mask value */
> +	ret = rte_get_rx_ol_flag_list(PKT_RX_SEC_OFFLOAD, buf, sizeof(buf));
> +	if (ret != 0)
> +		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
> +
> +	buflen = strlen(buf);
> +	if (buflen == 0)
> +		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
> +				"non-zero, buffer should not be empty");
> +
> +
> +	return 0;
> +fail:
> +	return -1;
> +}
> +
> +static int
> +test_get_tx_ol_flag_list(void)
> +{

Same comment as rx.

[...]

> +struct flag_name {
> +	uint64_t flag;
> +	const char *name;
> +};
> +
> +static int
> +test_get_rx_ol_flag_name(void)
> +{
> +	uint16_t i;
> +	const char *flag_str = NULL;
> +	const struct flag_name rx_flags[] = {
> +		{ PKT_RX_VLAN, "PKT_RX_VLAN" },
> +		{ PKT_RX_RSS_HASH, "PKT_RX_RSS_HASH" },
> +		{ PKT_RX_FDIR, "PKT_RX_FDIR"},
> +		{ PKT_RX_L4_CKSUM_BAD, "PKT_RX_L4_CKSUM_BAD"},
> +		{ PKT_RX_L4_CKSUM_GOOD, "PKT_RX_L4_CKSUM_GOOD"},
> +		{ PKT_RX_L4_CKSUM_NONE, "PKT_RX_L4_CKSUM_NONE"},
> +		{ PKT_RX_IP_CKSUM_BAD, "PKT_RX_IP_CKSUM_BAD"},
> +		{ PKT_RX_IP_CKSUM_GOOD, "PKT_RX_IP_CKSUM_GOOD"},
> +		{ PKT_RX_IP_CKSUM_NONE, "PKT_RX_IP_CKSUM_NONE"},
> +		{ PKT_RX_EIP_CKSUM_BAD, "PKT_RX_EIP_CKSUM_BAD" },
> +		{ PKT_RX_VLAN_STRIPPED, "PKT_RX_VLAN_STRIPPED" },
> +		{ PKT_RX_IEEE1588_PTP, "PKT_RX_IEEE1588_PTP"},
> +		{ PKT_RX_IEEE1588_TMST, "PKT_RX_IEEE1588_TMST"},
> +		{ PKT_RX_FDIR_ID, "PKT_RX_FDIR_ID"},
> +		{ PKT_RX_FDIR_FLX, "PKT_RX_FDIR_FLX"},
> +		{ PKT_RX_QINQ_STRIPPED, "PKT_RX_QINQ_STRIPPED" },
> +		{ PKT_RX_LRO, "PKT_RX_LRO" },
> +		{ PKT_RX_TIMESTAMP, "PKT_RX_TIMESTAMP"},
> +		{ PKT_RX_SEC_OFFLOAD, "PKT_RX_SEC_OFFLOAD" },
> +		{ PKT_RX_SEC_OFFLOAD_FAILED, "PKT_RX_SEC_OFFLOAD_FAILED" },
> +		{ PKT_RX_OUTER_L4_CKSUM_BAD, "PKT_RX_OUTER_L4_CKSUM_BAD" },
> +		{ PKT_RX_OUTER_L4_CKSUM_GOOD, "PKT_RX_OUTER_L4_CKSUM_GOOD"},
> +		{ PKT_RX_OUTER_L4_CKSUM_INVALID,
> +			"PKT_RX_OUTER_L4_CKSUM_INVALID" },
> +	};

Since flag value and name are the same, why not using a #define
to ensure there is no typo? Something like this:

#define VAL_NAME(flag) { flag, #flag }
	const struct flag_name rx_flags[] = {
		VAL_NAME(PKT_RX_VLAN),
		VAL_NAME(PKT_RX_RSS_HASH),
		...

It makes me think that the same thing could be done in rte_mbuf.c
instead... in this case the test would become overkill.

[...]

> +static int
> +test_get_tx_ol_flag_name(void)
> +{

Same comment as rx.

Thanks,
Olivier

^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v5 0/2] add unit test cases for mbuf library
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-08-26  8:47       ` Olivier Matz
@ 2019-08-30 14:13       ` Lavanya Govindarajan
  2019-10-24  7:54         ` David Marchand
  2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 2/2] app/test: add unit test for mbuf flag names Lavanya Govindarajan
  3 siblings, 1 reply; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-08-30 14:13 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	jananeex.m.parthasarathy, pallantlax.poornima,
	Lavanya Govindarajan

This patchset contains unit testcases added to increase the
functional and decision coverage for the library functions
defined in rte_mbuf.h and rte_mbuf.c

1/2: unit test cases added for rte_mbuf.h
2/2: unit test cases added for rte_mbuf.c

Patch 2/2 depends on 1/2

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
Acked-by: Olivier Matz <olivier.matz@6wind.com>
---
v5: Made minor coding improvisations as suggested.

v4: Fixed cosmetic errors.

v3: Fixed build issue for environment FD30-64.
Improvised error log messages.

v2: Addressed v1's comments.
Removed rte prefix from the test function names.
Fixed comments given for the below test functions
test_mbuf_validate_tx_offload
test_neg_pktmbuf_alloc_bulk
test_pktmbuf_read_from_offset
test_pktmbuf_read_from_chain
---

Lavanya Govindarajan (1):
  app/test: add unit test cases for mbuf library APIs

Pallantla Poornima (1):
  app/test: add unit test for mbuf flag names

 app/test/test_mbuf.c | 1030 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 1027 insertions(+), 3 deletions(-)

-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v5 1/2] app/test: add unit test cases for mbuf library APIs
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
  2019-08-26  8:47       ` Olivier Matz
  2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 0/2] add unit test cases for mbuf library Lavanya Govindarajan
@ 2019-08-30 14:13       ` Lavanya Govindarajan
  2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 2/2] app/test: add unit test for mbuf flag names Lavanya Govindarajan
  3 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-08-30 14:13 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	jananeex.m.parthasarathy, pallantlax.poornima,
	Lavanya Govindarajan

Added new unit test cases to cover the below
functions defined in rte_mbuf.h
rte_validate_tx_offload,
rte_pktmbuf_alloc_bulk,
rte_pktmbuf_read,
rte_pktmbuf_ext_shinfo_init_helper,
rte_pktmbuf_attach_extbuf,
rte_mbuf_ext_refcnt_read,
rte_mbuf_ext_refcnt_update,
rte_mbuf_ext_refcnt_set,
rte_pktmbuf_detach_extbuf

Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
---
 app/test/test_mbuf.c | 773 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 770 insertions(+), 3 deletions(-)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 2a97afe20..346d9ede4 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -28,16 +28,28 @@
 #include <rte_random.h>
 #include <rte_cycles.h>
 #include <rte_malloc.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_tcp.h>
 
 #include "test.h"
 
+#define MEMPOOL_CACHE_SIZE      32
 #define MBUF_DATA_SIZE          2048
 #define NB_MBUF                 128
 #define MBUF_TEST_DATA_LEN      1464
 #define MBUF_TEST_DATA_LEN2     50
+#define MBUF_TEST_DATA_LEN3     256
 #define MBUF_TEST_HDR1_LEN      20
 #define MBUF_TEST_HDR2_LEN      30
 #define MBUF_TEST_ALL_HDRS_LEN  (MBUF_TEST_HDR1_LEN+MBUF_TEST_HDR2_LEN)
+#define MBUF_TEST_SEG_SIZE      64
+#define MBUF_TEST_BURST         8
+#define EXT_BUF_TEST_DATA_LEN   1024
+#define MBUF_MAX_SEG            16
+#define MBUF_NO_HEADER		0
+#define MBUF_HEADER		1
+#define MBUF_NEG_TEST_READ	2
 
 /* size of private data for mbuf in pktmbuf_pool2 */
 #define MBUF2_PRIV_SIZE         128
@@ -502,7 +514,6 @@ test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool,
 		rte_pktmbuf_free(clone2);
 	return -1;
 }
-#undef GOTO_FAIL
 
 /*
  * test allocation and free of mbufs
@@ -1121,6 +1132,718 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+static int
+test_mbuf_validate_tx_offload(const char *test_name,
+		struct rte_mempool *pktmbuf_pool,
+		uint64_t ol_flags,
+		uint16_t segsize,
+		int expected_retval)
+{
+	struct rte_mbuf *m = NULL;
+	int ret = 0;
+	/* alloc a mbuf and do sanity check */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+	m->ol_flags = ol_flags;
+	m->tso_segsz = segsize;
+	ret = rte_validate_tx_offload(m);
+	if (ret != expected_retval)
+		GOTO_FAIL("%s(%s): expected ret val: %d; received: %d\n",
+				__func__, test_name, expected_retval, ret);
+	rte_pktmbuf_free(m);
+	m = NULL;
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+static int
+test_mbuf_validate_tx_offload_one(struct rte_mempool *pktmbuf_pool)
+{
+	/* test to validate tx offload flags */
+	uint64_t ol_flags = 0;
+	/* test to validate if IP checksum is counted only for IPV4 packet */
+	/* set both IP checksum and IPV6 flags */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_CKSUM_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0)
+		GOTO_FAIL("%s failed: IP cksum is set incorrect.\n", __func__);
+	/* resetting ol_flags for next testcase */
+	ol_flags = 0;
+
+	/* test to validate if IP type is set when required */
+	ol_flags |= PKT_TX_L4_MASK;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0)
+		GOTO_FAIL("%s failed: IP type is not set.\n", __func__);
+
+	/* test if IP type is set when TCP SEG is on */
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0)
+		GOTO_FAIL("%s failed: IP type is not set.\n", __func__);
+
+	ol_flags = 0;
+	/* test to confirm IP type (IPV4/IPV6) is set */
+	ol_flags = PKT_TX_L4_MASK;
+	ol_flags |= PKT_TX_IPV6;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_IP_TYPE_SET",
+				pktmbuf_pool,
+				ol_flags, 0, 0) < 0)
+		GOTO_FAIL("%s failed: tx offload flag error.\n", __func__);
+
+	ol_flags = 0;
+	/* test to check TSO segment size is non-zero */
+	ol_flags |= PKT_TX_IPV4;
+	ol_flags |= PKT_TX_TCP_SEG;
+	/* set 0 tso segment size */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_NULL_TSO_SEGSZ",
+				pktmbuf_pool,
+				ol_flags, 0, -EINVAL) < 0)
+		GOTO_FAIL("%s failed: tso segment size is null.\n", __func__);
+
+	/* retain IPV4 and PKT_TX_TCP_SEG mask */
+	/* set valid tso segment size but IP CKSUM not set */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0)
+		GOTO_FAIL("%s failed: IP CKSUM is not set.\n", __func__);
+
+	/* test to validate if IP checksum is set for TSO capability */
+	/* retain IPV4, TCP_SEG, tso_seg size */
+	ol_flags |= PKT_TX_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IP_CKSUM_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0)
+		GOTO_FAIL("%s failed: tx offload flag error.\n", __func__);
+
+	/* test to confirm TSO for IPV6 type */
+	ol_flags = 0;
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_TCP_SEG;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_TSO_IPV6_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0)
+		GOTO_FAIL("%s failed: TSO req not met.\n", __func__);
+
+	ol_flags = 0;
+	/* test if outer IP checksum set for non outer IPv4 packet */
+	ol_flags |= PKT_TX_IPV6;
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, -EINVAL) < 0)
+		GOTO_FAIL("%s failed: Outer IP cksum set.\n", __func__);
+
+	ol_flags = 0;
+	/* test to confirm outer IP checksum is set for outer IPV4 packet */
+	ol_flags |= PKT_TX_OUTER_IP_CKSUM;
+	ol_flags |= PKT_TX_OUTER_IPV4;
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OUTER_IPV4_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0)
+		GOTO_FAIL("%s failed: tx offload flag error.\n", __func__);
+
+	ol_flags = 0;
+	/* test to confirm if packets with no TX_OFFLOAD_MASK are skipped */
+	if (test_mbuf_validate_tx_offload("MBUF_TEST_OL_MASK_NOT_SET",
+				pktmbuf_pool,
+				ol_flags, 512, 0) < 0)
+		GOTO_FAIL("%s failed: tx offload flag error.\n", __func__);
+	return 0;
+fail:
+	return -1;
+}
+
+/*
+ * Test for allocating a bulk of mbufs
+ * define an array with positive sizes for mbufs allocations.
+ */
+static int
+test_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int ret = 0;
+	unsigned int idx, loop;
+	unsigned int alloc_counts[] = {
+		0,
+		MEMPOOL_CACHE_SIZE - 1,
+		MEMPOOL_CACHE_SIZE + 1,
+		MEMPOOL_CACHE_SIZE * 1.5,
+		MEMPOOL_CACHE_SIZE * 2,
+		MEMPOOL_CACHE_SIZE * 2 - 1,
+		MEMPOOL_CACHE_SIZE * 2 + 1,
+		MEMPOOL_CACHE_SIZE,
+	};
+
+	/* allocate a large array of mbuf pointers */
+	struct rte_mbuf *mbufs[NB_MBUF] = { 0 };
+	for (idx = 0; idx < RTE_DIM(alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				alloc_counts[idx]);
+		if (ret == 0) {
+			for (loop = 0; loop < alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+		} else if (ret != 0) {
+			printf("%s: Bulk alloc failed count(%u); ret val(%d)\n",
+					__func__, alloc_counts[idx], ret);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Negative testing for allocating a bulk of mbufs
+ */
+static int
+test_neg_pktmbuf_alloc_bulk(struct rte_mempool *pktmbuf_pool)
+{
+	int ret = 0;
+	unsigned int idx, loop;
+	unsigned int neg_alloc_counts[] = {
+		MEMPOOL_CACHE_SIZE - NB_MBUF,
+		NB_MBUF + 1,
+		NB_MBUF * 8,
+		UINT_MAX
+	};
+	struct rte_mbuf *mbufs[NB_MBUF * 8] = { 0 };
+
+	for (idx = 0; idx < RTE_DIM(neg_alloc_counts); idx++) {
+		ret = rte_pktmbuf_alloc_bulk(pktmbuf_pool, mbufs,
+				neg_alloc_counts[idx]);
+		if (ret == 0) {
+			printf("%s: Bulk alloc must fail! count(%u); ret(%d)\n",
+					__func__, neg_alloc_counts[idx], ret);
+			for (loop = 0; loop < neg_alloc_counts[idx] &&
+					mbufs[loop] != NULL; loop++)
+				rte_pktmbuf_free(mbufs[loop]);
+			return -1;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Test to read mbuf packet using rte_pktmbuf_read
+ */
+static int
+test_pktmbuf_read(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	int off;
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	memset(data, 0xfe, MBUF_TEST_DATA_LEN2);
+
+	/* read the data from mbuf */
+	data_copy = rte_pktmbuf_read(m, 0, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xfe)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/*
+ * Test to read mbuf packet data from offset
+ */
+static int
+test_pktmbuf_read_from_offset(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct ether_hdr *hdr = NULL;
+	char *data = NULL;
+	const char *data_copy = NULL;
+	unsigned int off;
+	unsigned int hdr_len = sizeof(struct rte_ether_hdr);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	/* prepend an ethernet header */
+	hdr = (struct ether_hdr *)rte_pktmbuf_prepend(m, hdr_len);
+	if (hdr == NULL)
+		GOTO_FAIL("%s: Cannot prepend header\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad pkt length", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len)
+		GOTO_FAIL("%s: Bad data length", __func__);
+	memset(hdr, 0xde, hdr_len);
+
+	/* read mbuf header info from 0 offset */
+	data_copy = rte_pktmbuf_read(m, 0, hdr_len, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header!\n", __func__);
+	for (off = 0; off < hdr_len; off++) {
+		if (data_copy[off] != (char)0xde)
+			GOTO_FAIL("Header info corrupted at offset %u", off);
+	}
+
+	/* append sample data after ethernet header */
+	data = rte_pktmbuf_append(m, MBUF_TEST_DATA_LEN2);
+	if (data == NULL)
+		GOTO_FAIL("%s: Cannot append data\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	if (rte_pktmbuf_data_len(m) != hdr_len + MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Bad data length\n", __func__);
+	memset(data, 0xcc, MBUF_TEST_DATA_LEN2);
+
+	/* read mbuf data after header info */
+	data_copy = rte_pktmbuf_read(m, hdr_len, MBUF_TEST_DATA_LEN2, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading header data!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* partial reading of mbuf data */
+	data_copy = rte_pktmbuf_read(m, hdr_len + 5, MBUF_TEST_DATA_LEN2 - 5,
+			NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2 - 5)
+		GOTO_FAIL("%s: Incorrect data length!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2 - 5; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read length greater than mbuf data_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_data_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf data len!\n",
+				__func__);
+
+	/* read length greater than mbuf pkt_len */
+	if (rte_pktmbuf_read(m, hdr_len, rte_pktmbuf_pkt_len(m) + 1,
+				NULL) != NULL)
+		GOTO_FAIL("%s: Requested len is larger than mbuf pkt len!\n",
+				__func__);
+
+	/* read data of zero len from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	if (strlen(data_copy) != MBUF_TEST_DATA_LEN2)
+		GOTO_FAIL("%s: Corrupted data content!\n", __func__);
+	for (off = 0; off < MBUF_TEST_DATA_LEN2; off++) {
+		if (data_copy[off] != (char)0xcc)
+			GOTO_FAIL("Data corrupted at offset %u", off);
+	}
+
+	/* read data of zero length from zero offset */
+	data_copy = rte_pktmbuf_read(m, 0, 0, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of header info */
+	if (hdr != (const struct ether_hdr *)data_copy)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* read data of max length from valid offset */
+	data_copy = rte_pktmbuf_read(m, hdr_len, UINT_MAX, NULL);
+	if (data_copy == NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+	/* check if the received address is the beginning of data segment */
+	if (data_copy != data)
+		GOTO_FAIL("%s: Corrupted data address!\n", __func__);
+
+	/* try to read from mbuf with max size offset */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, 0, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	/* try to read from mbuf with max size offset and len */
+	data_copy = rte_pktmbuf_read(m, UINT_MAX, UINT_MAX, NULL);
+	if (data_copy != NULL)
+		GOTO_FAIL("%s: Error in reading packet data!\n", __func__);
+
+	rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+
+	return 0;
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+struct test_case {
+	unsigned int seg_count;
+	unsigned int flags;
+	uint32_t read_off;
+	uint32_t read_len;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+};
+
+/* create a mbuf with different sized segments
+ *  and fill with data [0x00 0x01 0x02 ...]
+ */
+static struct rte_mbuf *
+create_packet(struct rte_mempool *pktmbuf_pool,
+		struct test_case *test_data)
+{
+	uint16_t i, ret, seg, seg_len = 0;
+	uint32_t last_index = 0;
+	unsigned int seg_lengths[MBUF_MAX_SEG];
+	unsigned int hdr_len;
+	struct rte_mbuf *pkt = NULL;
+	struct rte_mbuf	*pkt_seg = NULL;
+	char *hdr = NULL;
+	char *data = NULL;
+	memcpy(seg_lengths, test_data->seg_lengths,
+			sizeof(unsigned int)*test_data->seg_count);
+	for (seg = 0; seg < test_data->seg_count; seg++) {
+		hdr_len = 0;
+		seg_len =  seg_lengths[seg];
+		pkt_seg = rte_pktmbuf_alloc(pktmbuf_pool);
+		if (pkt_seg == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != 0)
+			GOTO_FAIL("%s: Bad packet length\n", __func__);
+		rte_mbuf_sanity_check(pkt_seg, 0);
+		/* Add header only for the first segment */
+		if (test_data->flags == MBUF_HEADER && seg == 0) {
+			hdr_len = sizeof(struct rte_ether_hdr);
+			/* prepend a header and fill with dummy data */
+			hdr = (char *)rte_pktmbuf_prepend(pkt_seg, hdr_len);
+			if (hdr == NULL)
+				GOTO_FAIL("%s: Cannot prepend header\n",
+						__func__);
+			if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad pkt length", __func__);
+			if (rte_pktmbuf_data_len(pkt_seg) != hdr_len)
+				GOTO_FAIL("%s: Bad data length", __func__);
+			for (i = 0; i < hdr_len; i++)
+				hdr[i] = (last_index + i) % 0xffff;
+			last_index += hdr_len;
+		}
+		/* skip appending segment with 0 length */
+		if (seg_len == 0)
+			continue;
+		data = rte_pktmbuf_append(pkt_seg, seg_len);
+		if (data == NULL)
+			GOTO_FAIL("%s: Cannot append data segment\n", __func__);
+		if (rte_pktmbuf_pkt_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad packet segment length: %d\n",
+					__func__, rte_pktmbuf_pkt_len(pkt_seg));
+		if (rte_pktmbuf_data_len(pkt_seg) != hdr_len + seg_len)
+			GOTO_FAIL("%s: Bad data length\n", __func__);
+		for (i = 0; i < seg_len; i++)
+			data[i] = (last_index + i) % 0xffff;
+		/* to fill continuous data from one seg to another */
+		last_index += i;
+		/* create chained mbufs */
+		if (seg == 0)
+			pkt = pkt_seg;
+		else {
+			ret = rte_pktmbuf_chain(pkt, pkt_seg);
+			if (ret != 0)
+				GOTO_FAIL("%s:FAIL: Chained mbuf creation %d\n",
+						__func__, ret);
+		}
+
+		pkt_seg = pkt_seg->next;
+	}
+	return pkt;
+fail:
+	if (pkt != NULL) {
+		rte_pktmbuf_free(pkt);
+		pkt = NULL;
+	}
+	if (pkt_seg != NULL) {
+		rte_pktmbuf_free(pkt_seg);
+		pkt_seg = NULL;
+	}
+	return NULL;
+}
+
+static int
+test_pktmbuf_read_from_chain(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m;
+	struct test_case test_cases[] = {
+		{
+			.seg_lengths = { 100, 100, 100 },
+			.seg_count = 3,
+			.flags = MBUF_NO_HEADER,
+			.read_off = 0,
+			.read_len = 300
+		},
+		{
+			.seg_lengths = { 100, 125, 150 },
+			.seg_count = 3,
+			.flags = MBUF_NO_HEADER,
+			.read_off = 99,
+			.read_len = 201
+		},
+		{
+			.seg_lengths = { 100, 100 },
+			.seg_count = 2,
+			.flags = MBUF_NO_HEADER,
+			.read_off = 0,
+			.read_len = 100
+		},
+		{
+			.seg_lengths = { 100, 200 },
+			.seg_count = 2,
+			.flags = MBUF_HEADER,
+			.read_off = sizeof(struct rte_ether_hdr),
+			.read_len = 150
+		},
+		{
+			.seg_lengths = { 1000, 100 },
+			.seg_count = 2,
+			.flags = MBUF_NO_HEADER,
+			.read_off = 0,
+			.read_len = 1000
+		},
+		{
+			.seg_lengths = { 1024, 0, 100 },
+			.seg_count = 3,
+			.flags = MBUF_NO_HEADER,
+			.read_off = 100,
+			.read_len = 1001
+		},
+		{
+			.seg_lengths = { 1000, 1, 1000 },
+			.seg_count = 3,
+			.flags = MBUF_NO_HEADER,
+			.read_off = 1000,
+			.read_len = 2
+		},
+		{
+			.seg_lengths = { MBUF_TEST_DATA_LEN,
+					MBUF_TEST_DATA_LEN2,
+					MBUF_TEST_DATA_LEN3, 800, 10 },
+			.seg_count = 5,
+			.flags = MBUF_NEG_TEST_READ,
+			.read_off = 1000,
+			.read_len = MBUF_DATA_SIZE
+		},
+	};
+
+	uint32_t i, pos;
+	const char *data_copy = NULL;
+	char data_buf[MBUF_DATA_SIZE];
+	memset(data_buf, 0, MBUF_DATA_SIZE);
+
+	for (i = 0; i < RTE_DIM(test_cases); i++) {
+		m = create_packet(pktmbuf_pool, &test_cases[i]);
+		if (m == NULL)
+			GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+
+		data_copy = rte_pktmbuf_read(m, test_cases[i].read_off,
+				test_cases[i].read_len, data_buf);
+		if (test_cases[i].flags == MBUF_NEG_TEST_READ) {
+			if (data_copy != NULL)
+				GOTO_FAIL("%s: mbuf data read should fail!\n",
+						__func__);
+			else {
+				rte_pktmbuf_free(m);
+				m = NULL;
+				continue;
+			}
+		}
+		if (data_copy == NULL)
+			GOTO_FAIL("%s: Error in reading packet data!\n",
+					__func__);
+		for (pos = 0; pos < test_cases[i].read_len; pos++) {
+			if (data_copy[pos] !=
+					(char)((test_cases[i].read_off + pos)
+						% 0xffff))
+				GOTO_FAIL("Data corrupted at offset %u is %2X",
+						pos, data_copy[pos]);
+		}
+		rte_pktmbuf_dump(stdout, m, rte_pktmbuf_pkt_len(m));
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return 0;
+
+fail:
+	if (m != NULL) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	return -1;
+}
+
+/* Define a free call back function to be used for external buffer */
+static void
+ext_buf_free_callback_fn(void *addr __rte_unused, void *opaque)
+{
+	void *ext_buf_addr = opaque;
+	if (ext_buf_addr == NULL) {
+		printf("External buffer address is invalid\n");
+		return;
+	}
+	rte_free(ext_buf_addr);
+	ext_buf_addr = NULL;
+	printf("External buffer freed via callback\n");
+}
+
+/*
+ * Test to initialize shared data in external buffer before attaching to mbuf
+ *  - Allocate mbuf with no data.
+ *  - Allocate external buffer with size should be large enough to accommodate
+ *     rte_mbuf_ext_shared_info.
+ *  - Invoke pktmbuf_ext_shinfo_init_helper to initialize shared data.
+ *  - Invoke rte_pktmbuf_attach_extbuf to attach external buffer to the mbuf.
+ *  - Clone another mbuf and attach the same external buffer to it.
+ *  - Invoke rte_pktmbuf_detach_extbuf to detach the external buffer from mbuf.
+ */
+static int
+test_pktmbuf_ext_shinfo_init_helper(struct rte_mempool *pktmbuf_pool)
+{
+	struct rte_mbuf *m = NULL;
+	struct rte_mbuf *clone = NULL;
+	struct rte_mbuf_ext_shared_info *ret_shinfo = NULL;
+	rte_iova_t buf_iova;
+	void *ext_buf_addr = NULL;
+	uint16_t buf_len = EXT_BUF_TEST_DATA_LEN +
+				sizeof(struct rte_mbuf_ext_shared_info);
+
+	/* alloc a mbuf */
+	m = rte_pktmbuf_alloc(pktmbuf_pool);
+	if (m == NULL)
+		GOTO_FAIL("%s: mbuf allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(m) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+	rte_mbuf_sanity_check(m, 0);
+
+	ext_buf_addr = rte_malloc("External buffer", buf_len,
+			RTE_CACHE_LINE_SIZE);
+	if (ext_buf_addr == NULL)
+		GOTO_FAIL("%s: External buffer allocation failed\n", __func__);
+
+	ret_shinfo = rte_pktmbuf_ext_shinfo_init_helper(ext_buf_addr, &buf_len,
+		ext_buf_free_callback_fn, ext_buf_addr);
+	if (ret_shinfo == NULL)
+		GOTO_FAIL("%s: Shared info initialization failed!\n", __func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: External refcount is not 1\n", __func__);
+
+	if (rte_mbuf_refcnt_read(m) != 1)
+		GOTO_FAIL("%s: Invalid refcnt in mbuf\n", __func__);
+
+	buf_iova = rte_mempool_virt2iova(ext_buf_addr);
+	rte_pktmbuf_attach_extbuf(m, ext_buf_addr, buf_iova, buf_len,
+		ret_shinfo);
+	if (m->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	/* allocate one more mbuf */
+	clone = rte_pktmbuf_clone(m, pktmbuf_pool);
+	if (clone == NULL)
+		GOTO_FAIL("%s: mbuf clone allocation failed!\n", __func__);
+	if (rte_pktmbuf_pkt_len(clone) != 0)
+		GOTO_FAIL("%s: Bad packet length\n", __func__);
+
+	/* attach the same external buffer to the cloned mbuf */
+	rte_pktmbuf_attach_extbuf(clone, ext_buf_addr, buf_iova, buf_len,
+			ret_shinfo);
+	if (clone->ol_flags != EXT_ATTACHED_MBUF)
+		GOTO_FAIL("%s: External buffer is not attached to mbuf\n",
+				__func__);
+
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	/* test to manually update ext_buf_ref_cnt from 2 to 3*/
+	rte_mbuf_ext_refcnt_update(ret_shinfo, 1);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 3)
+		GOTO_FAIL("%s: Update ext_buf ref_cnt failed\n", __func__);
+
+	/* reset the ext_refcnt before freeing the external buffer */
+	rte_mbuf_ext_refcnt_set(ret_shinfo, 2);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 2)
+		GOTO_FAIL("%s: set ext_buf ref_cnt failed\n", __func__);
+
+	/* detach the external buffer from mbufs */
+	rte_pktmbuf_detach_extbuf(m);
+	/* check if ref cnt is decremented */
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 1)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_detach_extbuf(clone);
+	if (rte_mbuf_ext_refcnt_read(ret_shinfo) != 0)
+		GOTO_FAIL("%s: Invalid ext_buf ref_cnt\n", __func__);
+
+	rte_pktmbuf_free(m);
+	m = NULL;
+	rte_pktmbuf_free(clone);
+	clone = NULL;
+
+	return 0;
+
+fail:
+	if (m) {
+		rte_pktmbuf_free(m);
+		m = NULL;
+	}
+	if (clone) {
+		rte_pktmbuf_free(clone);
+		clone = NULL;
+	}
+	if (ext_buf_addr != NULL) {
+		rte_free(ext_buf_addr);
+		ext_buf_addr = NULL;
+	}
+	return -1;
+}
+
 static int
 test_mbuf(void)
 {
@@ -1133,7 +1856,8 @@ test_mbuf(void)
 
 	/* create pktmbuf pool if it does not exist */
 	pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool",
-			NB_MBUF, 32, 0, MBUF_DATA_SIZE, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1143,7 +1867,8 @@ test_mbuf(void)
 	/* create a specific pktmbuf pool with a priv_size != 0 and no data
 	 * room size */
 	pktmbuf_pool2 = rte_pktmbuf_pool_create("test_pktmbuf_pool2",
-			NB_MBUF, 32, MBUF2_PRIV_SIZE, 0, SOCKET_ID_ANY);
+			NB_MBUF, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0,
+			SOCKET_ID_ANY);
 
 	if (pktmbuf_pool2 == NULL) {
 		printf("cannot allocate mbuf pool\n");
@@ -1225,6 +1950,47 @@ test_mbuf(void)
 		goto err;
 	}
 
+	if (test_mbuf_validate_tx_offload_one(pktmbuf_pool) < 0) {
+		printf("test_mbuf_validate_tx_offload_one() failed\n");
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test for allocating a bulk of mbufs with various sizes */
+	if (test_neg_pktmbuf_alloc_bulk(pktmbuf_pool) < 0) {
+		printf("test_neg_rte_pktmbuf_alloc_bulk() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet */
+	if (test_pktmbuf_read(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read() failed\n");
+		goto err;
+	}
+
+	/* test to read mbuf packet from offset */
+	if (test_pktmbuf_read_from_offset(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_offset() failed\n");
+		goto err;
+	}
+
+	/* test to read data from chain of mbufs with data segments */
+	if (test_pktmbuf_read_from_chain(pktmbuf_pool) < 0) {
+		printf("test_rte_pktmbuf_read_from_chain() failed\n");
+		goto err;
+	}
+
+	/* test to initialize shared info. at the end of external buffer */
+	if (test_pktmbuf_ext_shinfo_init_helper(pktmbuf_pool) < 0) {
+		printf("test_pktmbuf_ext_shinfo_init_helper() failed\n");
+		goto err;
+	}
+
 	ret = 0;
 err:
 	rte_mempool_free(pktmbuf_pool);
@@ -1233,3 +1999,4 @@ test_mbuf(void)
 }
 
 REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);
+#undef GOTO_FAIL
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* [dpdk-dev] [PATCH v5 2/2] app/test: add unit test for mbuf flag names
  2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
                         ` (2 preceding siblings ...)
  2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
@ 2019-08-30 14:13       ` Lavanya Govindarajan
  3 siblings, 0 replies; 22+ messages in thread
From: Lavanya Govindarajan @ 2019-08-30 14:13 UTC (permalink / raw)
  To: dev
  Cc: reshma.pattan, olivier.matz, bruce.richardson,
	jananeex.m.parthasarathy, pallantlax.poornima

From: Pallantla Poornima <pallantlax.poornima@intel.com>

Added UT for the below four functions in test_mbuf.c
rte_get_rx_ol_flag_list
rte_get_tx_ol_flag_list
rte_get_rx_ol_flag_name
rte_get_tx_ol_flag_name

Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
---
 app/test/test_mbuf.c | 257 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 257 insertions(+)

diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c
index 346d9ede4..dd1bc25e6 100644
--- a/app/test/test_mbuf.c
+++ b/app/test/test_mbuf.c
@@ -50,6 +50,7 @@
 #define MBUF_NO_HEADER		0
 #define MBUF_HEADER		1
 #define MBUF_NEG_TEST_READ	2
+#define VAL_NAME(flag)          { flag, #flag }
 
 /* size of private data for mbuf in pktmbuf_pool2 */
 #define MBUF2_PRIV_SIZE         128
@@ -1132,6 +1133,242 @@ test_tx_offload(void)
 	return (v1 == v2) ? 0 : -EINVAL;
 }
 
+static int
+test_get_rx_ol_flag_list(void)
+{
+	int len = 6, ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_rx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_L4_CKSUM_MASK, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0)
+		GOTO_FAIL("%s buffer should be empty, received = %d\n",
+				__func__, buflen);
+
+	/* Test case to check with reduced buffer len */
+	ret = rte_get_rx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received = %d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_rx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_rx_ol_flag_list(PKT_RX_SEC_OFFLOAD, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_list(void)
+{
+	int len = 6, ret = 0;
+	char buf[256] = "";
+	int buflen = 0;
+
+	/* Test case to check with null buffer */
+	ret = rte_get_tx_ol_flag_list(0, NULL, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	/* Test case to check with zero buffer len */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_IP_CKSUM, buf, 0);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != 0) {
+		GOTO_FAIL("%s buffer should be empty, received = %d\n",
+				__func__, buflen);
+	}
+
+	/* Test case to check with reduced buffer len */
+	ret = rte_get_tx_ol_flag_list(0, buf, len);
+	if (ret != -1)
+		GOTO_FAIL("%s expected: -1, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen != (len - 1))
+		GOTO_FAIL("%s invalid buffer length retrieved, expected: %d,"
+				"received = %d\n", __func__,
+				(len - 1), buflen);
+
+	/* Test case to check with zero mask value */
+	ret = rte_get_tx_ol_flag_list(0, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	/* Test case to check with valid mask value */
+	ret = rte_get_tx_ol_flag_list(PKT_TX_UDP_CKSUM, buf, sizeof(buf));
+	if (ret != 0)
+		GOTO_FAIL("%s expected: 0, received = %d\n", __func__, ret);
+
+	buflen = strlen(buf);
+	if (buflen == 0)
+		GOTO_FAIL("%s expected: %s, received length = 0\n", __func__,
+				"non-zero, buffer should not be empty");
+
+	return 0;
+fail:
+	return -1;
+
+}
+
+struct flag_name {
+	uint64_t flag;
+	const char *name;
+};
+
+static int
+test_get_rx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name rx_flags[] = {
+
+		VAL_NAME(PKT_RX_VLAN),
+		VAL_NAME(PKT_RX_RSS_HASH),
+		VAL_NAME(PKT_RX_FDIR),
+		VAL_NAME(PKT_RX_L4_CKSUM_BAD),
+		VAL_NAME(PKT_RX_L4_CKSUM_GOOD),
+		VAL_NAME(PKT_RX_L4_CKSUM_NONE),
+		VAL_NAME(PKT_RX_IP_CKSUM_BAD),
+		VAL_NAME(PKT_RX_IP_CKSUM_GOOD),
+		VAL_NAME(PKT_RX_IP_CKSUM_NONE),
+		VAL_NAME(PKT_RX_EIP_CKSUM_BAD),
+		VAL_NAME(PKT_RX_VLAN_STRIPPED),
+		VAL_NAME(PKT_RX_IEEE1588_PTP),
+		VAL_NAME(PKT_RX_IEEE1588_TMST),
+		VAL_NAME(PKT_RX_FDIR_ID),
+		VAL_NAME(PKT_RX_FDIR_FLX),
+		VAL_NAME(PKT_RX_QINQ_STRIPPED),
+		VAL_NAME(PKT_RX_LRO),
+		VAL_NAME(PKT_RX_TIMESTAMP),
+		VAL_NAME(PKT_RX_SEC_OFFLOAD),
+		VAL_NAME(PKT_RX_SEC_OFFLOAD_FAILED),
+		VAL_NAME(PKT_RX_OUTER_L4_CKSUM_BAD),
+		VAL_NAME(PKT_RX_OUTER_L4_CKSUM_GOOD),
+		VAL_NAME(PKT_RX_OUTER_L4_CKSUM_INVALID),
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(rx_flags); i++) {
+		flag_str = rte_get_rx_ol_flag_name(rx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s: Expected flagname = %s; received null\n",
+					__func__, rx_flags[i].name);
+		if (strcmp(flag_str, rx_flags[i].name) != 0)
+			GOTO_FAIL("%s: Expected flagname = %s; received = %s\n",
+				__func__, rx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_rx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s: Expected flag name = null; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+}
+
+static int
+test_get_tx_ol_flag_name(void)
+{
+	uint16_t i;
+	const char *flag_str = NULL;
+	const struct flag_name tx_flags[] = {
+
+		VAL_NAME(PKT_TX_VLAN),
+		VAL_NAME(PKT_TX_IP_CKSUM),
+		VAL_NAME(PKT_TX_TCP_CKSUM),
+		VAL_NAME(PKT_TX_SCTP_CKSUM),
+		VAL_NAME(PKT_TX_UDP_CKSUM),
+		VAL_NAME(PKT_TX_IEEE1588_TMST),
+		VAL_NAME(PKT_TX_TCP_SEG),
+		VAL_NAME(PKT_TX_IPV4),
+		VAL_NAME(PKT_TX_IPV6),
+		VAL_NAME(PKT_TX_OUTER_IP_CKSUM),
+		VAL_NAME(PKT_TX_OUTER_IPV4),
+		VAL_NAME(PKT_TX_OUTER_IPV6),
+		VAL_NAME(PKT_TX_TUNNEL_VXLAN),
+		VAL_NAME(PKT_TX_TUNNEL_GRE),
+		VAL_NAME(PKT_TX_TUNNEL_IPIP),
+		VAL_NAME(PKT_TX_TUNNEL_GENEVE),
+		VAL_NAME(PKT_TX_TUNNEL_MPLSINUDP),
+		VAL_NAME(PKT_TX_TUNNEL_VXLAN_GPE),
+		VAL_NAME(PKT_TX_TUNNEL_IP),
+		VAL_NAME(PKT_TX_TUNNEL_UDP),
+		VAL_NAME(PKT_TX_QINQ),
+		VAL_NAME(PKT_TX_MACSEC),
+		VAL_NAME(PKT_TX_SEC_OFFLOAD),
+		VAL_NAME(PKT_TX_UDP_SEG),
+		VAL_NAME(PKT_TX_OUTER_UDP_CKSUM),
+		VAL_NAME(PKT_TX_METADATA),
+	};
+
+	/* Test case to check with valid flag */
+	for (i = 0; i < RTE_DIM(tx_flags); i++) {
+		flag_str = rte_get_tx_ol_flag_name(tx_flags[i].flag);
+		if (flag_str == NULL)
+			GOTO_FAIL("%s: Expected flagname = %s; received null\n",
+				__func__, tx_flags[i].name);
+		if (strcmp(flag_str, tx_flags[i].name) != 0)
+			GOTO_FAIL("%s: Expected flagname = %s; received = %s\n",
+				__func__, tx_flags[i].name, flag_str);
+	}
+	/* Test case to check with invalid flag */
+	flag_str = rte_get_tx_ol_flag_name(0);
+	if (flag_str != NULL) {
+		GOTO_FAIL("%s: Expected flag name = null; received = %s\n",
+				__func__, flag_str);
+	}
+
+	return 0;
+fail:
+	return -1;
+
+}
+
 static int
 test_mbuf_validate_tx_offload(const char *test_name,
 		struct rte_mempool *pktmbuf_pool,
@@ -1950,6 +2187,26 @@ test_mbuf(void)
 		goto err;
 	}
 
+	if (test_get_rx_ol_flag_list() < 0) {
+		printf("test_rte_get_rx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_list() < 0) {
+		printf("test_rte_get_tx_ol_flag_list() failed\n");
+		goto err;
+	}
+
+	if (test_get_rx_ol_flag_name() < 0) {
+		printf("test_rte_get_rx_ol_flag_name() failed\n");
+		goto err;
+	}
+
+	if (test_get_tx_ol_flag_name() < 0) {
+		printf("test_rte_get_tx_ol_flag_name() failed\n");
+		goto err;
+	}
+
 	if (test_mbuf_validate_tx_offload_one(pktmbuf_pool) < 0) {
 		printf("test_mbuf_validate_tx_offload_one() failed\n");
 		goto err;
-- 
2.17.2


^ permalink raw reply	[flat|nested] 22+ messages in thread

* Re: [dpdk-dev] [PATCH v5 0/2] add unit test cases for mbuf library
  2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 0/2] add unit test cases for mbuf library Lavanya Govindarajan
@ 2019-10-24  7:54         ` David Marchand
  0 siblings, 0 replies; 22+ messages in thread
From: David Marchand @ 2019-10-24  7:54 UTC (permalink / raw)
  To: Lavanya Govindarajan
  Cc: dev, Pattan, Reshma, Olivier Matz, Bruce Richardson,
	Parthasarathy, JananeeX M, Pallantla Poornima

On Fri, Aug 30, 2019 at 4:14 PM Lavanya Govindarajan
<lavanyax.govindarajan@intel.com> wrote:
>
> This patchset contains unit testcases added to increase the
> functional and decision coverage for the library functions
> defined in rte_mbuf.h and rte_mbuf.c
>
> 1/2: unit test cases added for rte_mbuf.h
> 2/2: unit test cases added for rte_mbuf.c
>
> Patch 2/2 depends on 1/2
>
> Signed-off-by: Lavanya Govindarajan <lavanyax.govindarajan@intel.com>
> Signed-off-by: Pallantla Poornima <pallantlax.poornima@intel.com>
> Reviewed-by: Reshma Pattan <reshma.pattan@intel.com>
> Acked-by: Olivier Matz <olivier.matz@6wind.com>

Applied, thanks.


--
David Marchand


^ permalink raw reply	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2019-10-24  7:55 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-15 12:40 [dpdk-dev] [PATCH] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
2019-04-15 12:40 ` Lavanya Govindarajan
2019-05-31 10:45 ` Pattan, Reshma
2019-06-03  8:39 ` Olivier Matz
2019-07-22 13:32   ` Govindarajan, LavanyaX
2019-08-13 10:26     ` Govindarajan, LavanyaX
2019-08-22 11:21       ` Govindarajan, LavanyaX
2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 0/2] add unit test cases for mbuf library Lavanya Govindarajan
2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
2019-07-22 13:42 ` [dpdk-dev] [PATCH v2 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 0/2] add unit test cases for mbuf library Lavanya Govindarajan
2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 0/2] add unit test cases for mbuf library Lavanya Govindarajan
2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
2019-08-26  8:47       ` Olivier Matz
2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 0/2] add unit test cases for mbuf library Lavanya Govindarajan
2019-10-24  7:54         ` David Marchand
2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 1/2] app/test: add unit test cases for mbuf library APIs Lavanya Govindarajan
2019-08-30 14:13       ` [dpdk-dev] [PATCH v5 2/2] app/test: add unit test for mbuf flag names Lavanya Govindarajan
2019-08-08 13:34     ` [dpdk-dev] [PATCH v4 2/2] app/test: add unit test cases to mbuf Lavanya Govindarajan
2019-08-26  9:09       ` Olivier Matz
2019-07-23 12:14   ` [dpdk-dev] [PATCH v3 " Lavanya Govindarajan

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).