aboutsummaryrefslogtreecommitdiff
path: root/test/common_plat/validation/api/packet
diff options
context:
space:
mode:
authorChristophe Milard <christophe.milard@linaro.org>2016-07-13 21:50:41 +0200
committerMaxim Uvarov <maxim.uvarov@linaro.org>2016-07-21 16:02:40 +0300
commitefa6bc89a4e7a5823a3c8c27fcdc9573d7ac5694 (patch)
treef54ae4d3df7f05b6ad83d665c721ff4b5b8cae82 /test/common_plat/validation/api/packet
parentc79b041f389e56a2c713a507b75762e08d75e4b4 (diff)
validation: moving api validation tests to prepare for new interfaces
API tests are now moved to test/common_plat/validation/api (from test/validation), The reason for this move is two folded: * Moving down validation to all-plaforms/validation disambiguates the meaning of validation (which up to now was referring to both platform agnostic tests and to the set of tests to pass to be ODP compatible). Now things in test/common_plat/ are platform agnostic. So test/common_plat/validation/* are platform agnostic things for the validation tests, as much as test/common_plat/performance are platform agnostic things for the performance tests. * creating the api directory under "validation" simply enable adding other interfaces (such as future drv) as part of the validation tests Signed-off-by: Christophe Milard <christophe.milard@linaro.org> Reviewed-by: Bill Fischofer <bill.fischofer@linaro.org> Reviewed-and-tested-by: Yi He <yi.he@linaro.org> Reviewed-by: Mike Holmes <mike.holmes@linaro.org> Signed-off-by: Maxim Uvarov <maxim.uvarov@linaro.org>
Diffstat (limited to 'test/common_plat/validation/api/packet')
-rw-r--r--test/common_plat/validation/api/packet/.gitignore1
-rw-r--r--test/common_plat/validation/api/packet/Makefile.am10
-rw-r--r--test/common_plat/validation/api/packet/packet.c1369
-rw-r--r--test/common_plat/validation/api/packet/packet.h49
-rw-r--r--test/common_plat/validation/api/packet/packet_main.c12
5 files changed, 1441 insertions, 0 deletions
diff --git a/test/common_plat/validation/api/packet/.gitignore b/test/common_plat/validation/api/packet/.gitignore
new file mode 100644
index 000000000..c05530d2d
--- /dev/null
+++ b/test/common_plat/validation/api/packet/.gitignore
@@ -0,0 +1 @@
+packet_main
diff --git a/test/common_plat/validation/api/packet/Makefile.am b/test/common_plat/validation/api/packet/Makefile.am
new file mode 100644
index 000000000..d8ebc1a23
--- /dev/null
+++ b/test/common_plat/validation/api/packet/Makefile.am
@@ -0,0 +1,10 @@
+include ../Makefile.inc
+
+noinst_LTLIBRARIES = libtestpacket.la
+libtestpacket_la_SOURCES = packet.c
+
+test_PROGRAMS = packet_main$(EXEEXT)
+dist_packet_main_SOURCES = packet_main.c
+packet_main_LDADD = libtestpacket.la $(LIBCUNIT_COMMON) $(LIBODP)
+
+EXTRA_DIST = packet.h
diff --git a/test/common_plat/validation/api/packet/packet.c b/test/common_plat/validation/api/packet/packet.c
new file mode 100644
index 000000000..a4426e22f
--- /dev/null
+++ b/test/common_plat/validation/api/packet/packet.c
@@ -0,0 +1,1369 @@
+/* Copyright (c) 2014, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <stdlib.h>
+
+#include <odp_api.h>
+#include <odp_cunit_common.h>
+#include "packet.h"
+
+#define PACKET_BUF_LEN ODP_CONFIG_PACKET_SEG_LEN_MIN
+/* Reserve some tailroom for tests */
+#define PACKET_TAILROOM_RESERVE 4
+
+static odp_pool_t packet_pool, packet_pool_no_uarea, packet_pool_double_uarea;
+static uint32_t packet_len;
+
+static uint32_t segmented_packet_len;
+static odp_bool_t segmentation_supported = true;
+
+odp_packet_t test_packet, segmented_test_packet;
+
+static struct udata_struct {
+ uint64_t u64;
+ uint32_t u32;
+ char str[10];
+} test_packet_udata = {
+ 123456,
+ 789912,
+ "abcdefg",
+};
+
+int packet_suite_init(void)
+{
+ odp_pool_param_t params;
+ odp_pool_capability_t capa;
+ struct udata_struct *udat;
+ uint32_t udat_size;
+ uint8_t data = 0;
+ uint32_t i;
+
+ if (odp_pool_capability(&capa) < 0)
+ return -1;
+
+ packet_len = capa.pkt.min_seg_len - PACKET_TAILROOM_RESERVE;
+
+ if (capa.pkt.max_len) {
+ segmented_packet_len = capa.pkt.max_len;
+ } else {
+ segmented_packet_len = capa.pkt.min_seg_len *
+ capa.pkt.max_segs_per_pkt;
+ }
+
+ odp_pool_param_init(&params);
+
+ params.type = ODP_POOL_PACKET;
+ params.pkt.seg_len = capa.pkt.min_seg_len;
+ params.pkt.len = capa.pkt.min_seg_len;
+ params.pkt.num = 100;
+ params.pkt.uarea_size = sizeof(struct udata_struct);
+
+ packet_pool = odp_pool_create("packet_pool", &params);
+ if (packet_pool == ODP_POOL_INVALID)
+ return -1;
+
+ params.pkt.uarea_size = 0;
+ packet_pool_no_uarea = odp_pool_create("packet_pool_no_uarea",
+ &params);
+ if (packet_pool_no_uarea == ODP_POOL_INVALID) {
+ odp_pool_destroy(packet_pool);
+ return -1;
+ }
+
+ params.pkt.uarea_size = 2 * sizeof(struct udata_struct);
+ packet_pool_double_uarea = odp_pool_create("packet_pool_double_uarea",
+ &params);
+
+ if (packet_pool_double_uarea == ODP_POOL_INVALID) {
+ odp_pool_destroy(packet_pool_no_uarea);
+ odp_pool_destroy(packet_pool);
+ return -1;
+ }
+
+ test_packet = odp_packet_alloc(packet_pool, packet_len);
+
+ for (i = 0; i < packet_len; i++) {
+ odp_packet_copy_from_mem(test_packet, i, 1, &data);
+ data++;
+ }
+
+ /* Try to allocate the largest possible packet to see
+ * if segmentation is supported */
+ do {
+ segmented_test_packet = odp_packet_alloc(packet_pool,
+ segmented_packet_len);
+ if (segmented_test_packet == ODP_PACKET_INVALID)
+ segmented_packet_len -= capa.pkt.min_seg_len;
+ } while (segmented_test_packet == ODP_PACKET_INVALID);
+
+ if (odp_packet_is_valid(test_packet) == 0 ||
+ odp_packet_is_valid(segmented_test_packet) == 0)
+ return -1;
+
+ segmentation_supported = odp_packet_is_segmented(segmented_test_packet);
+
+ data = 0;
+ for (i = 0; i < segmented_packet_len; i++) {
+ odp_packet_copy_from_mem(segmented_test_packet, i, 1, &data);
+ data++;
+ }
+
+ udat = odp_packet_user_area(test_packet);
+ udat_size = odp_packet_user_area_size(test_packet);
+ if (!udat || udat_size != sizeof(struct udata_struct))
+ return -1;
+ odp_pool_print(packet_pool);
+ memcpy(udat, &test_packet_udata, sizeof(struct udata_struct));
+
+ udat = odp_packet_user_area(segmented_test_packet);
+ udat_size = odp_packet_user_area_size(segmented_test_packet);
+ if (udat == NULL || udat_size != sizeof(struct udata_struct))
+ return -1;
+ memcpy(udat, &test_packet_udata, sizeof(struct udata_struct));
+
+ return 0;
+}
+
+int packet_suite_term(void)
+{
+ odp_packet_free(test_packet);
+ odp_packet_free(segmented_test_packet);
+
+ if (odp_pool_destroy(packet_pool_double_uarea) != 0 ||
+ odp_pool_destroy(packet_pool_no_uarea) != 0 ||
+ odp_pool_destroy(packet_pool) != 0)
+ return -1;
+
+ return 0;
+}
+
+void packet_test_alloc_free(void)
+{
+ odp_pool_t pool;
+ odp_packet_t packet;
+ odp_pool_param_t params;
+ odp_pool_capability_t capa;
+
+ CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0);
+
+ odp_pool_param_init(&params);
+
+ params.type = ODP_POOL_PACKET;
+ params.pkt.seg_len = capa.pkt.min_seg_len;
+ params.pkt.len = capa.pkt.min_seg_len;
+ params.pkt.num = 1;
+
+ pool = odp_pool_create("packet_pool_alloc", &params);
+
+ /* Allocate the only buffer from the pool */
+ packet = odp_packet_alloc(pool, packet_len);
+ CU_ASSERT_FATAL(packet != ODP_PACKET_INVALID);
+ CU_ASSERT(odp_packet_len(packet) == packet_len);
+ CU_ASSERT(odp_event_type(odp_packet_to_event(packet)) ==
+ ODP_EVENT_PACKET);
+ CU_ASSERT(odp_packet_to_u64(packet) !=
+ odp_packet_to_u64(ODP_PACKET_INVALID));
+
+ /* Pool should have only one packet */
+ CU_ASSERT_FATAL(odp_packet_alloc(pool, packet_len)
+ == ODP_PACKET_INVALID);
+
+ odp_packet_free(packet);
+
+ /* Check that the buffer was returned back to the pool */
+ packet = odp_packet_alloc(pool, packet_len);
+ CU_ASSERT_FATAL(packet != ODP_PACKET_INVALID);
+ CU_ASSERT(odp_packet_len(packet) == packet_len);
+
+ odp_packet_free(packet);
+ CU_ASSERT(odp_pool_destroy(pool) == 0);
+}
+
+/* Wrapper to call odp_packet_alloc_multi multiple times until
+ * either no mure buffers are returned, or num buffers were alloced */
+static int packet_alloc_multi(odp_pool_t pool, uint32_t pkt_len,
+ odp_packet_t pkt[], int num)
+{
+ int ret, total = 0;
+
+ do {
+ ret = odp_packet_alloc_multi(pool, pkt_len, pkt + total,
+ num - total);
+ CU_ASSERT(ret >= 0);
+ CU_ASSERT(ret <= num - total);
+ total += ret;
+ } while (total < num && ret);
+
+ return total;
+}
+
+void packet_test_alloc_free_multi(void)
+{
+ const int num_pkt = 2;
+ odp_pool_t pool[2];
+ int i, ret;
+ odp_packet_t packet[2 * num_pkt + 1];
+ odp_packet_t inval_pkt[num_pkt];
+ odp_pool_param_t params;
+ odp_pool_capability_t capa;
+
+ CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0);
+
+ odp_pool_param_init(&params);
+
+ params.type = ODP_POOL_PACKET;
+ params.pkt.seg_len = capa.pkt.min_seg_len;
+ params.pkt.len = capa.pkt.min_seg_len;
+ params.pkt.num = num_pkt;
+
+ pool[0] = odp_pool_create("packet_pool_alloc_multi_0", &params);
+ pool[1] = odp_pool_create("packet_pool_alloc_multi_1", &params);
+ CU_ASSERT_FATAL(pool[0] != ODP_POOL_INVALID);
+ CU_ASSERT_FATAL(pool[1] != ODP_POOL_INVALID);
+
+ /* Allocate all the packets from the pools */
+
+ ret = packet_alloc_multi(pool[0], packet_len, &packet[0], num_pkt + 1);
+ CU_ASSERT_FATAL(ret == num_pkt);
+ ret = packet_alloc_multi(pool[1], packet_len,
+ &packet[num_pkt], num_pkt + 1);
+ CU_ASSERT_FATAL(ret == num_pkt);
+
+ for (i = 0; i < 2 * num_pkt; ++i) {
+ CU_ASSERT(odp_packet_len(packet[i]) == packet_len);
+ CU_ASSERT(odp_event_type(odp_packet_to_event(packet[i])) ==
+ ODP_EVENT_PACKET);
+ CU_ASSERT(odp_packet_to_u64(packet[i]) !=
+ odp_packet_to_u64(ODP_PACKET_INVALID));
+ }
+
+ /* Pools should have no more packets */
+ ret = odp_packet_alloc_multi(pool[0], packet_len, inval_pkt, num_pkt);
+ CU_ASSERT(ret == 0);
+ ret = odp_packet_alloc_multi(pool[1], packet_len, inval_pkt, num_pkt);
+ CU_ASSERT(ret == 0);
+
+ /* Free all packets from all pools at once */
+ odp_packet_free_multi(packet, 2 * num_pkt);
+
+ /* Check that all the packets were returned back to their pools */
+ ret = packet_alloc_multi(pool[0], packet_len, &packet[0], num_pkt);
+ CU_ASSERT(ret);
+ ret = packet_alloc_multi(pool[1], packet_len,
+ &packet[num_pkt], num_pkt);
+ CU_ASSERT(ret);
+
+ for (i = 0; i < 2 * num_pkt; ++i) {
+ CU_ASSERT_FATAL(packet[i] != ODP_PACKET_INVALID);
+ CU_ASSERT(odp_packet_len(packet[i]) == packet_len);
+ }
+ odp_packet_free_multi(packet, 2 * num_pkt);
+ CU_ASSERT(odp_pool_destroy(pool[0]) == 0);
+ CU_ASSERT(odp_pool_destroy(pool[1]) == 0);
+}
+
+void packet_test_alloc_segmented(void)
+{
+ odp_packet_t pkt;
+ uint32_t len;
+ odp_pool_capability_t capa;
+
+ CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0);
+
+ if (capa.pkt.max_len)
+ len = capa.pkt.max_len;
+ else
+ len = capa.pkt.min_seg_len * capa.pkt.max_segs_per_pkt;
+
+ pkt = odp_packet_alloc(packet_pool, len);
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+ CU_ASSERT(odp_packet_len(pkt) == len);
+ if (segmentation_supported)
+ CU_ASSERT(odp_packet_is_segmented(pkt) == 1);
+ odp_packet_free(pkt);
+}
+
+void packet_test_event_conversion(void)
+{
+ odp_packet_t pkt = test_packet;
+ odp_packet_t tmp_pkt;
+ odp_event_t ev;
+
+ ev = odp_packet_to_event(pkt);
+ CU_ASSERT_FATAL(ev != ODP_EVENT_INVALID);
+ CU_ASSERT(odp_event_type(ev) == ODP_EVENT_PACKET);
+
+ tmp_pkt = odp_packet_from_event(ev);
+ CU_ASSERT_FATAL(tmp_pkt != ODP_PACKET_INVALID);
+ /** @todo: Need an API to compare packets */
+}
+
+void packet_test_basic_metadata(void)
+{
+ odp_packet_t pkt = test_packet;
+ odp_time_t ts;
+
+ CU_ASSERT_PTR_NOT_NULL(odp_packet_head(pkt));
+ CU_ASSERT_PTR_NOT_NULL(odp_packet_data(pkt));
+
+ CU_ASSERT(odp_packet_pool(pkt) != ODP_POOL_INVALID);
+ /* Packet was allocated by application so shouldn't have valid pktio. */
+ CU_ASSERT(odp_packet_input(pkt) == ODP_PKTIO_INVALID);
+ CU_ASSERT(odp_packet_input_index(pkt) < 0);
+
+ odp_packet_flow_hash_set(pkt, UINT32_MAX);
+ CU_ASSERT(odp_packet_has_flow_hash(pkt));
+ CU_ASSERT(odp_packet_flow_hash(pkt) == UINT32_MAX);
+ odp_packet_has_flow_hash_clr(pkt);
+ CU_ASSERT(!odp_packet_has_flow_hash(pkt));
+
+ ts = odp_time_global();
+ odp_packet_ts_set(pkt, ts);
+ CU_ASSERT_FATAL(odp_packet_has_ts(pkt));
+ CU_ASSERT(!odp_time_cmp(ts, odp_packet_ts(pkt)));
+ odp_packet_has_ts_clr(pkt);
+ CU_ASSERT(!odp_packet_has_ts(pkt));
+}
+
+void packet_test_length(void)
+{
+ odp_packet_t pkt = test_packet;
+ uint32_t buf_len, headroom, tailroom;
+ odp_pool_capability_t capa;
+
+ CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0);
+
+ buf_len = odp_packet_buf_len(pkt);
+ headroom = odp_packet_headroom(pkt);
+ tailroom = odp_packet_tailroom(pkt);
+
+ CU_ASSERT(odp_packet_len(pkt) == packet_len);
+ CU_ASSERT(headroom >= capa.pkt.min_headroom);
+ CU_ASSERT(tailroom >= capa.pkt.min_tailroom);
+
+ CU_ASSERT(buf_len >= packet_len + headroom + tailroom);
+}
+
+void packet_test_prefetch(void)
+{
+ odp_packet_prefetch(test_packet, 0, odp_packet_len(test_packet));
+ CU_PASS();
+}
+
+void packet_test_debug(void)
+{
+ CU_ASSERT(odp_packet_is_valid(test_packet) == 1);
+ odp_packet_print(test_packet);
+}
+
+void packet_test_context(void)
+{
+ odp_packet_t pkt = test_packet;
+ char ptr_test_value = 2;
+ void *prev_ptr;
+ struct udata_struct *udat;
+
+ prev_ptr = odp_packet_user_ptr(pkt);
+ odp_packet_user_ptr_set(pkt, &ptr_test_value);
+ CU_ASSERT(odp_packet_user_ptr(pkt) == &ptr_test_value);
+ odp_packet_user_ptr_set(pkt, prev_ptr);
+
+ udat = odp_packet_user_area(pkt);
+ CU_ASSERT_PTR_NOT_NULL(udat);
+ CU_ASSERT(odp_packet_user_area_size(pkt) ==
+ sizeof(struct udata_struct));
+ CU_ASSERT(memcmp(udat, &test_packet_udata, sizeof(struct udata_struct))
+ == 0);
+
+ odp_packet_reset(pkt, packet_len);
+}
+
+void packet_test_layer_offsets(void)
+{
+ odp_packet_t pkt = test_packet;
+ uint8_t *l2_addr, *l3_addr, *l4_addr;
+ uint32_t seg_len;
+ const uint32_t l2_off = 2;
+ const uint32_t l3_off = l2_off + 14;
+ const uint32_t l4_off = l3_off + 14;
+ int ret;
+
+ /* Set offsets to the same value */
+ ret = odp_packet_l2_offset_set(pkt, l2_off);
+ CU_ASSERT(ret == 0);
+ ret = odp_packet_l3_offset_set(pkt, l2_off);
+ CU_ASSERT(ret == 0);
+ ret = odp_packet_l4_offset_set(pkt, l2_off);
+ CU_ASSERT(ret == 0);
+
+ /* Addresses should be the same */
+ l2_addr = odp_packet_l2_ptr(pkt, &seg_len);
+ CU_ASSERT(seg_len != 0);
+ l3_addr = odp_packet_l3_ptr(pkt, &seg_len);
+ CU_ASSERT(seg_len != 0);
+ l4_addr = odp_packet_l4_ptr(pkt, &seg_len);
+ CU_ASSERT(seg_len != 0);
+ CU_ASSERT_PTR_NOT_NULL(l2_addr);
+ CU_ASSERT(l2_addr == l3_addr);
+ CU_ASSERT(l2_addr == l4_addr);
+
+ /* Set offsets to the different values */
+ odp_packet_l2_offset_set(pkt, l2_off);
+ CU_ASSERT(odp_packet_l2_offset(pkt) == l2_off);
+ odp_packet_l3_offset_set(pkt, l3_off);
+ CU_ASSERT(odp_packet_l3_offset(pkt) == l3_off);
+ odp_packet_l4_offset_set(pkt, l4_off);
+ CU_ASSERT(odp_packet_l4_offset(pkt) == l4_off);
+
+ /* Addresses should not be the same */
+ l2_addr = odp_packet_l2_ptr(pkt, NULL);
+ CU_ASSERT_PTR_NOT_NULL(l2_addr);
+ l3_addr = odp_packet_l3_ptr(pkt, NULL);
+ CU_ASSERT_PTR_NOT_NULL(l3_addr);
+ l4_addr = odp_packet_l4_ptr(pkt, NULL);
+ CU_ASSERT_PTR_NOT_NULL(l4_addr);
+
+ CU_ASSERT(l2_addr != l3_addr);
+ CU_ASSERT(l2_addr != l4_addr);
+ CU_ASSERT(l3_addr != l4_addr);
+}
+
+static void _verify_headroom_shift(odp_packet_t *pkt,
+ int shift)
+{
+ uint32_t room = odp_packet_headroom(*pkt);
+ uint32_t seg_data_len = odp_packet_seg_len(*pkt);
+ uint32_t pkt_data_len = odp_packet_len(*pkt);
+ void *data;
+ char *data_orig = odp_packet_data(*pkt);
+ char *head_orig = odp_packet_head(*pkt);
+ uint32_t seg_len;
+ int extended, rc;
+
+ if (shift >= 0) {
+ if ((uint32_t)abs(shift) <= room) {
+ data = odp_packet_push_head(*pkt, shift);
+ extended = 0;
+ } else {
+ rc = odp_packet_extend_head(pkt, shift,
+ &data, &seg_len);
+ extended = 1;
+ }
+ } else {
+ if ((uint32_t)abs(shift) <= seg_data_len) {
+ data = odp_packet_pull_head(*pkt, -shift);
+ extended = 0;
+ } else {
+ rc = odp_packet_trunc_head(pkt, -shift,
+ &data, &seg_len);
+ extended = 1;
+ }
+ }
+
+ CU_ASSERT_PTR_NOT_NULL(data);
+ if (extended) {
+ CU_ASSERT(rc >= 0);
+ if (shift >= 0) {
+ CU_ASSERT(odp_packet_seg_len(*pkt) == shift - room);
+ } else {
+ CU_ASSERT(odp_packet_headroom(*pkt) >=
+ (uint32_t)abs(shift) - seg_data_len);
+ }
+ CU_ASSERT(odp_packet_head(*pkt) != head_orig);
+ } else {
+ CU_ASSERT(odp_packet_headroom(*pkt) == room - shift);
+ CU_ASSERT(odp_packet_seg_len(*pkt) == seg_data_len + shift);
+ CU_ASSERT(data == data_orig - shift);
+ CU_ASSERT(odp_packet_head(*pkt) == head_orig);
+ }
+
+ CU_ASSERT(odp_packet_len(*pkt) == pkt_data_len + shift);
+ CU_ASSERT(odp_packet_data(*pkt) == data);
+}
+
+void packet_test_headroom(void)
+{
+ odp_packet_t pkt = odp_packet_copy(test_packet,
+ odp_packet_pool(test_packet));
+ uint32_t room;
+ uint32_t seg_data_len;
+ uint32_t push_val, pull_val;
+ odp_pool_capability_t capa;
+
+ CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0);
+
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+ room = odp_packet_headroom(pkt);
+
+ CU_ASSERT(room >= capa.pkt.min_headroom);
+
+ seg_data_len = odp_packet_seg_len(pkt);
+ CU_ASSERT(seg_data_len >= 1);
+ /** @todo: should be len - 1 */
+ pull_val = seg_data_len / 2;
+ push_val = room;
+
+ _verify_headroom_shift(&pkt, -pull_val);
+ _verify_headroom_shift(&pkt, push_val + pull_val);
+ _verify_headroom_shift(&pkt, -push_val);
+ _verify_headroom_shift(&pkt, 0);
+
+ if (segmentation_supported) {
+ push_val = room * 2;
+ _verify_headroom_shift(&pkt, push_val);
+ _verify_headroom_shift(&pkt, 0);
+ _verify_headroom_shift(&pkt, -push_val);
+ }
+
+ odp_packet_free(pkt);
+}
+
+static void _verify_tailroom_shift(odp_packet_t *pkt,
+ int shift)
+{
+ odp_packet_seg_t seg;
+ uint32_t room;
+ uint32_t seg_data_len, pkt_data_len, seg_len;
+ void *tail;
+ char *tail_orig;
+ int extended, rc;
+
+ room = odp_packet_tailroom(*pkt);
+ pkt_data_len = odp_packet_len(*pkt);
+ tail_orig = odp_packet_tail(*pkt);
+
+ seg = odp_packet_last_seg(*pkt);
+ CU_ASSERT(seg != ODP_PACKET_SEG_INVALID);
+ seg_data_len = odp_packet_seg_data_len(*pkt, seg);
+
+ if (shift >= 0) {
+ uint32_t l2_off, l3_off, l4_off;
+
+ l2_off = odp_packet_l2_offset(*pkt);
+ l3_off = odp_packet_l3_offset(*pkt);
+ l4_off = odp_packet_l4_offset(*pkt);
+
+ if ((uint32_t)abs(shift) <= room) {
+ tail = odp_packet_push_tail(*pkt, shift);
+ extended = 0;
+ } else {
+ rc = odp_packet_extend_tail(pkt, shift,
+ &tail, &seg_len);
+ extended = 1;
+ }
+
+ CU_ASSERT(l2_off == odp_packet_l2_offset(*pkt));
+ CU_ASSERT(l3_off == odp_packet_l3_offset(*pkt));
+ CU_ASSERT(l4_off == odp_packet_l4_offset(*pkt));
+ } else {
+ if ((uint32_t)abs(shift) <= seg_data_len) {
+ tail = odp_packet_pull_tail(*pkt, -shift);
+ extended = 0;
+ } else {
+ rc = odp_packet_trunc_tail(pkt, -shift,
+ &tail, &seg_len);
+ extended = 1;
+ }
+ }
+
+ CU_ASSERT_PTR_NOT_NULL(tail);
+ if (extended) {
+ CU_ASSERT(rc >= 0);
+ CU_ASSERT(odp_packet_last_seg(*pkt) != seg);
+ seg = odp_packet_last_seg(*pkt);
+ if (shift > 0) {
+ CU_ASSERT(odp_packet_seg_data_len(*pkt, seg) ==
+ shift - room);
+ } else {
+ CU_ASSERT(odp_packet_tailroom(*pkt) >=
+ (uint32_t)abs(shift) - seg_data_len);
+ CU_ASSERT(seg_len == odp_packet_tailroom(*pkt));
+ }
+ } else {
+ CU_ASSERT(odp_packet_seg_data_len(*pkt, seg) ==
+ seg_data_len + shift);
+ CU_ASSERT(odp_packet_tailroom(*pkt) == room - shift);
+ if (room == 0 || (room - shift) == 0)
+ return;
+ if (shift >= 0) {
+ CU_ASSERT(odp_packet_tail(*pkt) ==
+ tail_orig + shift);
+ } else {
+ CU_ASSERT(tail == tail_orig + shift);
+ }
+ }
+
+ CU_ASSERT(odp_packet_len(*pkt) == pkt_data_len + shift);
+ if (shift >= 0) {
+ CU_ASSERT(tail == tail_orig);
+ } else {
+ CU_ASSERT(odp_packet_tail(*pkt) == tail);
+ }
+}
+
+void packet_test_tailroom(void)
+{
+ odp_packet_t pkt = odp_packet_copy(test_packet,
+ odp_packet_pool(test_packet));
+ odp_packet_seg_t segment;
+ uint32_t room;
+ uint32_t seg_data_len;
+ uint32_t push_val, pull_val;
+ odp_pool_capability_t capa;
+
+ CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0);
+
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+
+ segment = odp_packet_last_seg(pkt);
+ CU_ASSERT(segment != ODP_PACKET_SEG_INVALID);
+ room = odp_packet_tailroom(pkt);
+ CU_ASSERT(room >= capa.pkt.min_tailroom);
+
+ seg_data_len = odp_packet_seg_data_len(pkt, segment);
+ CU_ASSERT(seg_data_len >= 1);
+ /** @todo: should be len - 1 */
+ pull_val = seg_data_len / 2;
+ /* Leave one byte in a tailroom for odp_packet_tail() to succeed */
+ push_val = (room > 0) ? room - 1 : room;
+
+ _verify_tailroom_shift(&pkt, -pull_val);
+ _verify_tailroom_shift(&pkt, push_val + pull_val);
+ _verify_tailroom_shift(&pkt, -push_val);
+ _verify_tailroom_shift(&pkt, 0);
+
+ if (segmentation_supported) {
+ _verify_tailroom_shift(&pkt, pull_val);
+ _verify_tailroom_shift(&pkt, 0);
+ _verify_tailroom_shift(&pkt, -pull_val);
+ }
+
+ odp_packet_free(pkt);
+}
+
+void packet_test_segments(void)
+{
+ int num_segs, seg_index;
+ uint32_t data_len;
+ odp_packet_seg_t seg;
+ odp_packet_t pkt = test_packet;
+ odp_packet_t seg_pkt = segmented_test_packet;
+
+ CU_ASSERT(odp_packet_is_valid(pkt) == 1);
+
+ num_segs = odp_packet_num_segs(pkt);
+ CU_ASSERT(num_segs != 0);
+
+ if (odp_packet_is_segmented(pkt)) {
+ CU_ASSERT(num_segs > 1);
+ } else {
+ CU_ASSERT(num_segs == 1);
+ }
+
+ CU_ASSERT(odp_packet_is_segmented(pkt) == 0);
+ if (segmentation_supported)
+ CU_ASSERT(odp_packet_is_segmented(seg_pkt) == 1);
+
+ seg = odp_packet_first_seg(pkt);
+ data_len = 0;
+ seg_index = 0;
+ while (seg_index < num_segs && seg != ODP_PACKET_SEG_INVALID) {
+ uint32_t seg_data_len;
+ void *seg_data;
+
+ seg_data_len = odp_packet_seg_data_len(pkt, seg);
+ seg_data = odp_packet_seg_data(pkt, seg);
+
+ CU_ASSERT(seg_data_len > 0);
+ CU_ASSERT_PTR_NOT_NULL(seg_data);
+ CU_ASSERT(odp_packet_seg_to_u64(seg) !=
+ odp_packet_seg_to_u64(ODP_PACKET_SEG_INVALID));
+
+ data_len += seg_data_len;
+
+ /** @todo: touch memory in a segment */
+ seg_index++;
+ seg = odp_packet_next_seg(pkt, seg);
+ }
+
+ CU_ASSERT(seg_index == num_segs);
+ CU_ASSERT(data_len <= odp_packet_buf_len(pkt));
+ CU_ASSERT(data_len == odp_packet_len(pkt));
+
+ if (seg_index == num_segs)
+ CU_ASSERT(seg == ODP_PACKET_SEG_INVALID);
+
+ seg = odp_packet_first_seg(seg_pkt);
+ num_segs = odp_packet_num_segs(seg_pkt);
+
+ data_len = 0;
+ seg_index = 0;
+
+ while (seg_index < num_segs && seg != ODP_PACKET_SEG_INVALID) {
+ uint32_t seg_data_len;
+ void *seg_data;
+
+ seg_data_len = odp_packet_seg_data_len(seg_pkt, seg);
+ seg_data = odp_packet_seg_data(seg_pkt, seg);
+
+ CU_ASSERT(seg_data_len > 0);
+ CU_ASSERT(seg_data != NULL);
+ CU_ASSERT(odp_packet_seg_to_u64(seg) !=
+ odp_packet_seg_to_u64(ODP_PACKET_SEG_INVALID));
+
+ data_len += seg_data_len;
+
+ /** @todo: touch memory in a segment */
+ seg_index++;
+ seg = odp_packet_next_seg(seg_pkt, seg);
+ }
+
+ CU_ASSERT(seg_index == num_segs);
+ CU_ASSERT(data_len <= odp_packet_buf_len(seg_pkt));
+ CU_ASSERT(data_len == odp_packet_len(seg_pkt));
+
+ if (seg_index == num_segs)
+ CU_ASSERT(seg == ODP_PACKET_SEG_INVALID);
+}
+
+void packet_test_segment_last(void)
+{
+ odp_packet_t pkt = test_packet;
+ odp_packet_seg_t seg;
+
+ seg = odp_packet_last_seg(pkt);
+ CU_ASSERT_FATAL(seg != ODP_PACKET_SEG_INVALID);
+
+ seg = odp_packet_next_seg(pkt, seg);
+ CU_ASSERT(seg == ODP_PACKET_SEG_INVALID);
+}
+
+#define TEST_INFLAG(packet, flag) \
+do { \
+ odp_packet_has_##flag##_set(packet, 0); \
+ CU_ASSERT(odp_packet_has_##flag(packet) == 0); \
+ odp_packet_has_##flag##_set(packet, 1); \
+ CU_ASSERT(odp_packet_has_##flag(packet) != 0); \
+} while (0)
+
+void packet_test_in_flags(void)
+{
+ odp_packet_t pkt = test_packet;
+
+ TEST_INFLAG(pkt, l2);
+ TEST_INFLAG(pkt, l3);
+ TEST_INFLAG(pkt, l4);
+ TEST_INFLAG(pkt, eth);
+ TEST_INFLAG(pkt, eth_bcast);
+ TEST_INFLAG(pkt, eth_mcast);
+ TEST_INFLAG(pkt, jumbo);
+ TEST_INFLAG(pkt, vlan);
+ TEST_INFLAG(pkt, vlan_qinq);
+ TEST_INFLAG(pkt, arp);
+ TEST_INFLAG(pkt, ipv4);
+ TEST_INFLAG(pkt, ipv6);
+ TEST_INFLAG(pkt, ip_bcast);
+ TEST_INFLAG(pkt, ip_mcast);
+ TEST_INFLAG(pkt, ipfrag);
+ TEST_INFLAG(pkt, ipopt);
+ TEST_INFLAG(pkt, ipsec);
+ TEST_INFLAG(pkt, udp);
+ TEST_INFLAG(pkt, tcp);
+ TEST_INFLAG(pkt, sctp);
+ TEST_INFLAG(pkt, icmp);
+}
+
+void packet_test_error_flags(void)
+{
+ odp_packet_t pkt = test_packet;
+ int err;
+
+ /**
+ * The packet have not been classified so it doesn't have error flags
+ * properly set. Just check that functions return one of allowed values.
+ * @todo: try with known good and bad packets.
+ */
+ err = odp_packet_has_error(pkt);
+ CU_ASSERT(err == 0 || err == 1);
+
+ err = odp_packet_has_l2_error(pkt);
+ CU_ASSERT(err == 0 || err == 1);
+
+ err = odp_packet_has_l3_error(pkt);
+ CU_ASSERT(err == 0 || err == 1);
+
+ err = odp_packet_has_l4_error(pkt);
+ CU_ASSERT(err == 0 || err == 1);
+}
+
+struct packet_metadata {
+ uint32_t l2_off;
+ uint32_t l3_off;
+ uint32_t l4_off;
+ void *usr_ptr;
+ uint64_t usr_u64;
+};
+
+void packet_test_add_rem_data(void)
+{
+ odp_packet_t pkt, new_pkt;
+ uint32_t pkt_len, offset, add_len;
+ void *usr_ptr;
+ struct udata_struct *udat, *new_udat;
+ int ret;
+ odp_pool_capability_t capa;
+ uint32_t min_seg_len;
+
+ CU_ASSERT_FATAL(odp_pool_capability(&capa) == 0);
+
+ min_seg_len = capa.pkt.min_seg_len;
+
+ pkt = odp_packet_alloc(packet_pool, packet_len);
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+
+ pkt_len = odp_packet_len(pkt);
+ usr_ptr = odp_packet_user_ptr(pkt);
+ udat = odp_packet_user_area(pkt);
+ CU_ASSERT(odp_packet_user_area_size(pkt) ==
+ sizeof(struct udata_struct));
+ memcpy(udat, &test_packet_udata, sizeof(struct udata_struct));
+
+ offset = pkt_len / 2;
+
+ if (segmentation_supported) {
+ /* Insert one more packet length in the middle of a packet */
+ add_len = min_seg_len;
+ } else {
+ /* Add diff between largest and smaller packets
+ * which is at least tailroom */
+ add_len = segmented_packet_len - packet_len;
+ }
+
+ new_pkt = pkt;
+ ret = odp_packet_add_data(&new_pkt, offset, add_len);
+ CU_ASSERT(ret >= 0);
+ if (ret < 0)
+ goto free_packet;
+ CU_ASSERT(odp_packet_len(new_pkt) == pkt_len + add_len);
+ /* Verify that user metadata is preserved */
+ CU_ASSERT(odp_packet_user_ptr(new_pkt) == usr_ptr);
+
+ /* Verify that user metadata has been preserved */
+ new_udat = odp_packet_user_area(new_pkt);
+ CU_ASSERT_PTR_NOT_NULL(new_udat);
+ CU_ASSERT(odp_packet_user_area_size(new_pkt) ==
+ sizeof(struct udata_struct));
+ CU_ASSERT(memcmp(new_udat, &test_packet_udata,
+ sizeof(struct udata_struct)) == 0);
+
+ pkt = new_pkt;
+
+ pkt_len = odp_packet_len(pkt);
+ usr_ptr = odp_packet_user_ptr(pkt);
+
+ ret = odp_packet_rem_data(&new_pkt, offset, add_len);
+ CU_ASSERT(ret >= 0);
+ if (ret < 0)
+ goto free_packet;
+ CU_ASSERT(odp_packet_len(new_pkt) == pkt_len - add_len);
+ CU_ASSERT(odp_packet_user_ptr(new_pkt) == usr_ptr);
+
+ /* Verify that user metadata has been preserved */
+ new_udat = odp_packet_user_area(new_pkt);
+ CU_ASSERT_PTR_NOT_NULL(new_udat);
+ CU_ASSERT(odp_packet_user_area_size(new_pkt) ==
+ sizeof(struct udata_struct));
+ CU_ASSERT(memcmp(new_udat, &test_packet_udata,
+ sizeof(struct udata_struct)) == 0);
+
+ pkt = new_pkt;
+
+free_packet:
+ odp_packet_free(pkt);
+}
+
+#define COMPARE_HAS_INFLAG(p1, p2, flag) \
+ CU_ASSERT(odp_packet_has_##flag(p1) == odp_packet_has_##flag(p2))
+
+#define COMPARE_INFLAG(p1, p2, flag) \
+ CU_ASSERT(odp_packet_##flag(p1) == odp_packet_##flag(p2))
+
+static void _packet_compare_inflags(odp_packet_t pkt1, odp_packet_t pkt2)
+{
+ COMPARE_HAS_INFLAG(pkt1, pkt2, l2);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, l3);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, l4);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, eth);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, eth_bcast);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, eth_mcast);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, jumbo);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, vlan);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, vlan_qinq);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, arp);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ipv4);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ipv6);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ip_bcast);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ip_mcast);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ipfrag);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ipopt);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ipsec);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, udp);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, tcp);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, sctp);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, icmp);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, flow_hash);
+ COMPARE_HAS_INFLAG(pkt1, pkt2, ts);
+
+ COMPARE_INFLAG(pkt1, pkt2, color);
+ COMPARE_INFLAG(pkt1, pkt2, drop_eligible);
+ COMPARE_INFLAG(pkt1, pkt2, shaper_len_adjust);
+}
+
+static void _packet_compare_data(odp_packet_t pkt1, odp_packet_t pkt2)
+{
+ uint32_t len = odp_packet_len(pkt1);
+ uint32_t offset = 0;
+ uint32_t seglen1, seglen2, cmplen;
+
+ CU_ASSERT_FATAL(len == odp_packet_len(pkt2));
+
+ while (len > 0) {
+ void *pkt1map = odp_packet_offset(pkt1, offset, &seglen1, NULL);
+ void *pkt2map = odp_packet_offset(pkt2, offset, &seglen2, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(pkt1map);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(pkt2map);
+ cmplen = seglen1 < seglen2 ? seglen1 : seglen2;
+ CU_ASSERT(!memcmp(pkt1map, pkt2map, cmplen));
+
+ offset += cmplen;
+ len -= cmplen;
+ }
+}
+
+static void _packet_compare_udata(odp_packet_t pkt1, odp_packet_t pkt2)
+{
+ uint32_t usize1 = odp_packet_user_area_size(pkt1);
+ uint32_t usize2 = odp_packet_user_area_size(pkt2);
+
+ void *uaddr1 = odp_packet_user_area(pkt1);
+ void *uaddr2 = odp_packet_user_area(pkt2);
+
+ uint32_t cmplen = usize1 <= usize2 ? usize1 : usize2;
+
+ if (cmplen)
+ CU_ASSERT(!memcmp(uaddr1, uaddr2, cmplen));
+}
+
+static void _packet_compare_offset(odp_packet_t pkt1, uint32_t off1,
+ odp_packet_t pkt2, uint32_t off2,
+ uint32_t len)
+{
+ uint32_t seglen1, seglen2, cmplen;
+
+ if (off1 + len > odp_packet_len(pkt1) ||
+ off2 + len > odp_packet_len(pkt2))
+ return;
+
+ while (len > 0) {
+ void *pkt1map = odp_packet_offset(pkt1, off1, &seglen1, NULL);
+ void *pkt2map = odp_packet_offset(pkt2, off2, &seglen2, NULL);
+
+ CU_ASSERT_PTR_NOT_NULL_FATAL(pkt1map);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(pkt2map);
+ cmplen = seglen1 < seglen2 ? seglen1 : seglen2;
+ if (len < cmplen)
+ cmplen = len;
+ CU_ASSERT(!memcmp(pkt1map, pkt2map, cmplen));
+
+ off1 += cmplen;
+ off2 += cmplen;
+ len -= cmplen;
+ }
+}
+
+void packet_test_copy(void)
+{
+ odp_packet_t pkt;
+ odp_packet_t pkt_copy, pkt_part;
+ odp_pool_t pool;
+ uint32_t i, plen, seg_len, src_offset, dst_offset;
+ void *pkt_data;
+
+ pkt = odp_packet_copy(test_packet, packet_pool_no_uarea);
+ CU_ASSERT(pkt == ODP_PACKET_INVALID);
+ if (pkt != ODP_PACKET_INVALID)
+ odp_packet_free(pkt);
+
+ pkt = odp_packet_copy(test_packet, odp_packet_pool(test_packet));
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+ _packet_compare_data(pkt, test_packet);
+ pool = odp_packet_pool(pkt);
+ CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);
+ pkt_copy = odp_packet_copy(pkt, pool);
+ CU_ASSERT_FATAL(pkt_copy != ODP_PACKET_INVALID);
+
+ CU_ASSERT(pkt != pkt_copy);
+ CU_ASSERT(odp_packet_data(pkt) != odp_packet_data(pkt_copy));
+ CU_ASSERT(odp_packet_len(pkt) == odp_packet_len(pkt_copy));
+
+ _packet_compare_inflags(pkt, pkt_copy);
+ _packet_compare_data(pkt, pkt_copy);
+ CU_ASSERT(odp_packet_user_area_size(pkt) ==
+ odp_packet_user_area_size(test_packet));
+ _packet_compare_udata(pkt, pkt_copy);
+ odp_packet_free(pkt_copy);
+ odp_packet_free(pkt);
+
+ pkt = odp_packet_copy(test_packet, packet_pool_double_uarea);
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+ _packet_compare_data(pkt, test_packet);
+ pool = odp_packet_pool(pkt);
+ CU_ASSERT_FATAL(pool != ODP_POOL_INVALID);
+ pkt_copy = odp_packet_copy(pkt, pool);
+ CU_ASSERT_FATAL(pkt_copy != ODP_PACKET_INVALID);
+
+ CU_ASSERT(pkt != pkt_copy);
+ CU_ASSERT(odp_packet_data(pkt) != odp_packet_data(pkt_copy));
+ CU_ASSERT(odp_packet_len(pkt) == odp_packet_len(pkt_copy));
+
+ _packet_compare_inflags(pkt, pkt_copy);
+ _packet_compare_data(pkt, pkt_copy);
+ CU_ASSERT(odp_packet_user_area_size(pkt) ==
+ 2 * odp_packet_user_area_size(test_packet));
+ _packet_compare_udata(pkt, pkt_copy);
+ _packet_compare_udata(pkt, test_packet);
+ odp_packet_free(pkt_copy);
+
+ /* Now test copy_part */
+ pkt_part = odp_packet_copy_part(pkt, 0, odp_packet_len(pkt) + 1, pool);
+ CU_ASSERT(pkt_part == ODP_PACKET_INVALID);
+ pkt_part = odp_packet_copy_part(pkt, odp_packet_len(pkt), 1, pool);
+ CU_ASSERT(pkt_part == ODP_PACKET_INVALID);
+
+ pkt_part = odp_packet_copy_part(pkt, 0, odp_packet_len(pkt), pool);
+ CU_ASSERT_FATAL(pkt_part != ODP_PACKET_INVALID);
+ CU_ASSERT(pkt != pkt_part);
+ CU_ASSERT(odp_packet_data(pkt) != odp_packet_data(pkt_part));
+ CU_ASSERT(odp_packet_len(pkt) == odp_packet_len(pkt_part));
+
+ _packet_compare_data(pkt, pkt_part);
+ odp_packet_free(pkt_part);
+
+ plen = odp_packet_len(pkt);
+ for (i = 0; i < plen / 2; i += 5) {
+ pkt_part = odp_packet_copy_part(pkt, i, plen / 4, pool);
+ CU_ASSERT_FATAL(pkt_part != ODP_PACKET_INVALID);
+ CU_ASSERT(odp_packet_len(pkt_part) == plen / 4);
+ _packet_compare_offset(pkt_part, 0, pkt, i, plen / 4);
+ odp_packet_free(pkt_part);
+ }
+
+ /* Test copy and move apis */
+ CU_ASSERT(odp_packet_copy_data(pkt, 0, plen - plen / 8, plen / 8) == 0);
+ _packet_compare_offset(pkt, 0, pkt, plen - plen / 8, plen / 8);
+ _packet_compare_offset(pkt, 0, test_packet, plen - plen / 8, plen / 8);
+
+ /* Test segment crossing if we support segments */
+ pkt_data = odp_packet_offset(pkt, 0, &seg_len, NULL);
+ CU_ASSERT(pkt_data != NULL);
+
+ if (seg_len < plen) {
+ src_offset = seg_len - 15;
+ dst_offset = seg_len - 5;
+ } else {
+ src_offset = seg_len - 40;
+ dst_offset = seg_len - 25;
+ }
+
+ pkt_part = odp_packet_copy_part(pkt, src_offset, 20, pool);
+ CU_ASSERT(odp_packet_move_data(pkt, dst_offset, src_offset, 20) == 0);
+ _packet_compare_offset(pkt, dst_offset, pkt_part, 0, 20);
+
+ odp_packet_free(pkt_part);
+ odp_packet_free(pkt);
+}
+
+void packet_test_copydata(void)
+{
+ odp_packet_t pkt = test_packet;
+ uint32_t pkt_len = odp_packet_len(pkt);
+ uint8_t *data_buf;
+ uint32_t i;
+ int correct_memory;
+
+ CU_ASSERT_FATAL(pkt_len > 0);
+
+ data_buf = malloc(pkt_len);
+ CU_ASSERT_PTR_NOT_NULL_FATAL(data_buf);
+
+ for (i = 0; i < pkt_len; i++)
+ data_buf[i] = (uint8_t)i;
+
+ CU_ASSERT(!odp_packet_copy_from_mem(pkt, 0, pkt_len, data_buf));
+ memset(data_buf, 0, pkt_len);
+ CU_ASSERT(!odp_packet_copy_to_mem(pkt, 0, pkt_len, data_buf));
+
+ correct_memory = 1;
+ for (i = 0; i < pkt_len; i++)
+ if (data_buf[i] != (uint8_t)i) {
+ correct_memory = 0;
+ break;
+ }
+ CU_ASSERT(correct_memory);
+
+ free(data_buf);
+
+ pkt = odp_packet_alloc(odp_packet_pool(test_packet), pkt_len / 2);
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+
+ CU_ASSERT(odp_packet_copy_from_pkt(pkt, 0, test_packet, 0,
+ pkt_len) < 0);
+ CU_ASSERT(odp_packet_copy_from_pkt(pkt, pkt_len, test_packet, 0,
+ 1) < 0);
+
+ for (i = 0; i < pkt_len / 2; i++) {
+ CU_ASSERT(odp_packet_copy_from_pkt(pkt, i, test_packet, i,
+ 1) == 0);
+ }
+
+ _packet_compare_offset(pkt, 0, test_packet, 0, pkt_len / 2);
+ odp_packet_free(pkt);
+
+ pkt = odp_packet_alloc(odp_packet_pool(segmented_test_packet),
+ odp_packet_len(segmented_test_packet) / 2);
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+
+ CU_ASSERT(odp_packet_copy_from_pkt(pkt, 0, segmented_test_packet,
+ odp_packet_len(pkt) / 4,
+ odp_packet_len(pkt)) == 0);
+ _packet_compare_offset(pkt, 0, segmented_test_packet,
+ odp_packet_len(pkt) / 4,
+ odp_packet_len(pkt));
+ odp_packet_free(pkt);
+}
+
+void packet_test_concatsplit(void)
+{
+ odp_packet_t pkt, pkt2;
+ uint32_t pkt_len;
+ odp_packet_t splits[4];
+
+ pkt = odp_packet_copy(test_packet, odp_packet_pool(test_packet));
+ pkt_len = odp_packet_len(test_packet);
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+
+ CU_ASSERT(odp_packet_concat(&pkt, pkt) == 0);
+ CU_ASSERT(odp_packet_len(pkt) == pkt_len * 2);
+ _packet_compare_offset(pkt, 0, pkt, pkt_len, pkt_len);
+
+ CU_ASSERT(odp_packet_split(&pkt, pkt_len, &pkt2) == 0);
+ CU_ASSERT(pkt != pkt2);
+ CU_ASSERT(odp_packet_data(pkt) != odp_packet_data(pkt2));
+ CU_ASSERT(odp_packet_len(pkt) == odp_packet_len(pkt2));
+ _packet_compare_data(pkt, pkt2);
+ _packet_compare_data(pkt, test_packet);
+
+ odp_packet_free(pkt);
+ odp_packet_free(pkt2);
+
+ pkt = odp_packet_copy(segmented_test_packet,
+ odp_packet_pool(segmented_test_packet));
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+ pkt_len = odp_packet_len(pkt);
+
+ _packet_compare_data(pkt, segmented_test_packet);
+ CU_ASSERT(odp_packet_split(&pkt, pkt_len / 2, &splits[0]) == 0);
+ CU_ASSERT(pkt != splits[0]);
+ CU_ASSERT(odp_packet_data(pkt) != odp_packet_data(splits[0]));
+ CU_ASSERT(odp_packet_len(pkt) == pkt_len / 2);
+ CU_ASSERT(odp_packet_len(pkt) + odp_packet_len(splits[0]) == pkt_len);
+
+ _packet_compare_offset(pkt, 0, segmented_test_packet, 0, pkt_len / 2);
+ _packet_compare_offset(splits[0], 0, segmented_test_packet,
+ pkt_len / 2, odp_packet_len(splits[0]));
+
+ CU_ASSERT(odp_packet_concat(&pkt, splits[0]) == 0);
+ _packet_compare_offset(pkt, 0, segmented_test_packet, 0, pkt_len / 2);
+ _packet_compare_offset(pkt, pkt_len / 2, segmented_test_packet,
+ pkt_len / 2, pkt_len / 2);
+ _packet_compare_offset(pkt, 0, segmented_test_packet, 0,
+ pkt_len);
+
+ CU_ASSERT(odp_packet_len(pkt) == odp_packet_len(segmented_test_packet));
+ _packet_compare_data(pkt, segmented_test_packet);
+
+ CU_ASSERT(odp_packet_split(&pkt, pkt_len / 2, &splits[0]) == 0);
+ CU_ASSERT(odp_packet_split(&pkt, pkt_len / 4, &splits[1]) == 0);
+ CU_ASSERT(odp_packet_split(&pkt, pkt_len / 8, &splits[2]) == 0);
+
+ CU_ASSERT(odp_packet_len(splits[0]) + odp_packet_len(splits[1]) +
+ odp_packet_len(splits[2]) + odp_packet_len(pkt) == pkt_len);
+
+ CU_ASSERT(odp_packet_concat(&pkt, splits[2]) == 0);
+ CU_ASSERT(odp_packet_concat(&pkt, splits[1]) == 0);
+ CU_ASSERT(odp_packet_concat(&pkt, splits[0]) == 0);
+
+ CU_ASSERT(odp_packet_len(pkt) == odp_packet_len(segmented_test_packet));
+ _packet_compare_data(pkt, segmented_test_packet);
+
+ odp_packet_free(pkt);
+}
+
+void packet_test_align(void)
+{
+ odp_packet_t pkt;
+ uint32_t pkt_len, seg_len, offset, aligned_seglen;
+ void *pkt_data, *aligned_data;
+ const uint32_t max_align = 32;
+
+ pkt = odp_packet_copy_part(segmented_test_packet, 0,
+ odp_packet_len(segmented_test_packet) / 2,
+ odp_packet_pool(segmented_test_packet));
+ CU_ASSERT_FATAL(pkt != ODP_PACKET_INVALID);
+
+ pkt_len = odp_packet_len(pkt);
+ seg_len = odp_packet_seg_len(pkt);
+
+ if (odp_packet_is_segmented(pkt)) {
+ /* Can't address across segment boundaries */
+ CU_ASSERT(odp_packet_align(&pkt, 0, pkt_len, 0) < 0);
+
+ offset = seg_len - 5;
+ (void)odp_packet_offset(pkt, offset, &seg_len, NULL);
+
+ /* Realign for addressability */
+ CU_ASSERT(odp_packet_align(&pkt, offset,
+ seg_len + 2, 0) >= 0);
+
+ /* Alignment doesn't change packet length or contents */
+ CU_ASSERT(odp_packet_len(pkt) == pkt_len);
+ (void)odp_packet_offset(pkt, offset, &aligned_seglen, NULL);
+ _packet_compare_offset(pkt, offset,
+ segmented_test_packet, offset,
+ aligned_seglen);
+
+ /* Verify requested contiguous addressabilty */
+ CU_ASSERT(aligned_seglen >= seg_len + 2);
+ }
+
+ /* Get a misaligned address */
+ pkt_data = odp_packet_offset(pkt, 0, &seg_len, NULL);
+ offset = seg_len - 5;
+ pkt_data = odp_packet_offset(pkt, offset, &seg_len, NULL);
+ if ((uintptr_t)pkt_data % max_align == 0) {
+ offset--;
+ pkt_data = odp_packet_offset(pkt, offset, &seg_len, NULL);
+ }
+
+ /* Realign for alignment */
+ CU_ASSERT(odp_packet_align(&pkt, offset, 1, max_align) >= 0);
+ aligned_data = odp_packet_offset(pkt, offset, &aligned_seglen, NULL);
+
+ CU_ASSERT(odp_packet_len(pkt) == pkt_len);
+ _packet_compare_offset(pkt, offset, segmented_test_packet, offset,
+ aligned_seglen);
+ CU_ASSERT((uintptr_t)aligned_data % max_align == 0);
+
+ odp_packet_free(pkt);
+}
+
+void packet_test_offset(void)
+{
+ odp_packet_t pkt = test_packet;
+ uint32_t seg_len, full_seg_len;
+ odp_packet_seg_t seg;
+ uint8_t *ptr, *start_ptr;
+ uint32_t offset;
+
+ ptr = odp_packet_offset(pkt, 0, &seg_len, &seg);
+ CU_ASSERT(seg != ODP_PACKET_SEG_INVALID);
+ CU_ASSERT(seg_len > 1);
+ CU_ASSERT(seg_len == odp_packet_seg_len(pkt));
+ CU_ASSERT(seg_len == odp_packet_seg_data_len(pkt, seg));
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ CU_ASSERT(ptr == odp_packet_data(pkt));
+ CU_ASSERT(ptr == odp_packet_seg_data(pkt, seg));
+
+ /* Query a second byte */
+ start_ptr = ptr;
+ full_seg_len = seg_len;
+ offset = 1;
+
+ ptr = odp_packet_offset(pkt, offset, &seg_len, NULL);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ CU_ASSERT(ptr == start_ptr + offset);
+ CU_ASSERT(seg_len == full_seg_len - offset);
+
+ /* Query the last byte in a segment */
+ offset = full_seg_len - 1;
+
+ ptr = odp_packet_offset(pkt, offset, &seg_len, NULL);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ CU_ASSERT(ptr == start_ptr + offset);
+ CU_ASSERT(seg_len == full_seg_len - offset);
+
+ /* Query the last byte in a packet */
+ offset = odp_packet_len(pkt) - 1;
+ ptr = odp_packet_offset(pkt, offset, &seg_len, NULL);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+ CU_ASSERT(seg_len == 1);
+
+ /* Pass NULL to [out] arguments */
+ ptr = odp_packet_offset(pkt, 0, NULL, NULL);
+ CU_ASSERT_PTR_NOT_NULL(ptr);
+}
+
+odp_testinfo_t packet_suite[] = {
+ ODP_TEST_INFO(packet_test_alloc_free),
+ ODP_TEST_INFO(packet_test_alloc_free_multi),
+ ODP_TEST_INFO(packet_test_alloc_segmented),
+ ODP_TEST_INFO(packet_test_basic_metadata),
+ ODP_TEST_INFO(packet_test_debug),
+ ODP_TEST_INFO(packet_test_segments),
+ ODP_TEST_INFO(packet_test_length),
+ ODP_TEST_INFO(packet_test_prefetch),
+ ODP_TEST_INFO(packet_test_headroom),
+ ODP_TEST_INFO(packet_test_tailroom),
+ ODP_TEST_INFO(packet_test_context),
+ ODP_TEST_INFO(packet_test_event_conversion),
+ ODP_TEST_INFO(packet_test_layer_offsets),
+ ODP_TEST_INFO(packet_test_segment_last),
+ ODP_TEST_INFO(packet_test_in_flags),
+ ODP_TEST_INFO(packet_test_error_flags),
+ ODP_TEST_INFO(packet_test_add_rem_data),
+ ODP_TEST_INFO(packet_test_copy),
+ ODP_TEST_INFO(packet_test_copydata),
+ ODP_TEST_INFO(packet_test_concatsplit),
+ ODP_TEST_INFO(packet_test_align),
+ ODP_TEST_INFO(packet_test_offset),
+ ODP_TEST_INFO_NULL,
+};
+
+odp_suiteinfo_t packet_suites[] = {
+ { .pName = "packet tests",
+ .pTests = packet_suite,
+ .pInitFunc = packet_suite_init,
+ .pCleanupFunc = packet_suite_term,
+ },
+ ODP_SUITE_INFO_NULL,
+};
+
+int packet_main(int argc, char *argv[])
+{
+ int ret;
+
+ /* parse common options: */
+ if (odp_cunit_parse_options(argc, argv))
+ return -1;
+
+ ret = odp_cunit_register(packet_suites);
+
+ if (ret == 0)
+ ret = odp_cunit_run();
+
+ return ret;
+}
diff --git a/test/common_plat/validation/api/packet/packet.h b/test/common_plat/validation/api/packet/packet.h
new file mode 100644
index 000000000..10a377cf0
--- /dev/null
+++ b/test/common_plat/validation/api/packet/packet.h
@@ -0,0 +1,49 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef _ODP_TEST_PACKET_H_
+#define _ODP_TEST_PACKET_H_
+
+#include <odp_cunit_common.h>
+
+/* test functions: */
+void packet_test_alloc_free(void);
+void packet_test_alloc_free_multi(void);
+void packet_test_alloc_segmented(void);
+void packet_test_event_conversion(void);
+void packet_test_basic_metadata(void);
+void packet_test_length(void);
+void packet_test_prefetch(void);
+void packet_test_debug(void);
+void packet_test_context(void);
+void packet_test_layer_offsets(void);
+void packet_test_headroom(void);
+void packet_test_tailroom(void);
+void packet_test_segments(void);
+void packet_test_segment_last(void);
+void packet_test_in_flags(void);
+void packet_test_error_flags(void);
+void packet_test_add_rem_data(void);
+void packet_test_copy(void);
+void packet_test_copydata(void);
+void packet_test_concatsplit(void);
+void packet_test_align(void);
+void packet_test_offset(void);
+
+/* test arrays: */
+extern odp_testinfo_t packet_suite[];
+
+/* test array init/term functions: */
+int packet_suite_init(void);
+int packet_suite_term(void);
+
+/* test registry: */
+extern odp_suiteinfo_t packet_suites[];
+
+/* main test program: */
+int packet_main(int argc, char *argv[]);
+
+#endif
diff --git a/test/common_plat/validation/api/packet/packet_main.c b/test/common_plat/validation/api/packet/packet_main.c
new file mode 100644
index 000000000..511bb104b
--- /dev/null
+++ b/test/common_plat/validation/api/packet/packet_main.c
@@ -0,0 +1,12 @@
+/* Copyright (c) 2015, Linaro Limited
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include "packet.h"
+
+int main(int argc, char *argv[])
+{
+ return packet_main(argc, argv);
+}