diff options
Diffstat (limited to 'test/common_plat/validation/api/packet')
-rw-r--r-- | test/common_plat/validation/api/packet/.gitignore | 1 | ||||
-rw-r--r-- | test/common_plat/validation/api/packet/Makefile.am | 10 | ||||
-rw-r--r-- | test/common_plat/validation/api/packet/packet.c | 1369 | ||||
-rw-r--r-- | test/common_plat/validation/api/packet/packet.h | 49 | ||||
-rw-r--r-- | test/common_plat/validation/api/packet/packet_main.c | 12 |
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(¶ms); + + 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", ¶ms); + if (packet_pool == ODP_POOL_INVALID) + return -1; + + params.pkt.uarea_size = 0; + packet_pool_no_uarea = odp_pool_create("packet_pool_no_uarea", + ¶ms); + 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", + ¶ms); + + 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(¶ms); + + 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", ¶ms); + + /* 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(¶ms); + + 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", ¶ms); + pool[1] = odp_pool_create("packet_pool_alloc_multi_1", ¶ms); + 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); +} |