X-Git-Url: http://git.droids-corp.org/?p=dpdk.git;a=blobdiff_plain;f=app%2Ftest%2Ftest_mbuf.c;h=a96ba3fa11ef85d03062bb4d4c955d5566cb6165;hp=f4437340ea4fe1eba05ad79748be35693a1822ea;hb=a617494eeb01ff;hpb=21a7f4e2646e1cb6b0dbd6643e5d64f72355af58 diff --git a/app/test/test_mbuf.c b/app/test/test_mbuf.c index f4437340ea..a96ba3fa11 100644 --- a/app/test/test_mbuf.c +++ b/app/test/test_mbuf.c @@ -1,34 +1,5 @@ -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * * Neither the name of Intel Corporation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(c) 2010-2014 Intel Corporation */ #include @@ -41,14 +12,12 @@ #include #include +#include #include #include -#include #include #include -#include #include -#include #include #include #include @@ -59,33 +28,50 @@ #include #include #include +#include +#include +#include +#include +#include #include "test.h" -#define MBUF_SIZE 2048 +#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 +#define VAL_NAME(flag) { flag, #flag } + +/* chain length in bulk test */ +#define CHAIN_LEN 16 + +/* size of private data for mbuf in pktmbuf_pool2 */ +#define MBUF2_PRIV_SIZE 128 #define REFCNT_MAX_ITER 64 #define REFCNT_MAX_TIMEOUT 10 #define REFCNT_MAX_REF (RTE_MAX_LCORE) #define REFCNT_MBUF_NUM 64 -#define REFCNT_MBUF_SIZE (sizeof (struct rte_mbuf) + RTE_PKTMBUF_HEADROOM) #define REFCNT_RING_SIZE (REFCNT_MBUF_NUM * REFCNT_MAX_REF) -#define MAKE_STRING(x) # x +#define MAGIC_DATA 0x42424242 -static struct rte_mempool *pktmbuf_pool = NULL; -static struct rte_mempool *ctrlmbuf_pool = NULL; +#define MAKE_STRING(x) # x -#if defined RTE_MBUF_SCATTER_GATHER && defined RTE_MBUF_REFCNT_ATOMIC +#ifdef RTE_MBUF_REFCNT_ATOMIC -static struct rte_mempool *refcnt_pool = NULL; -static struct rte_ring *refcnt_mbuf_ring = NULL; static volatile uint32_t refcnt_stop_slaves; static unsigned refcnt_lcore[RTE_MAX_LCORE]; @@ -125,6 +111,10 @@ static unsigned refcnt_lcore[RTE_MAX_LCORE]; * - Repeat the test to check that allocation operations * reinitialize the mbuf correctly. * + * #. Test packet cloning + * - Clone a mbuf and verify the data + * - Clone the cloned mbuf and verify the data + * - Attach a mbuf to another that does not have the same priv_size. */ #define GOTO_FAIL(str, ...) do { \ @@ -137,7 +127,7 @@ static unsigned refcnt_lcore[RTE_MAX_LCORE]; * test data manipulation in mbuf with non-ascii data */ static int -test_pktmbuf_with_non_ascii_data(void) +test_pktmbuf_with_non_ascii_data(struct rte_mempool *pktmbuf_pool) { struct rte_mbuf *m = NULL; char *data; @@ -158,7 +148,7 @@ test_pktmbuf_with_non_ascii_data(void) memset(data, 0xff, rte_pktmbuf_pkt_len(m)); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); - rte_pktmbuf_dump(m, MBUF_TEST_DATA_LEN); + rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN); rte_pktmbuf_free(m); @@ -175,7 +165,7 @@ fail: * test data manipulation in mbuf */ static int -test_one_pktmbuf(void) +test_one_pktmbuf(struct rte_mempool *pktmbuf_pool) { struct rte_mbuf *m = NULL; char *data, *data2, *hdr; @@ -191,7 +181,7 @@ test_one_pktmbuf(void) if (rte_pktmbuf_pkt_len(m) != 0) GOTO_FAIL("Bad length"); - rte_pktmbuf_dump(m, 0); + rte_pktmbuf_dump(stdout, m, 0); /* append data */ @@ -205,8 +195,8 @@ test_one_pktmbuf(void) memset(data, 0x66, rte_pktmbuf_pkt_len(m)); if (!rte_pktmbuf_is_contiguous(m)) GOTO_FAIL("Buffer should be continuous"); - rte_pktmbuf_dump(m, MBUF_TEST_DATA_LEN); - rte_pktmbuf_dump(m, 2*MBUF_TEST_DATA_LEN); + rte_pktmbuf_dump(stdout, m, MBUF_TEST_DATA_LEN); + rte_pktmbuf_dump(stdout, m, 2*MBUF_TEST_DATA_LEN); /* this append should fail */ @@ -272,9 +262,9 @@ test_one_pktmbuf(void) GOTO_FAIL("Buffer should be continuous"); memset(hdr, 0x55, MBUF_TEST_HDR2_LEN); - rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 1); - rte_mbuf_sanity_check(m, RTE_MBUF_PKT, 0); - rte_pktmbuf_dump(m, 0); + rte_mbuf_sanity_check(m, 1); + rte_mbuf_sanity_check(m, 0); + rte_pktmbuf_dump(stdout, m, 0); /* this prepend should fail */ @@ -320,103 +310,390 @@ fail: return -1; } -/* - * test control mbuf - */ +static uint16_t +testclone_refcnt_read(struct rte_mbuf *m) +{ + return RTE_MBUF_HAS_PINNED_EXTBUF(m) ? + rte_mbuf_ext_refcnt_read(m->shinfo) : + rte_mbuf_refcnt_read(m); +} + static int -test_one_ctrlmbuf(void) +testclone_testupdate_testdetach(struct rte_mempool *pktmbuf_pool, + struct rte_mempool *clone_pool) { struct rte_mbuf *m = NULL; - char message[] = "This is a message carried by a ctrlmbuf"; - - printf("Test ctrlmbuf API\n"); + struct rte_mbuf *clone = NULL; + struct rte_mbuf *clone2 = NULL; + unaligned_uint32_t *data; /* alloc a mbuf */ - - m = rte_ctrlmbuf_alloc(ctrlmbuf_pool); + m = rte_pktmbuf_alloc(pktmbuf_pool); if (m == NULL) - GOTO_FAIL("Cannot allocate mbuf"); - if (rte_ctrlmbuf_len(m) != 0) + GOTO_FAIL("ooops not allocating mbuf"); + + if (rte_pktmbuf_pkt_len(m) != 0) GOTO_FAIL("Bad length"); - /* set data */ - rte_ctrlmbuf_data(m) = &message; - rte_ctrlmbuf_len(m) = sizeof(message); + rte_pktmbuf_append(m, sizeof(uint32_t)); + data = rte_pktmbuf_mtod(m, unaligned_uint32_t *); + *data = MAGIC_DATA; + + /* clone the allocated mbuf */ + clone = rte_pktmbuf_clone(m, clone_pool); + if (clone == NULL) + GOTO_FAIL("cannot clone data\n"); + + data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone\n"); + + if (testclone_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + /* free the clone */ + rte_pktmbuf_free(clone); + clone = NULL; + + /* same test with a chained mbuf */ + m->next = rte_pktmbuf_alloc(pktmbuf_pool); + if (m->next == NULL) + GOTO_FAIL("Next Pkt Null\n"); + m->nb_segs = 2; + + rte_pktmbuf_append(m->next, sizeof(uint32_t)); + m->pkt_len = 2 * sizeof(uint32_t); + + data = rte_pktmbuf_mtod(m->next, unaligned_uint32_t *); + *data = MAGIC_DATA; + + clone = rte_pktmbuf_clone(m, clone_pool); + if (clone == NULL) + GOTO_FAIL("cannot clone data\n"); + + data = rte_pktmbuf_mtod(clone, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone\n"); + + data = rte_pktmbuf_mtod(clone->next, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone->next\n"); + + if (testclone_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + if (testclone_refcnt_read(m->next) != 2) + GOTO_FAIL("invalid refcnt in m->next\n"); + + /* try to clone the clone */ + + clone2 = rte_pktmbuf_clone(clone, clone_pool); + if (clone2 == NULL) + GOTO_FAIL("cannot clone the clone\n"); - /* read data */ - if (rte_ctrlmbuf_data(m) != message) - GOTO_FAIL("Invalid data pointer"); - if (rte_ctrlmbuf_len(m) != sizeof(message)) - GOTO_FAIL("Invalid len"); + data = rte_pktmbuf_mtod(clone2, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone2\n"); - rte_mbuf_sanity_check(m, RTE_MBUF_CTRL, 0); + data = rte_pktmbuf_mtod(clone2->next, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone2->next\n"); + + if (testclone_refcnt_read(m) != 3) + GOTO_FAIL("invalid refcnt in m\n"); + + if (testclone_refcnt_read(m->next) != 3) + GOTO_FAIL("invalid refcnt in m->next\n"); /* free mbuf */ - rte_ctrlmbuf_free(m); + rte_pktmbuf_free(m); + rte_pktmbuf_free(clone); + rte_pktmbuf_free(clone2); + m = NULL; + clone = NULL; + clone2 = NULL; + printf("%s ok\n", __func__); return 0; fail: if (m) - rte_ctrlmbuf_free(m); + rte_pktmbuf_free(m); + if (clone) + rte_pktmbuf_free(clone); + if (clone2) + rte_pktmbuf_free(clone2); return -1; } static int -testclone_testupdate_testdetach(void) +test_pktmbuf_copy(struct rte_mempool *pktmbuf_pool, + struct rte_mempool *clone_pool) { -#ifndef RTE_MBUF_SCATTER_GATHER - return 0; -#else - struct rte_mbuf *mc = NULL; + struct rte_mbuf *m = NULL; + struct rte_mbuf *copy = NULL; + struct rte_mbuf *copy2 = NULL; struct rte_mbuf *clone = NULL; + unaligned_uint32_t *data; /* alloc a mbuf */ - - mc = rte_pktmbuf_alloc(pktmbuf_pool); - if (mc == NULL) + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) GOTO_FAIL("ooops not allocating mbuf"); - if (rte_pktmbuf_pkt_len(mc) != 0) + if (rte_pktmbuf_pkt_len(m) != 0) GOTO_FAIL("Bad length"); + rte_pktmbuf_append(m, sizeof(uint32_t)); + data = rte_pktmbuf_mtod(m, unaligned_uint32_t *); + *data = MAGIC_DATA; - /* clone the allocated mbuf */ - clone = rte_pktmbuf_clone(mc, pktmbuf_pool); + /* copy the allocated mbuf */ + copy = rte_pktmbuf_copy(m, pktmbuf_pool, 0, UINT32_MAX); + if (copy == NULL) + GOTO_FAIL("cannot copy data\n"); + + if (rte_pktmbuf_pkt_len(copy) != sizeof(uint32_t)) + GOTO_FAIL("copy length incorrect\n"); + + if (rte_pktmbuf_data_len(copy) != sizeof(uint32_t)) + GOTO_FAIL("copy data length incorrect\n"); + + data = rte_pktmbuf_mtod(copy, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in copy\n"); + + /* free the copy */ + rte_pktmbuf_free(copy); + copy = NULL; + + /* same test with a cloned mbuf */ + clone = rte_pktmbuf_clone(m, clone_pool); if (clone == NULL) GOTO_FAIL("cannot clone data\n"); + + if ((!RTE_MBUF_HAS_PINNED_EXTBUF(m) && + !RTE_MBUF_CLONED(clone)) || + (RTE_MBUF_HAS_PINNED_EXTBUF(m) && + !RTE_MBUF_HAS_EXTBUF(clone))) + GOTO_FAIL("clone did not give a cloned mbuf\n"); + + copy = rte_pktmbuf_copy(clone, pktmbuf_pool, 0, UINT32_MAX); + if (copy == NULL) + GOTO_FAIL("cannot copy cloned mbuf\n"); + + if (RTE_MBUF_CLONED(copy)) + GOTO_FAIL("copy of clone is cloned?\n"); + + if (rte_pktmbuf_pkt_len(copy) != sizeof(uint32_t)) + GOTO_FAIL("copy clone length incorrect\n"); + + if (rte_pktmbuf_data_len(copy) != sizeof(uint32_t)) + GOTO_FAIL("copy clone data length incorrect\n"); + + data = rte_pktmbuf_mtod(copy, unaligned_uint32_t *); + if (*data != MAGIC_DATA) + GOTO_FAIL("invalid data in clone copy\n"); rte_pktmbuf_free(clone); + rte_pktmbuf_free(copy); + copy = NULL; + clone = NULL; + - mc->pkt.next = rte_pktmbuf_alloc(pktmbuf_pool); - if(mc->pkt.next == NULL) + /* same test with a chained mbuf */ + m->next = rte_pktmbuf_alloc(pktmbuf_pool); + if (m->next == NULL) GOTO_FAIL("Next Pkt Null\n"); + m->nb_segs = 2; - clone = rte_pktmbuf_clone(mc, pktmbuf_pool); - if (clone == NULL) - GOTO_FAIL("cannot clone data\n"); + rte_pktmbuf_append(m->next, sizeof(uint32_t)); + m->pkt_len = 2 * sizeof(uint32_t); + data = rte_pktmbuf_mtod(m->next, unaligned_uint32_t *); + *data = MAGIC_DATA + 1; + + copy = rte_pktmbuf_copy(m, pktmbuf_pool, 0, UINT32_MAX); + if (copy == NULL) + GOTO_FAIL("cannot copy data\n"); + + if (rte_pktmbuf_pkt_len(copy) != 2 * sizeof(uint32_t)) + GOTO_FAIL("chain copy length incorrect\n"); + + if (rte_pktmbuf_data_len(copy) != 2 * sizeof(uint32_t)) + GOTO_FAIL("chain copy data length incorrect\n"); + + data = rte_pktmbuf_mtod(copy, unaligned_uint32_t *); + if (data[0] != MAGIC_DATA || data[1] != MAGIC_DATA + 1) + GOTO_FAIL("invalid data in copy\n"); + + rte_pktmbuf_free(copy2); + + /* test offset copy */ + copy2 = rte_pktmbuf_copy(copy, pktmbuf_pool, + sizeof(uint32_t), UINT32_MAX); + if (copy2 == NULL) + GOTO_FAIL("cannot copy the copy\n"); + + if (rte_pktmbuf_pkt_len(copy2) != sizeof(uint32_t)) + GOTO_FAIL("copy with offset, length incorrect\n"); + + if (rte_pktmbuf_data_len(copy2) != sizeof(uint32_t)) + GOTO_FAIL("copy with offset, data length incorrect\n"); + + data = rte_pktmbuf_mtod(copy2, unaligned_uint32_t *); + if (data[0] != MAGIC_DATA + 1) + GOTO_FAIL("copy with offset, invalid data\n"); + + rte_pktmbuf_free(copy2); + + /* test truncation copy */ + copy2 = rte_pktmbuf_copy(copy, pktmbuf_pool, + 0, sizeof(uint32_t)); + if (copy2 == NULL) + GOTO_FAIL("cannot copy the copy\n"); + + if (rte_pktmbuf_pkt_len(copy2) != sizeof(uint32_t)) + GOTO_FAIL("copy with truncate, length incorrect\n"); + + if (rte_pktmbuf_data_len(copy2) != sizeof(uint32_t)) + GOTO_FAIL("copy with truncate, data length incorrect\n"); + + data = rte_pktmbuf_mtod(copy2, unaligned_uint32_t *); + if (data[0] != MAGIC_DATA) + GOTO_FAIL("copy with truncate, invalid data\n"); /* free mbuf */ - rte_pktmbuf_free(mc); - rte_pktmbuf_free(clone); - mc = NULL; - clone = NULL; + rte_pktmbuf_free(m); + rte_pktmbuf_free(copy); + rte_pktmbuf_free(copy2); + + m = NULL; + copy = NULL; + copy2 = NULL; + printf("%s ok\n", __func__); return 0; fail: - if (mc) - rte_pktmbuf_free(mc); + if (m) + rte_pktmbuf_free(m); + if (copy) + rte_pktmbuf_free(copy); + if (copy2) + rte_pktmbuf_free(copy2); return -1; -#endif /* RTE_MBUF_SCATTER_GATHER */ } -#undef GOTO_FAIL +static int +test_attach_from_different_pool(struct rte_mempool *pktmbuf_pool, + struct rte_mempool *pktmbuf_pool2) +{ + struct rte_mbuf *m = NULL; + struct rte_mbuf *clone = NULL; + struct rte_mbuf *clone2 = NULL; + char *data, *c_data, *c_data2; + + /* alloc a mbuf */ + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) + GOTO_FAIL("cannot allocate mbuf"); + + if (rte_pktmbuf_pkt_len(m) != 0) + GOTO_FAIL("Bad length"); + + data = rte_pktmbuf_mtod(m, char *); + /* allocate a new mbuf from the second pool, and attach it to the first + * mbuf */ + clone = rte_pktmbuf_alloc(pktmbuf_pool2); + if (clone == NULL) + GOTO_FAIL("cannot allocate mbuf from second pool\n"); + + /* check data room size and priv size, and erase priv */ + if (rte_pktmbuf_data_room_size(clone->pool) != 0) + GOTO_FAIL("data room size should be 0\n"); + if (rte_pktmbuf_priv_size(clone->pool) != MBUF2_PRIV_SIZE) + GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE); + memset(clone + 1, 0, MBUF2_PRIV_SIZE); + + /* save data pointer to compare it after detach() */ + c_data = rte_pktmbuf_mtod(clone, char *); + if (c_data != (char *)clone + sizeof(*clone) + MBUF2_PRIV_SIZE) + GOTO_FAIL("bad data pointer in clone"); + if (rte_pktmbuf_headroom(clone) != 0) + GOTO_FAIL("bad headroom in clone"); + + rte_pktmbuf_attach(clone, m); + + if (rte_pktmbuf_mtod(clone, char *) != data) + GOTO_FAIL("clone was not attached properly\n"); + if (rte_pktmbuf_headroom(clone) != RTE_PKTMBUF_HEADROOM) + GOTO_FAIL("bad headroom in clone after attach"); + if (rte_mbuf_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + /* allocate a new mbuf from the second pool, and attach it to the first + * cloned mbuf */ + clone2 = rte_pktmbuf_alloc(pktmbuf_pool2); + if (clone2 == NULL) + GOTO_FAIL("cannot allocate clone2 from second pool\n"); + + /* check data room size and priv size, and erase priv */ + if (rte_pktmbuf_data_room_size(clone2->pool) != 0) + GOTO_FAIL("data room size should be 0\n"); + if (rte_pktmbuf_priv_size(clone2->pool) != MBUF2_PRIV_SIZE) + GOTO_FAIL("data room size should be %d\n", MBUF2_PRIV_SIZE); + memset(clone2 + 1, 0, MBUF2_PRIV_SIZE); + + /* save data pointer to compare it after detach() */ + c_data2 = rte_pktmbuf_mtod(clone2, char *); + if (c_data2 != (char *)clone2 + sizeof(*clone2) + MBUF2_PRIV_SIZE) + GOTO_FAIL("bad data pointer in clone2"); + if (rte_pktmbuf_headroom(clone2) != 0) + GOTO_FAIL("bad headroom in clone2"); + + rte_pktmbuf_attach(clone2, clone); + + if (rte_pktmbuf_mtod(clone2, char *) != data) + GOTO_FAIL("clone2 was not attached properly\n"); + if (rte_pktmbuf_headroom(clone2) != RTE_PKTMBUF_HEADROOM) + GOTO_FAIL("bad headroom in clone2 after attach"); + if (rte_mbuf_refcnt_read(m) != 3) + GOTO_FAIL("invalid refcnt in m\n"); + + /* detach the clones */ + rte_pktmbuf_detach(clone); + if (c_data != rte_pktmbuf_mtod(clone, char *)) + GOTO_FAIL("clone was not detached properly\n"); + if (rte_mbuf_refcnt_read(m) != 2) + GOTO_FAIL("invalid refcnt in m\n"); + + rte_pktmbuf_detach(clone2); + if (c_data2 != rte_pktmbuf_mtod(clone2, char *)) + GOTO_FAIL("clone2 was not detached properly\n"); + if (rte_mbuf_refcnt_read(m) != 1) + GOTO_FAIL("invalid refcnt in m\n"); + + /* free the clones and the initial mbuf */ + rte_pktmbuf_free(clone2); + rte_pktmbuf_free(clone); + rte_pktmbuf_free(m); + printf("%s ok\n", __func__); + return 0; + +fail: + if (m) + rte_pktmbuf_free(m); + if (clone) + rte_pktmbuf_free(clone); + if (clone2) + rte_pktmbuf_free(clone2); + return -1; +} /* * test allocation and free of mbufs */ static int -test_pktmbuf_pool(void) +test_pktmbuf_pool(struct rte_mempool *pktmbuf_pool) { unsigned i; struct rte_mbuf *m[NB_MBUF]; @@ -439,13 +716,11 @@ test_pktmbuf_pool(void) printf("Error pool not empty"); ret = -1; } -#ifdef RTE_MBUF_SCATTER_GATHER extra = rte_pktmbuf_clone(m[0], pktmbuf_pool); if(extra != NULL) { printf("Error pool not empty"); ret = -1; } -#endif /* free them */ for (i=0; ipkt.data = RTE_PTR_ADD(m[i]->pkt.data, 64); + m[i]->data_off += 64; } /* free them */ @@ -483,19 +928,20 @@ test_pktmbuf_pool_ptr(void) if (m[i] != NULL) rte_pktmbuf_free(m[i]); } - + for (i=0; ipkt.data != RTE_PTR_ADD(m[i]->buf_addr, RTE_PKTMBUF_HEADROOM)) { - printf ("pkt.data pointer not set properly\n"); + if (m[i]->data_off != RTE_PKTMBUF_HEADROOM) { + printf("invalid data_off\n"); ret = -1; } } @@ -510,7 +956,7 @@ test_pktmbuf_pool_ptr(void) } static int -test_pktmbuf_free_segment(void) +test_pktmbuf_free_segment(struct rte_mempool *pktmbuf_pool) { unsigned i; struct rte_mbuf *m[NB_MBUF]; @@ -536,7 +982,7 @@ test_pktmbuf_free_segment(void) mb = m[i]; while(mb != NULL) { mt = mb; - mb = mb->pkt.next; + mb = mb->next; rte_pktmbuf_free_seg(mt); } } @@ -547,18 +993,18 @@ test_pktmbuf_free_segment(void) /* * Stress test for rte_mbuf atomic refcnt. - * Implies that: - * RTE_MBUF_SCATTER_GATHER and RTE_MBUF_REFCNT_ATOMIC are both defined. - * For more efficency, recomended to run with RTE_LIBRTE_MBUF_DEBUG defined. + * Implies that RTE_MBUF_REFCNT_ATOMIC is defined. + * For more efficiency, recommended to run with RTE_LIBRTE_MBUF_DEBUG defined. */ -#if defined RTE_MBUF_SCATTER_GATHER && defined RTE_MBUF_REFCNT_ATOMIC +#ifdef RTE_MBUF_REFCNT_ATOMIC static int -test_refcnt_slave(__attribute__((unused)) void *arg) +test_refcnt_slave(void *arg) { unsigned lcore, free; void *mp = 0; + struct rte_ring *refcnt_mbuf_ring = arg; lcore = rte_lcore_id(); printf("%s started at lcore %u\n", __func__, lcore); @@ -567,7 +1013,7 @@ test_refcnt_slave(__attribute__((unused)) void *arg) while (refcnt_stop_slaves == 0) { if (rte_ring_dequeue(refcnt_mbuf_ring, &mp) == 0) { free++; - rte_pktmbuf_free((struct rte_mbuf *)mp); + rte_pktmbuf_free(mp); } } @@ -575,11 +1021,13 @@ test_refcnt_slave(__attribute__((unused)) void *arg) printf("%s finished at lcore %u, " "number of freed mbufs: %u\n", __func__, lcore, free); - return (0); + return 0; } static void -test_refcnt_iter(unsigned lcore, unsigned iter) +test_refcnt_iter(unsigned int lcore, unsigned int iter, + struct rte_mempool *refcnt_pool, + struct rte_ring *refcnt_mbuf_ring) { uint16_t ref; unsigned i, n, tref, wn; @@ -592,7 +1040,7 @@ test_refcnt_iter(unsigned lcore, unsigned iter) * - increment it's reference up to N+1, * - enqueue it N times into the ring for slave cores to free. */ - for (i = 0, n = rte_mempool_count(refcnt_pool); + for (i = 0, n = rte_mempool_avail_count(refcnt_pool); i != n && (m = rte_pktmbuf_alloc(refcnt_pool)) != NULL; i++) { ref = RTE_MAX(rte_rand() % REFCNT_MAX_REF, 1UL); @@ -620,14 +1068,14 @@ test_refcnt_iter(unsigned lcore, unsigned iter) /* check that all mbufs are back into mempool by now */ for (wn = 0; wn != REFCNT_MAX_TIMEOUT; wn++) { - if ((i = rte_mempool_count(refcnt_pool)) == n) { + if ((i = rte_mempool_avail_count(refcnt_pool)) == n) { refcnt_lcore[lcore] += tref; printf("%s(lcore=%u, iter=%u) completed, " "%u references processed\n", __func__, lcore, iter, tref); return; } - rte_delay_ms(1000); + rte_delay_ms(100); } rte_panic("(lcore=%u, iter=%u): after %us only " @@ -635,7 +1083,8 @@ test_refcnt_iter(unsigned lcore, unsigned iter) } static int -test_refcnt_master(void) +test_refcnt_master(struct rte_mempool *refcnt_pool, + struct rte_ring *refcnt_mbuf_ring) { unsigned i, lcore; @@ -643,13 +1092,13 @@ test_refcnt_master(void) printf("%s started at lcore %u\n", __func__, lcore); for (i = 0; i != REFCNT_MAX_ITER; i++) - test_refcnt_iter(lcore, i); + test_refcnt_iter(lcore, i, refcnt_pool, refcnt_mbuf_ring); refcnt_stop_slaves = 1; rte_wmb(); printf("%s finished at lcore %u\n", __func__, lcore); - return (0); + return 0; } #endif @@ -657,48 +1106,46 @@ test_refcnt_master(void) static int test_refcnt_mbuf(void) { -#if defined RTE_MBUF_SCATTER_GATHER && defined RTE_MBUF_REFCNT_ATOMIC - - unsigned lnum, master, slave, tref; - - - if ((lnum = rte_lcore_count()) == 1) { - printf("skipping %s, number of lcores: %u is not enough\n", - __func__, lnum); - return (0); +#ifdef RTE_MBUF_REFCNT_ATOMIC + unsigned int master, slave, tref; + int ret = -1; + struct rte_mempool *refcnt_pool = NULL; + struct rte_ring *refcnt_mbuf_ring = NULL; + + if (rte_lcore_count() < 2) { + printf("Not enough cores for test_refcnt_mbuf, expecting at least 2\n"); + return TEST_SKIPPED; } - printf("starting %s, at %u lcores\n", __func__, lnum); + printf("starting %s, at %u lcores\n", __func__, rte_lcore_count()); /* create refcnt pool & ring if they don't exist */ - if (refcnt_pool == NULL && - (refcnt_pool = rte_mempool_create( - MAKE_STRING(refcnt_pool), - REFCNT_MBUF_NUM, REFCNT_MBUF_SIZE, 0, - sizeof(struct rte_pktmbuf_pool_private), - rte_pktmbuf_pool_init, NULL, rte_pktmbuf_init, NULL, - SOCKET_ID_ANY, 0)) == NULL) { + refcnt_pool = rte_pktmbuf_pool_create(MAKE_STRING(refcnt_pool), + REFCNT_MBUF_NUM, 0, 0, 0, + SOCKET_ID_ANY); + if (refcnt_pool == NULL) { printf("%s: cannot allocate " MAKE_STRING(refcnt_pool) "\n", __func__); - return (-1); + return -1; } - if (refcnt_mbuf_ring == NULL && - (refcnt_mbuf_ring = rte_ring_create("refcnt_mbuf_ring", - REFCNT_RING_SIZE, SOCKET_ID_ANY, - RING_F_SP_ENQ)) == NULL) { + refcnt_mbuf_ring = rte_ring_create("refcnt_mbuf_ring", + rte_align32pow2(REFCNT_RING_SIZE), SOCKET_ID_ANY, + RING_F_SP_ENQ); + if (refcnt_mbuf_ring == NULL) { printf("%s: cannot allocate " MAKE_STRING(refcnt_mbuf_ring) "\n", __func__); - return (-1); + goto err; } refcnt_stop_slaves = 0; memset(refcnt_lcore, 0, sizeof (refcnt_lcore)); - rte_eal_mp_remote_launch(test_refcnt_slave, NULL, SKIP_MASTER); + rte_eal_mp_remote_launch(test_refcnt_slave, refcnt_mbuf_ring, + SKIP_MASTER); - test_refcnt_master(); + test_refcnt_master(refcnt_pool, refcnt_mbuf_ring); rte_eal_mp_wait_lcore(); @@ -710,31 +1157,27 @@ test_refcnt_mbuf(void) tref += refcnt_lcore[slave]; if (tref != refcnt_lcore[master]) - rte_panic("refernced mbufs: %u, freed mbufs: %u\n", + rte_panic("referenced mbufs: %u, freed mbufs: %u\n", tref, refcnt_lcore[master]); - rte_mempool_dump(refcnt_pool); - rte_ring_dump(refcnt_mbuf_ring); - -#endif - return (0); -} + rte_mempool_dump(stdout, refcnt_pool); + rte_ring_dump(stdout, refcnt_mbuf_ring); -#ifdef RTE_EXEC_ENV_BAREMETAL + ret = 0; -/* baremetal - don't test failing sanity checks */ -static int -test_failing_mbuf_sanity_check(void) -{ +err: + rte_mempool_free(refcnt_pool); + rte_ring_free(refcnt_mbuf_ring); + return ret; +#else return 0; +#endif } -#else - #include #include -/* linuxapp - use fork() to test mbuf errors panic */ +/* use fork() to test mbuf errors panic */ static int verify_mbuf_check_panics(struct rte_mbuf *buf) { @@ -744,7 +1187,7 @@ verify_mbuf_check_panics(struct rte_mbuf *buf) pid = fork(); if (pid == 0) { - rte_mbuf_sanity_check(buf, RTE_MBUF_PKT, 1); /* should panic */ + rte_mbuf_sanity_check(buf, 1); /* should panic */ exit(0); /* return normally if it doesn't panic */ } else if (pid < 0){ printf("Fork Failed\n"); @@ -758,7 +1201,7 @@ verify_mbuf_check_panics(struct rte_mbuf *buf) } static int -test_failing_mbuf_sanity_check(void) +test_failing_mbuf_sanity_check(struct rte_mempool *pktmbuf_pool) { struct rte_mbuf *buf; struct rte_mbuf badbuf; @@ -769,6 +1212,7 @@ test_failing_mbuf_sanity_check(void) buf = rte_pktmbuf_alloc(pktmbuf_pool); if (buf == NULL) return -1; + printf("Checking good mbuf initially\n"); if (verify_mbuf_check_panics(buf) != -1) return -1; @@ -780,13 +1224,6 @@ test_failing_mbuf_sanity_check(void) return -1; } - badbuf = *buf; - badbuf.type = (uint8_t)-1; - if (verify_mbuf_check_panics(&badbuf)) { - printf("Error with bad-type mbuf test\n"); - return -1; - } - badbuf = *buf; badbuf.pool = NULL; if (verify_mbuf_check_panics(&badbuf)) { @@ -795,7 +1232,7 @@ test_failing_mbuf_sanity_check(void) } badbuf = *buf; - badbuf.buf_physaddr = 0; + badbuf.buf_iova = 0; if (verify_mbuf_check_panics(&badbuf)) { printf("Error with bad-physaddr mbuf test\n"); return -1; @@ -808,7 +1245,6 @@ test_failing_mbuf_sanity_check(void) return -1; } -#ifdef RTE_MBUF_SCATTER_GATHER badbuf = *buf; badbuf.refcnt = 0; if (verify_mbuf_check_panics(&badbuf)) { @@ -822,108 +1258,1706 @@ test_failing_mbuf_sanity_check(void) printf("Error with bad-refcnt(MAX) mbuf test\n"); return -1; } -#endif return 0; } -#endif - -int -test_mbuf(void) +static int +test_mbuf_linearize(struct rte_mempool *pktmbuf_pool, int pkt_len, + int nb_segs) { - RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != 64); - /* create pktmbuf pool if it does not exist */ - if (pktmbuf_pool == NULL) { - pktmbuf_pool = - rte_mempool_create("test_pktmbuf_pool", NB_MBUF, - MBUF_SIZE, 32, - sizeof(struct rte_pktmbuf_pool_private), - rte_pktmbuf_pool_init, NULL, - rte_pktmbuf_init, NULL, - SOCKET_ID_ANY, 0); - } + struct rte_mbuf *m = NULL, *mbuf = NULL; + uint8_t *data; + int data_len = 0; + int remain; + int seg, seg_len; + int i; - if (pktmbuf_pool == NULL) { - printf("cannot allocate mbuf pool\n"); + if (pkt_len < 1) { + printf("Packet size must be 1 or more (is %d)\n", pkt_len); return -1; } - /* test multiple mbuf alloc */ - if (test_pktmbuf_pool() < 0) { - printf("test_mbuf_pool() failed\n"); + if (nb_segs < 1) { + printf("Number of segments must be 1 or more (is %d)\n", + nb_segs); return -1; } - /* do it another time to check that all mbufs were freed */ - if (test_pktmbuf_pool() < 0) { - printf("test_mbuf_pool() failed (2)\n"); - return -1; - } - - /* test that the pointer to the data on a packet mbuf is set properly */ - if (test_pktmbuf_pool_ptr() < 0) { - printf("test_pktmbuf_pool_ptr() failed\n"); - return -1; - } + seg_len = pkt_len / nb_segs; + if (seg_len == 0) + seg_len = 1; - /* test data manipulation in mbuf */ - if (test_one_pktmbuf() < 0) { - printf("test_one_mbuf() failed\n"); - return -1; - } + remain = pkt_len; + /* Create chained mbuf_src and fill it generated data */ + for (seg = 0; remain > 0; seg++) { - /* - * do it another time, to check that allocation reinitialize - * the mbuf correctly - */ - if (test_one_pktmbuf() < 0) { - printf("test_one_mbuf() failed (2)\n"); - return -1; - } + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) { + printf("Cannot create segment for source mbuf"); + goto fail; + } - if (test_pktmbuf_with_non_ascii_data() < 0) { - printf("test_pktmbuf_with_non_ascii_data() failed\n"); - return -1; - } + /* Make sure if tailroom is zeroed */ + memset(rte_pktmbuf_mtod(m, uint8_t *), 0, + rte_pktmbuf_tailroom(m)); - /* create ctrlmbuf pool if it does not exist */ - if (ctrlmbuf_pool == NULL) { - ctrlmbuf_pool = - rte_mempool_create("test_ctrlmbuf_pool", NB_MBUF, - sizeof(struct rte_mbuf), 32, 0, - NULL, NULL, - rte_ctrlmbuf_init, NULL, - SOCKET_ID_ANY, 0); - } + data_len = remain; + if (data_len > seg_len) + data_len = seg_len; - /* test control mbuf */ - if (test_one_ctrlmbuf() < 0) { - printf("test_one_ctrlmbuf() failed\n"); - return -1; - } + data = (uint8_t *)rte_pktmbuf_append(m, data_len); + if (data == NULL) { + printf("Cannot append %d bytes to the mbuf\n", + data_len); + goto fail; + } - /* test free pktmbuf segment one by one */ - if (test_pktmbuf_free_segment() < 0) { - printf("test_pktmbuf_free_segment() failed.\n"); - return -1; - } + for (i = 0; i < data_len; i++) + data[i] = (seg * seg_len + i) % 0x0ff; - if (testclone_testupdate_testdetach()<0){ - printf("testclone_and_testupdate() failed \n"); - return -1; + if (seg == 0) + mbuf = m; + else + rte_pktmbuf_chain(mbuf, m); + + remain -= data_len; } - if (test_refcnt_mbuf()<0){ - printf("test_refcnt_mbuf() failed \n"); - return -1; + /* Create destination buffer to store coalesced data */ + if (rte_pktmbuf_linearize(mbuf)) { + printf("Mbuf linearization failed\n"); + goto fail; } - if (test_failing_mbuf_sanity_check() < 0) { - printf("test_failing_mbuf_sanity_check() failed\n"); - return -1; + if (!rte_pktmbuf_is_contiguous(mbuf)) { + printf("Source buffer should be contiguous after " + "linearization\n"); + goto fail; } + + data = rte_pktmbuf_mtod(mbuf, uint8_t *); + + for (i = 0; i < pkt_len; i++) + if (data[i] != (i % 0x0ff)) { + printf("Incorrect data in linearized mbuf\n"); + goto fail; + } + + rte_pktmbuf_free(mbuf); + return 0; + +fail: + if (mbuf) + rte_pktmbuf_free(mbuf); + return -1; +} + +static int +test_mbuf_linearize_check(struct rte_mempool *pktmbuf_pool) +{ + struct test_mbuf_array { + int size; + int nb_segs; + } mbuf_array[] = { + { 128, 1 }, + { 64, 64 }, + { 512, 10 }, + { 250, 11 }, + { 123, 8 }, + }; + unsigned int i; + + printf("Test mbuf linearize API\n"); + + for (i = 0; i < RTE_DIM(mbuf_array); i++) + if (test_mbuf_linearize(pktmbuf_pool, mbuf_array[i].size, + mbuf_array[i].nb_segs)) { + printf("Test failed for %d, %d\n", mbuf_array[i].size, + mbuf_array[i].nb_segs); + return -1; + } + return 0; } + +/* + * Helper function for test_tx_ofload + */ +static inline void +set_tx_offload(struct rte_mbuf *mb, uint64_t il2, uint64_t il3, uint64_t il4, + uint64_t tso, uint64_t ol3, uint64_t ol2) +{ + mb->l2_len = il2; + mb->l3_len = il3; + mb->l4_len = il4; + mb->tso_segsz = tso; + mb->outer_l3_len = ol3; + mb->outer_l2_len = ol2; +} + +static int +test_tx_offload(void) +{ + struct rte_mbuf *mb; + uint64_t tm, v1, v2; + size_t sz; + uint32_t i; + + static volatile struct { + uint16_t l2; + uint16_t l3; + uint16_t l4; + uint16_t tso; + } txof; + + const uint32_t num = 0x10000; + + txof.l2 = rte_rand() % (1 << RTE_MBUF_L2_LEN_BITS); + txof.l3 = rte_rand() % (1 << RTE_MBUF_L3_LEN_BITS); + txof.l4 = rte_rand() % (1 << RTE_MBUF_L4_LEN_BITS); + txof.tso = rte_rand() % (1 << RTE_MBUF_TSO_SEGSZ_BITS); + + printf("%s started, tx_offload = {\n" + "\tl2_len=%#hx,\n" + "\tl3_len=%#hx,\n" + "\tl4_len=%#hx,\n" + "\ttso_segsz=%#hx,\n" + "\touter_l3_len=%#x,\n" + "\touter_l2_len=%#x,\n" + "};\n", + __func__, + txof.l2, txof.l3, txof.l4, txof.tso, txof.l3, txof.l2); + + sz = sizeof(*mb) * num; + mb = rte_zmalloc(NULL, sz, RTE_CACHE_LINE_SIZE); + if (mb == NULL) { + printf("%s failed, out of memory\n", __func__); + return -ENOMEM; + } + + memset(mb, 0, sz); + tm = rte_rdtsc_precise(); + + for (i = 0; i != num; i++) + set_tx_offload(mb + i, txof.l2, txof.l3, txof.l4, + txof.tso, txof.l3, txof.l2); + + tm = rte_rdtsc_precise() - tm; + printf("%s set tx_offload by bit-fields: %u iterations, %" + PRIu64 " cycles, %#Lf cycles/iter\n", + __func__, num, tm, (long double)tm / num); + + v1 = mb[rte_rand() % num].tx_offload; + + memset(mb, 0, sz); + tm = rte_rdtsc_precise(); + + for (i = 0; i != num; i++) + mb[i].tx_offload = rte_mbuf_tx_offload(txof.l2, txof.l3, + txof.l4, txof.tso, txof.l3, txof.l2, 0); + + tm = rte_rdtsc_precise() - tm; + printf("%s set raw tx_offload: %u iterations, %" + PRIu64 " cycles, %#Lf cycles/iter\n", + __func__, num, tm, (long double)tm / num); + + v2 = mb[rte_rand() % num].tx_offload; + + rte_free(mb); + + printf("%s finished\n" + "expected tx_offload value: 0x%" PRIx64 ";\n" + "rte_mbuf_tx_offload value: 0x%" PRIx64 ";\n", + __func__, v1, v2); + + 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), + }; + + /* 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, + 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; +} + +/* + * Test the mbuf pool with pinned external data buffers + * - Allocate memory zone for external buffer + * - Create the mbuf pool with pinned external buffer + * - Check the created pool with relevant mbuf pool unit tests + */ +static int +test_pktmbuf_ext_pinned_buffer(struct rte_mempool *std_pool) +{ + + struct rte_pktmbuf_extmem ext_mem; + struct rte_mempool *pinned_pool = NULL; + const struct rte_memzone *mz = NULL; + + printf("Test mbuf pool with external pinned data buffers\n"); + + /* Allocate memzone for the external data buffer */ + mz = rte_memzone_reserve("pinned_pool", + NB_MBUF * MBUF_DATA_SIZE, + SOCKET_ID_ANY, + RTE_MEMZONE_2MB | RTE_MEMZONE_SIZE_HINT_ONLY); + if (mz == NULL) + GOTO_FAIL("%s: Memzone allocation failed\n", __func__); + + /* Create the mbuf pool with pinned external data buffer */ + ext_mem.buf_ptr = mz->addr; + ext_mem.buf_iova = mz->iova; + ext_mem.buf_len = mz->len; + ext_mem.elt_size = MBUF_DATA_SIZE; + + pinned_pool = rte_pktmbuf_pool_create_extbuf("test_pinned_pool", + NB_MBUF, MEMPOOL_CACHE_SIZE, 0, + MBUF_DATA_SIZE, SOCKET_ID_ANY, + &ext_mem, 1); + if (pinned_pool == NULL) + GOTO_FAIL("%s: Mbuf pool with pinned external" + " buffer creation failed\n", __func__); + /* test multiple mbuf alloc */ + if (test_pktmbuf_pool(pinned_pool) < 0) + GOTO_FAIL("%s: test_mbuf_pool(pinned) failed\n", + __func__); + + /* do it another time to check that all mbufs were freed */ + if (test_pktmbuf_pool(pinned_pool) < 0) + GOTO_FAIL("%s: test_mbuf_pool(pinned) failed (2)\n", + __func__); + + /* test that the data pointer on a packet mbuf is set properly */ + if (test_pktmbuf_pool_ptr(pinned_pool) < 0) + GOTO_FAIL("%s: test_pktmbuf_pool_ptr(pinned) failed\n", + __func__); + + /* test data manipulation in mbuf with non-ascii data */ + if (test_pktmbuf_with_non_ascii_data(pinned_pool) < 0) + GOTO_FAIL("%s: test_pktmbuf_with_non_ascii_data(pinned)" + " failed\n", __func__); + + /* test free pktmbuf segment one by one */ + if (test_pktmbuf_free_segment(pinned_pool) < 0) + GOTO_FAIL("%s: test_pktmbuf_free_segment(pinned) failed\n", + __func__); + + if (testclone_testupdate_testdetach(pinned_pool, std_pool) < 0) + GOTO_FAIL("%s: testclone_and_testupdate(pinned) failed\n", + __func__); + + if (test_pktmbuf_copy(pinned_pool, std_pool) < 0) + GOTO_FAIL("%s: test_pktmbuf_copy(pinned) failed\n", + __func__); + + if (test_failing_mbuf_sanity_check(pinned_pool) < 0) + GOTO_FAIL("%s: test_failing_mbuf_sanity_check(pinned)" + " failed\n", __func__); + + if (test_mbuf_linearize_check(pinned_pool) < 0) + GOTO_FAIL("%s: test_mbuf_linearize_check(pinned) failed\n", + __func__); + + /* test for allocating a bulk of mbufs with various sizes */ + if (test_pktmbuf_alloc_bulk(pinned_pool) < 0) + GOTO_FAIL("%s: test_rte_pktmbuf_alloc_bulk(pinned) failed\n", + __func__); + + /* test for allocating a bulk of mbufs with various sizes */ + if (test_neg_pktmbuf_alloc_bulk(pinned_pool) < 0) + GOTO_FAIL("%s: test_neg_rte_pktmbuf_alloc_bulk(pinned)" + " failed\n", __func__); + + /* test to read mbuf packet */ + if (test_pktmbuf_read(pinned_pool) < 0) + GOTO_FAIL("%s: test_rte_pktmbuf_read(pinned) failed\n", + __func__); + + /* test to read mbuf packet from offset */ + if (test_pktmbuf_read_from_offset(pinned_pool) < 0) + GOTO_FAIL("%s: test_rte_pktmbuf_read_from_offset(pinned)" + " failed\n", __func__); + + /* test to read data from chain of mbufs with data segments */ + if (test_pktmbuf_read_from_chain(pinned_pool) < 0) + GOTO_FAIL("%s: test_rte_pktmbuf_read_from_chain(pinned)" + " failed\n", __func__); + + RTE_SET_USED(std_pool); + rte_mempool_free(pinned_pool); + rte_memzone_free(mz); + return 0; + +fail: + rte_mempool_free(pinned_pool); + rte_memzone_free(mz); + return -1; +} + +static int +test_mbuf_dyn(struct rte_mempool *pktmbuf_pool) +{ + const struct rte_mbuf_dynfield dynfield = { + .name = "test-dynfield", + .size = sizeof(uint8_t), + .align = __alignof__(uint8_t), + .flags = 0, + }; + const struct rte_mbuf_dynfield dynfield2 = { + .name = "test-dynfield2", + .size = sizeof(uint16_t), + .align = __alignof__(uint16_t), + .flags = 0, + }; + const struct rte_mbuf_dynfield dynfield3 = { + .name = "test-dynfield3", + .size = sizeof(uint8_t), + .align = __alignof__(uint8_t), + .flags = 0, + }; + const struct rte_mbuf_dynfield dynfield_fail_big = { + .name = "test-dynfield-fail-big", + .size = 256, + .align = 1, + .flags = 0, + }; + const struct rte_mbuf_dynfield dynfield_fail_align = { + .name = "test-dynfield-fail-align", + .size = 1, + .align = 3, + .flags = 0, + }; + const struct rte_mbuf_dynflag dynflag = { + .name = "test-dynflag", + .flags = 0, + }; + const struct rte_mbuf_dynflag dynflag2 = { + .name = "test-dynflag2", + .flags = 0, + }; + const struct rte_mbuf_dynflag dynflag3 = { + .name = "test-dynflag3", + .flags = 0, + }; + struct rte_mbuf *m = NULL; + int offset, offset2, offset3; + int flag, flag2, flag3; + int ret; + + printf("Test mbuf dynamic fields and flags\n"); + rte_mbuf_dyn_dump(stdout); + + offset = rte_mbuf_dynfield_register(&dynfield); + if (offset == -1) + GOTO_FAIL("failed to register dynamic field, offset=%d: %s", + offset, strerror(errno)); + + ret = rte_mbuf_dynfield_register(&dynfield); + if (ret != offset) + GOTO_FAIL("failed to lookup dynamic field, ret=%d: %s", + ret, strerror(errno)); + + offset2 = rte_mbuf_dynfield_register(&dynfield2); + if (offset2 == -1 || offset2 == offset || (offset2 & 1)) + GOTO_FAIL("failed to register dynamic field 2, offset2=%d: %s", + offset2, strerror(errno)); + + offset3 = rte_mbuf_dynfield_register_offset(&dynfield3, + offsetof(struct rte_mbuf, dynfield1[1])); + if (offset3 != offsetof(struct rte_mbuf, dynfield1[1])) + GOTO_FAIL("failed to register dynamic field 3, offset=%d: %s", + offset3, strerror(errno)); + + printf("dynfield: offset=%d, offset2=%d, offset3=%d\n", + offset, offset2, offset3); + + ret = rte_mbuf_dynfield_register(&dynfield_fail_big); + if (ret != -1) + GOTO_FAIL("dynamic field creation should fail (too big)"); + + ret = rte_mbuf_dynfield_register(&dynfield_fail_align); + if (ret != -1) + GOTO_FAIL("dynamic field creation should fail (bad alignment)"); + + ret = rte_mbuf_dynfield_register_offset(&dynfield_fail_align, + offsetof(struct rte_mbuf, ol_flags)); + if (ret != -1) + GOTO_FAIL("dynamic field creation should fail (not avail)"); + + flag = rte_mbuf_dynflag_register(&dynflag); + if (flag == -1) + GOTO_FAIL("failed to register dynamic flag, flag=%d: %s", + flag, strerror(errno)); + + ret = rte_mbuf_dynflag_register(&dynflag); + if (ret != flag) + GOTO_FAIL("failed to lookup dynamic flag, ret=%d: %s", + ret, strerror(errno)); + + flag2 = rte_mbuf_dynflag_register(&dynflag2); + if (flag2 == -1 || flag2 == flag) + GOTO_FAIL("failed to register dynamic flag 2, flag2=%d: %s", + flag2, strerror(errno)); + + flag3 = rte_mbuf_dynflag_register_bitnum(&dynflag3, + rte_bsf64(PKT_LAST_FREE)); + if (flag3 != rte_bsf64(PKT_LAST_FREE)) + GOTO_FAIL("failed to register dynamic flag 3, flag3=%d: %s", + flag3, strerror(errno)); + + printf("dynflag: flag=%d, flag2=%d, flag3=%d\n", flag, flag2, flag3); + + /* set, get dynamic field */ + m = rte_pktmbuf_alloc(pktmbuf_pool); + if (m == NULL) + GOTO_FAIL("Cannot allocate mbuf"); + + *RTE_MBUF_DYNFIELD(m, offset, uint8_t *) = 1; + if (*RTE_MBUF_DYNFIELD(m, offset, uint8_t *) != 1) + GOTO_FAIL("failed to read dynamic field"); + *RTE_MBUF_DYNFIELD(m, offset2, uint16_t *) = 1000; + if (*RTE_MBUF_DYNFIELD(m, offset2, uint16_t *) != 1000) + GOTO_FAIL("failed to read dynamic field"); + + /* set a dynamic flag */ + m->ol_flags |= (1ULL << flag); + + rte_mbuf_dyn_dump(stdout); + rte_pktmbuf_free(m); + return 0; +fail: + rte_pktmbuf_free(m); + return -1; +} + +static void +my_free_cb(void *addr, void *opaque __rte_unused) +{ + rte_free(addr); +} + +static int +test_shinfo_in_mbuf(struct rte_mempool *pktmbuf_pool) +{ + struct rte_mbuf_ext_shared_info *shinfo = NULL; + struct rte_mbuf *m2 = NULL; + struct rte_mbuf *m = NULL; + size_t buf_len = 256; + rte_iova_t iova; + char *buf = NULL; + + m = rte_pktmbuf_alloc(pktmbuf_pool); + printf("%s() m=%p\n", __func__, m); + if (m == NULL) + GOTO_FAIL("cannot allocate mbuf m"); + rte_pktmbuf_dump(stdout, m, 0); + + if (rte_pktmbuf_tailroom(m) < sizeof(*shinfo)) + GOTO_FAIL("tailroom too small"); + + buf = rte_malloc(NULL, buf_len, RTE_CACHE_LINE_SIZE); + if (buf == NULL) + GOTO_FAIL("cannot allocate buffer"); + + shinfo = rte_pktmbuf_mtod(m, struct rte_mbuf_ext_shared_info *); + shinfo->free_cb = my_free_cb; + shinfo->fcb_opaque = NULL; + rte_mbuf_ext_refcnt_set(shinfo, 1); + iova = rte_malloc_virt2iova(buf); + rte_pktmbuf_attach_extbuf(m, buf, iova, buf_len, shinfo); + printf("%s() m is attached to the ext buf\n", __func__); + rte_pktmbuf_dump(stdout, m, 0); + + m2 = rte_pktmbuf_alloc(pktmbuf_pool); + printf("%s() m2=%p\n", __func__, m2); + if (m2 == NULL) + GOTO_FAIL("cannot allocate mbuf m2"); + rte_pktmbuf_dump(stdout, m2, 0); + + rte_pktmbuf_attach(m2, m); + rte_pktmbuf_dump(stdout, m2, 0); + rte_pktmbuf_dump(stdout, m, 0); + rte_pktmbuf_free(m); + m = NULL; + + m = rte_pktmbuf_alloc(pktmbuf_pool); + printf("%s() m=%p\n", __func__, m); + if (m == NULL) + GOTO_FAIL("cannot allocate mbuf m"); + + /* clobber data in the mbuf we just allocated */ + shinfo = rte_pktmbuf_mtod(m, struct rte_mbuf_ext_shared_info *); + shinfo->free_cb = NULL; + + rte_pktmbuf_free(m); + m = NULL; + + rte_pktmbuf_free(m2); + m2 = NULL; + + printf("done\n"); + return 0; + + +fail: + rte_pktmbuf_free(m2); + rte_pktmbuf_free(m); + rte_free(buf); + return -1; +} + +static int +test_mbuf(void) +{ + int ret = -1; + struct rte_mempool *pktmbuf_pool = NULL; + struct rte_mempool *pktmbuf_pool2 = NULL; + + + RTE_BUILD_BUG_ON(sizeof(struct rte_mbuf) != RTE_CACHE_LINE_MIN_SIZE * 2); + + /* create pktmbuf pool if it does not exist */ + pktmbuf_pool = rte_pktmbuf_pool_create("test_pktmbuf_pool", + NB_MBUF, MEMPOOL_CACHE_SIZE, 0, MBUF_DATA_SIZE, + SOCKET_ID_ANY); + + if (pktmbuf_pool == NULL) { + printf("cannot allocate mbuf pool\n"); + goto err; + } + + if (test_shinfo_in_mbuf(pktmbuf_pool) < 0) { + printf("mbuf shinfo in mbuf failed\n"); + goto err; + } + + if (1) { + ret = 0; + goto err; + } + + /* test registration of dynamic fields and flags */ + if (test_mbuf_dyn(pktmbuf_pool) < 0) { + printf("mbuf dynflag test failed\n"); + goto err; + } + + /* 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, MEMPOOL_CACHE_SIZE, MBUF2_PRIV_SIZE, 0, + SOCKET_ID_ANY); + + if (pktmbuf_pool2 == NULL) { + printf("cannot allocate mbuf pool\n"); + goto err; + } + + /* test multiple mbuf alloc */ + if (test_pktmbuf_pool(pktmbuf_pool) < 0) { + printf("test_mbuf_pool() failed\n"); + goto err; + } + + /* do it another time to check that all mbufs were freed */ + if (test_pktmbuf_pool(pktmbuf_pool) < 0) { + printf("test_mbuf_pool() failed (2)\n"); + goto err; + } + + /* test bulk mbuf alloc and free */ + if (test_pktmbuf_pool_bulk() < 0) { + printf("test_pktmbuf_pool_bulk() failed\n"); + goto err; + } + + /* test that the pointer to the data on a packet mbuf is set properly */ + if (test_pktmbuf_pool_ptr(pktmbuf_pool) < 0) { + printf("test_pktmbuf_pool_ptr() failed\n"); + goto err; + } + + /* test data manipulation in mbuf */ + if (test_one_pktmbuf(pktmbuf_pool) < 0) { + printf("test_one_mbuf() failed\n"); + goto err; + } + + + /* + * do it another time, to check that allocation reinitialize + * the mbuf correctly + */ + if (test_one_pktmbuf(pktmbuf_pool) < 0) { + printf("test_one_mbuf() failed (2)\n"); + goto err; + } + + if (test_pktmbuf_with_non_ascii_data(pktmbuf_pool) < 0) { + printf("test_pktmbuf_with_non_ascii_data() failed\n"); + goto err; + } + + /* test free pktmbuf segment one by one */ + if (test_pktmbuf_free_segment(pktmbuf_pool) < 0) { + printf("test_pktmbuf_free_segment() failed.\n"); + goto err; + } + + if (testclone_testupdate_testdetach(pktmbuf_pool, pktmbuf_pool) < 0) { + printf("testclone_and_testupdate() failed \n"); + goto err; + } + + if (test_pktmbuf_copy(pktmbuf_pool, pktmbuf_pool) < 0) { + printf("test_pktmbuf_copy() failed\n"); + goto err; + } + + if (test_attach_from_different_pool(pktmbuf_pool, pktmbuf_pool2) < 0) { + printf("test_attach_from_different_pool() failed\n"); + goto err; + } + + if (test_refcnt_mbuf() < 0) { + printf("test_refcnt_mbuf() failed \n"); + goto err; + } + + if (test_failing_mbuf_sanity_check(pktmbuf_pool) < 0) { + printf("test_failing_mbuf_sanity_check() failed\n"); + goto err; + } + + if (test_mbuf_linearize_check(pktmbuf_pool) < 0) { + printf("test_mbuf_linearize_check() failed\n"); + goto err; + } + + if (test_tx_offload() < 0) { + printf("test_tx_offload() failed\n"); + 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; + } + + /* 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; + } + + /* test the mbuf pool with pinned external data buffers */ + if (test_pktmbuf_ext_pinned_buffer(pktmbuf_pool) < 0) { + printf("test_pktmbuf_ext_pinned_buffer() failed\n"); + goto err; + } + + + ret = 0; +err: + rte_mempool_free(pktmbuf_pool); + rte_mempool_free(pktmbuf_pool2); + return ret; +} +#undef GOTO_FAIL + +REGISTER_TEST_COMMAND(mbuf_autotest, test_mbuf);