diff options
Diffstat (limited to 'helper')
30 files changed, 587 insertions, 4102 deletions
diff --git a/helper/Makefile.am b/helper/Makefile.am index 54d4fbf66..5dd078596 100644 --- a/helper/Makefile.am +++ b/helper/Makefile.am @@ -20,7 +20,7 @@ helperinclude_HEADERS = \ include/odp/helper/autoheader_external.h\ include/odp/helper/deprecated.h\ include/odp/helper/chksum.h\ - include/odp/helper/odph_debug.h \ + include/odp/helper/debug.h \ include/odp/helper/eth.h\ include/odp/helper/gtp.h\ include/odp/helper/icmp.h\ @@ -29,14 +29,11 @@ helperinclude_HEADERS = \ include/odp/helper/ipsec.h\ include/odp/helper/macros.h\ include/odp/helper/odph_api.h\ - include/odp/helper/odph_cuckootable.h\ - include/odp/helper/odph_hashtable.h\ - include/odp/helper/odph_iplookuptable.h\ - include/odp/helper/odph_lineartable.h\ include/odp/helper/sctp.h \ + include/odp/helper/stress.h\ + include/odp/helper/string.h\ include/odp/helper/strong_types.h\ include/odp/helper/tcp.h\ - include/odp/helper/table.h\ include/odp/helper/threads.h \ include/odp/helper/udp.h \ include/odp/helper/version.h @@ -56,17 +53,10 @@ helperinclude_HEADERS += \ include/odp/helper/cli.h endif -noinst_HEADERS = \ - include/odph_list_internal.h - __LIB__libodphelper_la_SOURCES = \ eth.c \ ip.c \ chksum.c \ - hashtable.c \ - lineartable.c \ - cuckootable.c \ - iplookuptable.c \ ipsec.c \ threads.c \ version.c @@ -86,7 +76,7 @@ __LIB__libodphelper_la_LIBADD += $(LIBCLI_LIBS) lib_LTLIBRARIES = $(LIB)/libodphelper.la -CHECK_GLOBALS_REGEX = " (odph_|_deprecated_odph_)" +CHECK_GLOBALS_REGEX = " (odph_|_deprecated_odph_|__odr_asan)" TESTS_ENVIRONMENT = \ LIBTOOL="$(LIBTOOL)" \ diff --git a/helper/cli.c b/helper/cli.c index 4ce4bf62e..dc6491f6b 100644 --- a/helper/cli.c +++ b/helper/cli.c @@ -153,13 +153,13 @@ int odph_cli_register_command(const char *name, odph_cli_user_cmd_func_t func, cmd->fn = func; - if (strlen(name) >= MAX_NAME_LEN - 1) { + if (strlen(name) >= MAX_NAME_LEN) { ODPH_ERR("Error: command name too long\n"); goto error; } strcpy(cmd->name, name); - if (strlen(help) >= MAX_HELP_LEN - 1) { + if (strlen(help) >= MAX_HELP_LEN) { ODPH_ERR("Error: command help too long\n"); goto error; } diff --git a/helper/cuckootable.c b/helper/cuckootable.c deleted file mode 100644 index 85f715b3c..000000000 --- a/helper/cuckootable.c +++ /dev/null @@ -1,776 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2016-2018 Linaro Limited - */ - -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2016 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. - */ - -#include <string.h> -#include <stdint.h> -#include <errno.h> -#include <stdio.h> - -#include <odp/helper/odph_cuckootable.h> -#include <odp/helper/odph_debug.h> -#include <odp_api.h> - -/* More efficient access to a map of single ullong */ -#define ULLONG_FOR_EACH_1(IDX, MAP) \ - for (; MAP && (((IDX) = __builtin_ctzll(MAP)), true); \ - MAP = (MAP & (MAP - 1))) - -/** @magic word, write to the first byte of the memory block - * to indicate this block is used by a cuckoo hash table - */ -#define ODPH_CUCKOO_TABLE_MAGIC_WORD 0xDFDFFDFD - -/** Number of items per bucket. */ -#define HASH_BUCKET_ENTRIES 4 - -#define NULL_SIGNATURE 0 -#define KEY_ALIGNMENT 16 - -/** Maximum size of hash table that can be created. */ -#define HASH_ENTRIES_MAX 1048576 - -/** @internal signature struct - * Structure storing both primary and secondary hashes - */ -struct cuckoo_table_signatures { - union { - struct { - uint32_t current; - uint32_t alt; - }; - uint64_t sig; - }; -}; - -/** @internal kay-value struct - * Structure that stores key-value pair - */ -struct cuckoo_table_key_value { - uint8_t *key; - uint8_t *value; -}; - -/** @internal bucket structure - * Put the elements with different keys but a same signature - * into a bucket, and each bucket has at most HASH_BUCKET_ENTRIES - * elements. - */ -struct ODP_ALIGNED_CACHE cuckoo_table_bucket { - struct cuckoo_table_signatures signatures[HASH_BUCKET_ENTRIES]; - /* Includes dummy key index that always contains index 0 */ - odp_buffer_t key_buf[HASH_BUCKET_ENTRIES + 1]; - uint8_t flag[HASH_BUCKET_ENTRIES]; -}; - -/* More efficient access to a map of single ullong */ -#define ULLONG_FOR_EACH_1(IDX, MAP) \ - for (; MAP && (((IDX) = __builtin_ctzll(MAP)), true); \ - MAP = (MAP & (MAP - 1))) - -/** A hash table structure. */ -typedef struct ODP_ALIGNED_CACHE { - /**< for check */ - uint32_t magicword; - /**< Name of the hash. */ - char name[ODPH_TABLE_NAME_LEN]; - /**< Total table entries. */ - uint32_t entries; - /**< Number of buckets in table. */ - uint32_t num_buckets; - /**< Length of hash key. */ - uint32_t key_len; - /**< Length of value. */ - uint32_t value_len; - /**< Bitmask for getting bucket index from hash signature. */ - uint32_t bucket_bitmask; - /**< Queue that stores all free key-value slots*/ - odp_queue_t free_slots; - /** Table with buckets storing all the hash values and key indexes - to the key table*/ - struct cuckoo_table_bucket *buckets; -} odph_cuckoo_table_impl; - -/** - * Aligns input parameter to the next power of 2 - * - * @param x - * The integer value to algin - * - * @return - * Input parameter aligned to the next power of 2 - */ -static inline uint32_t -align32pow2(uint32_t x) -{ - x--; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - - return x + 1; -} - -odph_table_t -odph_cuckoo_table_lookup(const char *name) -{ - odph_cuckoo_table_impl *tbl = NULL; - odp_shm_t shm; - - if (name == NULL || strlen(name) >= ODPH_TABLE_NAME_LEN) - return NULL; - - shm = odp_shm_lookup(name); - if (shm != ODP_SHM_INVALID) - tbl = (odph_cuckoo_table_impl *)odp_shm_addr(shm); - if (!tbl || tbl->magicword != ODPH_CUCKOO_TABLE_MAGIC_WORD) - return NULL; - - if (strcmp(tbl->name, name)) - return NULL; - - return (odph_table_t)tbl; -} - -odph_table_t -odph_cuckoo_table_create( - const char *name, uint32_t capacity, uint32_t key_size, - uint32_t value_size) -{ - odph_cuckoo_table_impl *tbl; - odp_shm_t shm_tbl; - - odp_pool_t pool; - odp_pool_param_t param; - - odp_queue_t queue; - odp_queue_param_t qparam; - odp_queue_capability_t qcapa; - odp_pool_capability_t pcapa; - - char pool_name[ODPH_TABLE_NAME_LEN + 3], - queue_name[ODPH_TABLE_NAME_LEN + 3]; - unsigned i; - uint32_t impl_size, kv_entry_size, - bucket_num, bucket_size; - - if (odp_queue_capability(&qcapa)) { - ODPH_DBG("queue capa failed\n"); - return NULL; - } - - if (qcapa.plain.max_size && qcapa.plain.max_size < capacity) { - ODPH_DBG("queue max_size too small\n"); - return NULL; - } - - if (odp_pool_capability(&pcapa)) { - ODPH_DBG("pool capa failed\n"); - return NULL; - } - - if (pcapa.buf.max_num && pcapa.buf.max_num < capacity) { - ODPH_DBG("pool max_num too small\n"); - return NULL; - } - - /* Check for valid parameters */ - if ( - (capacity > HASH_ENTRIES_MAX) || - (capacity < HASH_BUCKET_ENTRIES) || - (key_size == 0) || - (strlen(name) == 0)) { - ODPH_DBG("invalid parameters\n"); - return NULL; - } - - /* Guarantee there's no existing */ - tbl = (odph_cuckoo_table_impl *)(void *)odph_cuckoo_table_lookup(name); - if (tbl != NULL) { - ODPH_DBG("cuckoo hash table %s already exists\n", name); - return NULL; - } - - /* Calculate the sizes of different parts of cuckoo hash table */ - impl_size = sizeof(odph_cuckoo_table_impl); - kv_entry_size = sizeof(struct cuckoo_table_key_value) - + key_size + value_size; - - bucket_num = align32pow2(capacity) / HASH_BUCKET_ENTRIES; - bucket_size = bucket_num * sizeof(struct cuckoo_table_bucket); - - shm_tbl = odp_shm_reserve(name, impl_size + bucket_size, - ODP_CACHE_LINE_SIZE, 0); - - if (shm_tbl == ODP_SHM_INVALID) { - ODPH_DBG( - "shm allocation failed for odph_cuckoo_table_impl %s\n", - name); - return NULL; - } - - tbl = (odph_cuckoo_table_impl *)odp_shm_addr(shm_tbl); - memset(tbl, 0, impl_size + bucket_size); - - /* header of this mem block is the table impl struct, - * then the bucket pool. - */ - tbl->buckets = (void *)((char *)tbl + impl_size); - - /* initialize key-value buffer pool */ - snprintf(pool_name, sizeof(pool_name), "kv_%s", name); - pool = odp_pool_lookup(pool_name); - - if (pool != ODP_POOL_INVALID) - if (odp_pool_destroy(pool)) { - odp_shm_free(shm_tbl); - ODPH_DBG("failed to destroy pre-existing pool\n"); - return NULL; - } - - odp_pool_param_init(¶m); - param.type = ODP_POOL_BUFFER; - param.buf.size = kv_entry_size; - if (pcapa.buf.max_align >= ODP_CACHE_LINE_SIZE) - param.buf.align = ODP_CACHE_LINE_SIZE; - param.buf.num = capacity; - - pool = odp_pool_create(pool_name, ¶m); - - if (pool == ODP_POOL_INVALID) { - ODPH_DBG("failed to create key-value pool\n"); - odp_shm_free(shm_tbl); - return NULL; - } - - /* initialize free_slots queue */ - odp_queue_param_init(&qparam); - qparam.type = ODP_QUEUE_TYPE_PLAIN; - qparam.size = capacity; - - snprintf(queue_name, sizeof(queue_name), "fs_%s", name); - queue = odp_queue_create(queue_name, &qparam); - if (queue == ODP_QUEUE_INVALID) { - ODPH_DBG("failed to create free_slots queue\n"); - (void)odp_pool_destroy(pool); - odp_shm_free(shm_tbl); - return NULL; - } - - /* Setup hash context */ - snprintf(tbl->name, sizeof(tbl->name), "%s", name); - tbl->magicword = ODPH_CUCKOO_TABLE_MAGIC_WORD; - tbl->entries = capacity; - tbl->key_len = key_size; - tbl->value_len = value_size; - tbl->num_buckets = bucket_num; - tbl->bucket_bitmask = bucket_num - 1; - tbl->free_slots = queue; - - /* generate all free buffers, and put into queue */ - for (i = 0; i < capacity; i++) { - odp_event_t ev = odp_buffer_to_event( - odp_buffer_alloc(pool)); - if (ev == ODP_EVENT_INVALID) { - ODPH_DBG("failed to generate free slots\n"); - odph_cuckoo_table_destroy((odph_table_t)tbl); - return NULL; - } - - if (odp_queue_enq(queue, ev) < 0) { - ODPH_DBG("failed to enqueue free slots\n"); - odph_cuckoo_table_destroy((odph_table_t)tbl); - return NULL; - } - } - - return (odph_table_t)tbl; -} - -int -odph_cuckoo_table_destroy(odph_table_t tbl) -{ - int ret; - odph_cuckoo_table_impl *impl = NULL; - char pool_name[ODPH_TABLE_NAME_LEN + 3]; - odp_event_t ev; - odp_shm_t shm; - odp_pool_t pool; - uint32_t i, j; - - if (tbl == NULL) - return -1; - - impl = (odph_cuckoo_table_impl *)(void *)tbl; - - /* check magic word */ - if (impl->magicword != ODPH_CUCKOO_TABLE_MAGIC_WORD) { - ODPH_DBG("wrong magicword for cuckoo table\n"); - return -1; - } - - /* free all used buffers*/ - for (i = 0; i < impl->num_buckets; i++) { - for (j = 0; j < HASH_BUCKET_ENTRIES; j++) { - if (impl->buckets[i].signatures[j].current - != NULL_SIGNATURE) - odp_buffer_free(impl->buckets[i].key_buf[j]); - } - } - - /* free all free buffers */ - while ((ev = odp_queue_deq(impl->free_slots)) - != ODP_EVENT_INVALID) { - odp_buffer_free(odp_buffer_from_event(ev)); - } - - /* destroy free_slots queue */ - ret = odp_queue_destroy(impl->free_slots); - if (ret < 0) - ODPH_DBG("failed to destroy free_slots queue\n"); - - /* destroy key-value pool */ - snprintf(pool_name, sizeof(pool_name), "kv_%s", impl->name); - pool = odp_pool_lookup(pool_name); - if (pool == ODP_POOL_INVALID) { - ODPH_DBG("invalid pool\n"); - return -1; - } - - ret = odp_pool_destroy(pool); - if (ret != 0) { - ODPH_DBG("failed to destroy key-value buffer pool\n"); - return -1; - } - - /* free impl */ - shm = odp_shm_lookup(impl->name); - if (shm == ODP_SHM_INVALID) { - ODPH_DBG("unable look up shm\n"); - return -1; - } - - return odp_shm_free(shm); -} - -static uint32_t hash(const odph_cuckoo_table_impl *h, const void *key) -{ - /* calc hash result by key */ - return odp_hash_crc32c(key, h->key_len, 0); -} - -/* Calc the secondary hash value from the primary hash value of a given key */ -static inline uint32_t -hash_secondary(const uint32_t primary_hash) -{ - static const unsigned all_bits_shift = 12; - static const unsigned alt_bits_xor = 0x5bd1e995; - - uint32_t tag = primary_hash >> all_bits_shift; - - return (primary_hash ^ ((tag + 1) * alt_bits_xor)); -} - -/* Search for an entry that can be pushed to its alternative location */ -static inline int -make_space_bucket( - const odph_cuckoo_table_impl *impl, - struct cuckoo_table_bucket *bkt) -{ - unsigned i, j; - int ret; - uint32_t next_bucket_idx; - struct cuckoo_table_bucket *next_bkt[HASH_BUCKET_ENTRIES]; - - /* - * Push existing item (search for bucket with space in - * alternative locations) to its alternative location - */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - /* Search for space in alternative locations */ - next_bucket_idx = bkt->signatures[i].alt & impl->bucket_bitmask; - next_bkt[i] = &impl->buckets[next_bucket_idx]; - for (j = 0; j < HASH_BUCKET_ENTRIES; j++) { - if (next_bkt[i]->signatures[j].sig == NULL_SIGNATURE) - break; - } - - if (j != HASH_BUCKET_ENTRIES) - break; - } - - /* Alternative location has spare room (end of recursive function) */ - if (i != HASH_BUCKET_ENTRIES) { - next_bkt[i]->signatures[j].alt = bkt->signatures[i].current; - next_bkt[i]->signatures[j].current = bkt->signatures[i].alt; - next_bkt[i]->key_buf[j] = bkt->key_buf[i]; - return i; - } - - /* Pick entry that has not been pushed yet */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) - if (bkt->flag[i] == 0) - break; - - /* All entries have been pushed, so entry cannot be added */ - if (i == HASH_BUCKET_ENTRIES) - return -ENOSPC; - - /* Set flag to indicate that this entry is going to be pushed */ - bkt->flag[i] = 1; - /* Need room in alternative bucket to insert the pushed entry */ - ret = make_space_bucket(impl, next_bkt[i]); - /* - * After recursive function. - * Clear flags and insert the pushed entry - * in its alternative location if successful, - * or return error - */ - bkt->flag[i] = 0; - if (ret >= 0) { - next_bkt[i]->signatures[ret].alt = bkt->signatures[i].current; - next_bkt[i]->signatures[ret].current = bkt->signatures[i].alt; - next_bkt[i]->key_buf[ret] = bkt->key_buf[i]; - return i; - } - - return ret; -} - -static inline int32_t -cuckoo_table_add_key_with_hash( - const odph_cuckoo_table_impl *h, const void *key, - uint32_t sig, void *data) -{ - uint32_t alt_hash; - uint32_t prim_bucket_idx, sec_bucket_idx; - unsigned i; - struct cuckoo_table_bucket *prim_bkt, *sec_bkt; - struct cuckoo_table_key_value *new_kv, *kv; - - odp_buffer_t new_buf; - int ret; - - prim_bucket_idx = sig & h->bucket_bitmask; - prim_bkt = &h->buckets[prim_bucket_idx]; - __builtin_prefetch((const void *)(uintptr_t)prim_bkt, 0, 3); - - alt_hash = hash_secondary(sig); - sec_bucket_idx = alt_hash & h->bucket_bitmask; - sec_bkt = &h->buckets[sec_bucket_idx]; - __builtin_prefetch((const void *)(uintptr_t)sec_bkt, 0, 3); - - /* Get a new slot for storing the new key */ - new_buf = odp_buffer_from_event(odp_queue_deq(h->free_slots)); - if (new_buf == ODP_BUFFER_INVALID) - return -ENOSPC; - - /* Check if key is already inserted in primary location */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - if ( - prim_bkt->signatures[i].current == sig && - prim_bkt->signatures[i].alt == alt_hash) { - kv = (struct cuckoo_table_key_value *)odp_buffer_addr( - prim_bkt->key_buf[i]); - if (memcmp(key, kv->key, h->key_len) == 0) { - odp_queue_enq( - h->free_slots, - odp_buffer_to_event(new_buf)); - /* Update data */ - if (kv->value != NULL) - memcpy(kv->value, data, h->value_len); - - /* Return bucket index */ - return prim_bucket_idx; - } - } - } - - /* Check if key is already inserted in secondary location */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - if ( - sec_bkt->signatures[i].alt == sig && - sec_bkt->signatures[i].current == alt_hash) { - kv = (struct cuckoo_table_key_value *)odp_buffer_addr( - sec_bkt->key_buf[i]); - if (memcmp(key, kv->key, h->key_len) == 0) { - odp_queue_enq( - h->free_slots, - odp_buffer_to_event(new_buf)); - /* Update data */ - if (kv->value != NULL) - memcpy(kv->value, data, h->value_len); - - /* Return bucket index */ - return sec_bucket_idx; - } - } - } - - new_kv = (struct cuckoo_table_key_value *)odp_buffer_addr(new_buf); - __builtin_prefetch((const void *)(uintptr_t)new_kv, 0, 3); - - /* Copy key and value. - * key-value mem block : struct cuckoo_table_key_value - * + key (key_len) + value (value_len) - */ - new_kv->key = (uint8_t *)new_kv - + sizeof(struct cuckoo_table_key_value); - memcpy(new_kv->key, key, h->key_len); - - if (h->value_len > 0) { - new_kv->value = new_kv->key + h->key_len; - memcpy(new_kv->value, data, h->value_len); - } else { - new_kv->value = NULL; - } - - /* Insert new entry is there is room in the primary bucket */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - /* Check if slot is available */ - if (odp_likely(prim_bkt->signatures[i].sig == NULL_SIGNATURE)) { - prim_bkt->signatures[i].current = sig; - prim_bkt->signatures[i].alt = alt_hash; - prim_bkt->key_buf[i] = new_buf; - return prim_bucket_idx; - } - } - - /* Primary bucket is full, so we need to make space for new entry */ - ret = make_space_bucket(h, prim_bkt); - - /* - * After recursive function. - * Insert the new entry in the position of the pushed entry - * if successful or return error and - * store the new slot back in the pool - */ - if (ret >= 0) { - prim_bkt->signatures[ret].current = sig; - prim_bkt->signatures[ret].alt = alt_hash; - prim_bkt->key_buf[ret] = new_buf; - return prim_bucket_idx; - } - - /* Error in addition, store new slot back in the free_slots */ - odp_queue_enq(h->free_slots, odp_buffer_to_event(new_buf)); - return ret; -} - -int -odph_cuckoo_table_put_value(odph_table_t tbl, void *key, void *value) -{ - odph_cuckoo_table_impl *impl; - int ret; - - if ((tbl == NULL) || (key == NULL)) - return -EINVAL; - - impl = (odph_cuckoo_table_impl *)(void *)tbl; - ret = cuckoo_table_add_key_with_hash( - impl, key, hash(impl, key), value); - - if (ret < 0) - return -1; - - return 0; -} - -static inline int32_t -cuckoo_table_lookup_with_hash( - const odph_cuckoo_table_impl *h, const void *key, - uint32_t sig, void **data_ptr) -{ - uint32_t bucket_idx; - uint32_t alt_hash; - unsigned i; - struct cuckoo_table_bucket *bkt; - struct cuckoo_table_key_value *kv; - - bucket_idx = sig & h->bucket_bitmask; - bkt = &h->buckets[bucket_idx]; - - /* Check if key is in primary location */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - if ( - bkt->signatures[i].current == sig && - bkt->signatures[i].sig != NULL_SIGNATURE) { - kv = (struct cuckoo_table_key_value *)odp_buffer_addr( - bkt->key_buf[i]); - if (memcmp(key, kv->key, h->key_len) == 0) { - if (data_ptr != NULL) - *data_ptr = kv->value; - /* - * Return index where key is stored, - * subtracting the first dummy index - */ - return bucket_idx; - } - } - } - - /* Calculate secondary hash */ - alt_hash = hash_secondary(sig); - bucket_idx = alt_hash & h->bucket_bitmask; - bkt = &h->buckets[bucket_idx]; - - /* Check if key is in secondary location */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - if ( - bkt->signatures[i].current == alt_hash && - bkt->signatures[i].alt == sig) { - kv = (struct cuckoo_table_key_value *)odp_buffer_addr( - bkt->key_buf[i]); - if (memcmp(key, kv->key, h->key_len) == 0) { - if (data_ptr != NULL) - *data_ptr = kv->value; - /* - * Return index where key is stored, - * subtracting the first dummy index - */ - return bucket_idx; - } - } - } - - return -ENOENT; -} - -int odph_cuckoo_table_get_value(odph_table_t tbl, void *key, - void *buffer, uint32_t buffer_size ODP_UNUSED) -{ - odph_cuckoo_table_impl *impl = (odph_cuckoo_table_impl *)(void *)tbl; - void *tmp = NULL; - int ret; - - if ((tbl == NULL) || (key == NULL)) - return -EINVAL; - - ret = cuckoo_table_lookup_with_hash(impl, key, hash(impl, key), &tmp); - - if (ret < 0) - return -1; - - if (impl->value_len > 0) - memcpy(buffer, tmp, impl->value_len); - - return 0; -} - -static inline int32_t -cuckoo_table_del_key_with_hash( - const odph_cuckoo_table_impl *h, - const void *key, uint32_t sig) -{ - uint32_t bucket_idx; - uint32_t alt_hash; - unsigned i; - struct cuckoo_table_bucket *bkt; - struct cuckoo_table_key_value *kv; - - bucket_idx = sig & h->bucket_bitmask; - bkt = &h->buckets[bucket_idx]; - - /* Check if key is in primary location */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - if ( - bkt->signatures[i].current == sig && - bkt->signatures[i].sig != NULL_SIGNATURE) { - kv = (struct cuckoo_table_key_value *)odp_buffer_addr( - bkt->key_buf[i]); - if (memcmp(key, kv->key, h->key_len) == 0) { - bkt->signatures[i].sig = NULL_SIGNATURE; - odp_queue_enq( - h->free_slots, - odp_buffer_to_event( - bkt->key_buf[i])); - return bucket_idx; - } - } - } - - /* Calculate secondary hash */ - alt_hash = hash_secondary(sig); - bucket_idx = alt_hash & h->bucket_bitmask; - bkt = &h->buckets[bucket_idx]; - - /* Check if key is in secondary location */ - for (i = 0; i < HASH_BUCKET_ENTRIES; i++) { - if ( - bkt->signatures[i].current == alt_hash && - bkt->signatures[i].sig != NULL_SIGNATURE) { - kv = (struct cuckoo_table_key_value *)odp_buffer_addr( - bkt->key_buf[i]); - if (memcmp(key, kv->key, h->key_len) == 0) { - bkt->signatures[i].sig = NULL_SIGNATURE; - odp_queue_enq( - h->free_slots, - odp_buffer_to_event( - bkt->key_buf[i])); - return bucket_idx; - } - } - } - - return -ENOENT; -} - -int -odph_cuckoo_table_remove_value(odph_table_t tbl, void *key) -{ - odph_cuckoo_table_impl *impl = (void *)tbl; - int ret; - - if ((tbl == NULL) || (key == NULL)) - return -EINVAL; - - ret = cuckoo_table_del_key_with_hash(impl, key, hash(impl, key)); - if (ret < 0) - return -1; - - return 0; -} - -odph_table_ops_t odph_cuckoo_table_ops = { - odph_cuckoo_table_create, - odph_cuckoo_table_lookup, - odph_cuckoo_table_destroy, - odph_cuckoo_table_put_value, - odph_cuckoo_table_get_value, - odph_cuckoo_table_remove_value -}; diff --git a/helper/hashtable.c b/helper/hashtable.c deleted file mode 100644 index 28c23a58c..000000000 --- a/helper/hashtable.c +++ /dev/null @@ -1,356 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2015-2018 Linaro Limited - */ - -#include <stdio.h> -#include <string.h> -#include <malloc.h> - -#include <odp/helper/odph_hashtable.h> -#include <odp/helper/odph_debug.h> -#include "odph_list_internal.h" -#include <odp_api.h> - -#define ODPH_SUCCESS 0 -#define ODPH_FAIL -1 - -/** @magic word, write to the first byte of the memory block - * to indicate this block is used by a hash table structure - */ -#define ODPH_HASH_TABLE_MAGIC_WORD 0xABABBABA - -/** @support 64k buckets. Bucket is a list that composed of - * elements with the same HASH-value but different keys - */ -#define ODPH_MAX_BUCKET_NUM 0x10000 - -/** @inner element structure of hash table - * To resolve the hash conflict: - * we put the elements with different keys but a same HASH-value - * into a list - */ -typedef struct odph_hash_node { - /** list structure,for list opt */ - odph_list_object list_node; - /** Flexible Array,memory will be alloced when table has been created - * Its length is key_size + value_size, - * suppose key_size = m; value_size = n; - * its structure is like: - * k_byte1 k_byte2...k_byten v_byte1...v_bytem - */ - char content[]; -} odph_hash_node; - -typedef struct { - uint32_t magicword; /**< for check */ - uint32_t key_size; /**< input param when create,in Bytes */ - uint32_t value_size; /**< input param when create,in Bytes */ - uint32_t init_cap; /**< input param when create,in Bytes */ - /** multi-process support,every list has one rw lock */ - odp_rwlock_t *lock_pool; - /** table bucket pool,every hash value has one list head */ - odph_list_head *list_head_pool; - /** number of the list head in list_head_pool */ - uint32_t head_num; - /** table element pool */ - odph_hash_node *hash_node_pool; - /** number of element in the hash_node_pool */ - uint32_t hash_node_num; - char rsv[7]; /**< Reserved,for alignment */ - char name[ODPH_TABLE_NAME_LEN]; /**< table name */ -} odph_hash_table_imp; - -odph_table_t odph_hash_table_create(const char *name, uint32_t capacity, - uint32_t key_size, - uint32_t value_size) -{ - int i; - uint32_t node_num; - odph_hash_table_imp *tbl; - odp_shm_t shmem; - uint32_t node_mem; - - if (strlen(name) >= ODPH_TABLE_NAME_LEN || capacity < 1 || - capacity >= 0x1000 || key_size == 0 || value_size == 0) { - ODPH_DBG("create para input error!\n"); - return NULL; - } - if (odp_shm_lookup(name) != ODP_SHM_INVALID) { - ODPH_DBG("name already exist\n"); - return NULL; - } - shmem = odp_shm_reserve(name, capacity << 20, 64, 0); - if (shmem == ODP_SHM_INVALID) { - ODPH_DBG("shm reserve fail\n"); - return NULL; - } - tbl = (odph_hash_table_imp *)odp_shm_addr(shmem); - - /* clean this block of memory */ - memset(tbl, 0, capacity << 20); - - tbl->init_cap = capacity << 20; - strncpy(tbl->name, name, ODPH_TABLE_NAME_LEN - 1); - tbl->key_size = key_size; - tbl->value_size = value_size; - - /* header of this mem block is the table control struct, - * then the lock pool, then the list header pool - * the last part is the element node pool - */ - - tbl->lock_pool = (odp_rwlock_t *)(void *)((char *)tbl - + sizeof(odph_hash_table_imp)); - tbl->list_head_pool = (odph_list_head *)(void *)((char *)tbl->lock_pool - + ODPH_MAX_BUCKET_NUM * sizeof(odp_rwlock_t)); - - node_mem = tbl->init_cap - sizeof(odph_hash_table_imp) - - ODPH_MAX_BUCKET_NUM * sizeof(odph_list_head) - - ODPH_MAX_BUCKET_NUM * sizeof(odp_rwlock_t); - - node_num = node_mem / (sizeof(odph_hash_node) + key_size + value_size); - tbl->hash_node_num = node_num; - tbl->hash_node_pool = - (odph_hash_node *)(void *)((char *)tbl->list_head_pool - + ODPH_MAX_BUCKET_NUM * sizeof(odph_list_head)); - - /* init every list head and rw lock */ - for (i = 0; i < ODPH_MAX_BUCKET_NUM; i++) { - ODPH_INIT_LIST_HEAD(&tbl->list_head_pool[i]); - odp_rwlock_init((odp_rwlock_t *)&tbl->lock_pool[i]); - } - - tbl->magicword = ODPH_HASH_TABLE_MAGIC_WORD; - return (odph_table_t)tbl; -} - -int odph_hash_table_destroy(odph_table_t table) -{ - int ret; - - if (table != NULL) { - odph_hash_table_imp *hash_tbl; - - hash_tbl = (odph_hash_table_imp *)(void *)table; - if (hash_tbl->magicword != ODPH_HASH_TABLE_MAGIC_WORD) - return ODPH_FAIL; - - ret = odp_shm_free(odp_shm_lookup(hash_tbl->name)); - if (ret != 0) { - ODPH_DBG("free fail\n"); - return ret; - } - /* clean head */ - return ODPH_SUCCESS; - } - return ODPH_FAIL; -} - -odph_table_t odph_hash_table_lookup(const char *name) -{ - odph_hash_table_imp *hash_tbl = NULL; - odp_shm_t shm; - - if (name == NULL || strlen(name) >= ODPH_TABLE_NAME_LEN) - return NULL; - - shm = odp_shm_lookup(name); - if (shm != ODP_SHM_INVALID) - hash_tbl = (odph_hash_table_imp *)odp_shm_addr(shm); - if (hash_tbl != NULL && strcmp(hash_tbl->name, name) == 0) - return (odph_table_t)hash_tbl; - return NULL; -} - -/** - * Calculate has value by the input key and key_size - * This hash algorithm is the most simple one, so we choose it as an DEMO - * User can use any other algorithm, like CRC... - */ -static uint16_t odp_key_hash(void *key, uint32_t key_size) -{ - register uint32_t hash = 0; - uint32_t idx = (key_size == 0 ? 1 : key_size); - uint32_t ch; - - while (idx != 0) { - ch = (uint32_t)(*(char *)key); - hash = hash * 131 + ch; - idx--; - } - return (uint16_t)(hash & 0x0000FFFF); -} - -/** - * Get an available node from pool - */ -static odph_hash_node *hashnode_take(odph_table_t table) -{ - odph_hash_table_imp *tbl; - uint32_t idx; - odph_hash_node *node; - - tbl = (odph_hash_table_imp *)(void *)table; - for (idx = 0; idx < tbl->hash_node_num; idx++) { - /** notice: memory of one hash_node is - * not only sizeof(odph_hash_node) - * should add the size of Flexible Array - */ - node = (odph_hash_node *)(void *)((char *)tbl->hash_node_pool - + idx * (sizeof(odph_hash_node) - + tbl->key_size - + tbl->value_size)); - if (node->list_node.next == NULL && - node->list_node.prev == NULL) { - ODPH_INIT_LIST_HEAD(&node->list_node); - return node; - } - } - return NULL; -} - -/** - * Release an node to the pool - */ -static void hashnode_give(odph_table_t table, odph_hash_node *node) -{ - odph_hash_table_imp *tbl; - - if (node == NULL) - return; - - tbl = (odph_hash_table_imp *)(void *)table; - - odph_list_del(&node->list_node); - memset(node, 0, - (sizeof(odph_hash_node) + tbl->key_size + tbl->value_size)); -} - -/* should make sure the input table exists and is available */ -int odph_hash_put_value(odph_table_t table, void *key, void *value) -{ - odph_hash_table_imp *tbl; - uint16_t hash = 0; - odph_hash_node *node = NULL; - char *tmp = NULL; - - if (table == NULL || key == NULL || value == NULL) - return ODPH_FAIL; - - tbl = (odph_hash_table_imp *)(void *)table; - /* hash value is just the index of the list head in pool */ - hash = odp_key_hash(key, tbl->key_size); - - odp_rwlock_write_lock(&tbl->lock_pool[hash]); - /* First, check if the key already exist */ - ODPH_LIST_FOR_EACH(node, &tbl->list_head_pool[hash], odph_hash_node, - list_node) - { - if (memcmp(node->content, key, tbl->key_size) == 0) { - /* copy value content to hash node*/ - tmp = (void *)((char *)node->content + tbl->key_size); - memcpy(tmp, value, tbl->value_size); - odp_rwlock_write_unlock(&tbl->lock_pool[hash]); - return ODPH_SUCCESS; - } - } - - /*if the key is a new one, get a new hash node form the pool */ - node = hashnode_take(table); - if (node == NULL) { - odp_rwlock_write_unlock(&tbl->lock_pool[hash]); - return ODPH_FAIL; - } - - /* copy both key and value content to the hash node */ - memcpy(node->content, key, tbl->key_size); - tmp = (void *)((char *)node->content + tbl->key_size); - memcpy(tmp, value, tbl->value_size); - - /* add the node to list */ - odph_list_add(&node->list_node, &tbl->list_head_pool[hash]); - - odp_rwlock_write_unlock(&tbl->lock_pool[hash]); - return ODPH_SUCCESS; -} - -/* should make sure the input table exists and is available */ -int odph_hash_get_value(odph_table_t table, void *key, void *buffer, - uint32_t buffer_size) -{ - odph_hash_table_imp *tbl; - uint16_t hash = 0; - odph_hash_node *node; - char *tmp = NULL; - - tbl = (odph_hash_table_imp *)(void *)table; - - if (table == NULL || key == NULL || buffer == NULL || - buffer_size < tbl->value_size) - return ODPH_FAIL; - - /* hash value is just the index of the list head in pool */ - hash = odp_key_hash(key, tbl->key_size); - - odp_rwlock_read_lock(&tbl->lock_pool[hash]); - - ODPH_LIST_FOR_EACH(node, &tbl->list_head_pool[hash], - odph_hash_node, list_node) - { - /* in case of hash conflict, compare the whole key */ - if (memcmp(node->content, key, tbl->key_size) == 0) { - /* find the target */ - tmp = (void *)((char *)node->content + tbl->key_size); - memcpy(buffer, tmp, tbl->value_size); - - odp_rwlock_read_unlock(&tbl->lock_pool[hash]); - - return ODPH_SUCCESS; - } - } - - odp_rwlock_read_unlock(&tbl->lock_pool[hash]); - - return ODPH_FAIL; -} - -/* should make sure the input table exists and is available */ -int odph_hash_remove_value(odph_table_t table, void *key) -{ - odph_hash_table_imp *tbl; - uint16_t hash = 0; - odph_hash_node *node; - - if (table == NULL || key == NULL) - return ODPH_FAIL; - - tbl = (odph_hash_table_imp *)(void *)table; - - /* hash value is just the index of the list head in pool */ - hash = odp_key_hash(key, tbl->key_size); - - odp_rwlock_write_lock(&tbl->lock_pool[hash]); - - ODPH_LIST_FOR_EACH(node, &tbl->list_head_pool[hash], odph_hash_node, - list_node) - { - if (memcmp(node->content, key, tbl->key_size) == 0) { - hashnode_give(table, node); - odp_rwlock_write_unlock(&tbl->lock_pool[hash]); - return ODPH_SUCCESS; - } - } - - odp_rwlock_write_unlock(&tbl->lock_pool[hash]); - - return ODPH_SUCCESS; -} - -odph_table_ops_t odph_hash_table_ops = { - odph_hash_table_create, - odph_hash_table_lookup, - odph_hash_table_destroy, - odph_hash_put_value, - odph_hash_get_value, - odph_hash_remove_value}; - diff --git a/helper/include/odp/helper/odph_debug.h b/helper/include/odp/helper/debug.h index 41b425ab2..41b425ab2 100644 --- a/helper/include/odp/helper/odph_debug.h +++ b/helper/include/odp/helper/debug.h diff --git a/helper/include/odp/helper/odph_api.h b/helper/include/odp/helper/odph_api.h index 94d43a61b..2541efa89 100644 --- a/helper/include/odp/helper/odph_api.h +++ b/helper/include/odp/helper/odph_api.h @@ -18,23 +18,20 @@ extern "C" { #include <odp/helper/autoheader_external.h> -#include <odp/helper/odph_debug.h> #include <odp/helper/chksum.h> -#include <odp/helper/odph_cuckootable.h> +#include <odp/helper/debug.h> #include <odp/helper/eth.h> #include <odp/helper/gtp.h> -#include <odp/helper/odph_hashtable.h> #include <odp/helper/icmp.h> #include <odp/helper/igmp.h> #include <odp/helper/ip.h> #include <odp/helper/ipsec.h> #include <odp/helper/macros.h> -#include <odp/helper/odph_lineartable.h> -#include <odp/helper/odph_iplookuptable.h> +#include <odp/helper/stress.h> #include <odp/helper/sctp.h> +#include <odp/helper/string.h> #include <odp/helper/strong_types.h> #include <odp/helper/tcp.h> -#include <odp/helper/table.h> #include <odp/helper/threads.h> #include <odp/helper/udp.h> #include <odp/helper/version.h> diff --git a/helper/include/odp/helper/odph_cuckootable.h b/helper/include/odp/helper/odph_cuckootable.h deleted file mode 100644 index 1c87a3d42..000000000 --- a/helper/include/odp/helper/odph_cuckootable.h +++ /dev/null @@ -1,146 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2016-2018 Linaro Limited - */ - -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2016 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. - */ - -#ifndef ODPH_CUCKOO_TABLE_H_ -#define ODPH_CUCKOO_TABLE_H_ - -#include <odp/helper/table.h> - -/** - * @file - * - * ODP Cuckoo Hash Table - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup odph_cuckootable ODPH CUCKOO TABLE - * Cuckoo table - * - * @{ - */ - -/** - * Create a cuckoo table - * - * @param name Name of the cuckoo table to be created - * @param capacity Number of elements table may store - * @param key_size Size of the key for each element - * @param value_size Size of the value stored for each element - * - * @return Handle of created cuckoo table - * @retval NULL Create failed - */ -odph_table_t odph_cuckoo_table_create( - const char *name, - uint32_t capacity, - uint32_t key_size, - uint32_t value_size); - -/** - * Lookup a cuckoo table by name - * - * @param name Name of the table to be located - * - * @return Handle of the located cuckoo table - * @retval NULL No table matching supplied name found - */ -odph_table_t odph_cuckoo_table_lookup(const char *name); - -/** - * Destroy a cuckoo table - * - * @param table Handle of the cuckoo table to be destroyed - * - * @retval 0 Success - * @retval < 0 Failure - */ -int odph_cuckoo_table_destroy(odph_table_t table); - -/** - * Insert a key/value pair into a cuckoo table - * - * @param table Table into which value is to be stored - * @param key Address of an odph_table_t to be used as key - * @param value Value to be associated with specified key - * - * @retval >= 0 Success - * @retval < 0 Failure - */ -int odph_cuckoo_table_put_value(odph_table_t table, void *key, void *value); - -/** - * Retrieve a value from a cuckoo table - * - * @param table Table from which value is to be retrieved - * @param key Address of an odph_table_t to be used as key - * @param[out] buffer Address of buffer to receive resulting value - * @param buffer_size Size of supplied buffer - * - * @retval 0 Success - * @retval 1 Success - * @retval < 0 Failure - */ -int odph_cuckoo_table_get_value(odph_table_t table, - void *key, void *buffer, - uint32_t buffer_size); - -/** - * Remove a value from a cuckoo table - * - * @param table Table from which value is to be removed - * @param key Address of odph_table_t to be used as key - * - * @retval >= 0 Success - * @retval < 0 Failure - */ -int odph_cuckoo_table_remove_value(odph_table_t table, void *key); - -extern odph_table_ops_t odph_cuckoo_table_ops; /**< @internal */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* ODPH_CUCKOO_TABLE_H_ */ diff --git a/helper/include/odp/helper/odph_hashtable.h b/helper/include/odp/helper/odph_hashtable.h deleted file mode 100644 index b2dd21920..000000000 --- a/helper/include/odp/helper/odph_hashtable.h +++ /dev/null @@ -1,111 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2015-2018 Linaro Limited - */ - -/** - * @file - * - * ODP Hash Table - */ - -#ifndef ODPH_HASH_TABLE_H_ -#define ODPH_HASH_TABLE_H_ - -#include <odp/helper/table.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup odph_hash_table ODPH HASH TABLE - * Hash table - * - * @{ - */ - -/** - * Create a hash table - * - * @param name Name of the hash table to be created. - * @param capacity Number of elements table may store - * @param key_size Size of the key for each element - * @param value_size Size of the value stored for each element - * - * @return Handle of created hash table - * @retval NULL Create failed - */ -odph_table_t odph_hash_table_create(const char *name, - uint32_t capacity, - uint32_t key_size, - uint32_t value_size); - -/** - * Lookup a hash table by name - * - * @param name Name of the table to be located - * - * @return Handle of the located hash table - * @return NULL No table matching supplied name found - */ -odph_table_t odph_hash_table_lookup(const char *name); - -/** - * Destroy a hash table - * - * @param table Handle of the hash table to be destroyed - * - * @retval 0 Success - * @retval < 0 Failure - */ -int odph_hash_table_destroy(odph_table_t table); - -/** - * Insert a key/value pair into a hash table - * - * @param table Table into which value is to be stored - * @param key Address of an odph_table_t to be used as key - * @param value Value to be associated with specified key - * - * @retval >= 0 Success - * @retval < 0 Failure - */ -int odph_hash_put_value(odph_table_t table, void *key, void *value); - -/** - * Retrieve a value from a hash table - * - * @param table Table from which value is to be retrieved - * @param key Address of an odph_table_t to be used as key - * @param[out] buffer Address of buffer to receive resulting value - * @param buffer_size Size of supplied buffer - * - * @retval 0 Success - * @retval 1 Success - * @retval < 0 Failure - */ -int odph_hash_get_value(odph_table_t table, void *key, void *buffer, - uint32_t buffer_size); - -/** - * Remove a value from a hash table - * - * @param table Table from which value is to be removed - * @param key Address of odph_table_t to be used as key - * - * @retval >= 0 Success - * @retval < 0 Failure - */ -int odph_hash_remove_value(odph_table_t table, void *key); - -extern odph_table_ops_t odph_hash_table_ops; /**< @internal */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/helper/include/odp/helper/odph_iplookuptable.h b/helper/include/odp/helper/odph_iplookuptable.h deleted file mode 100644 index 41235ecc6..000000000 --- a/helper/include/odp/helper/odph_iplookuptable.h +++ /dev/null @@ -1,125 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2016-2018 Linaro Limited - */ - -/** - * @file - * - * ODP IP Lookup Table - */ - -#ifndef ODPH_IPLOOKUP_TABLE_H_ -#define ODPH_IPLOOKUP_TABLE_H_ - -#include <odp/helper/table.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup odph_iplookuptable ODPH IP LOOKUP TABLE - * IP lookup table - * - * @details - * This is an implementation of the IP lookup table. The key of this table is - * IPv4 address (32 bits), and the value can be defined by user. This table uses - * the 16,8,8 ip lookup (longest prefix matching) algorithm. - * - * @{ - */ - -/** - * IP Lookup Prefix - */ -typedef struct { - uint32_t ip; /**< IPv4 address */ - uint8_t cidr; /**< CIDR value for prefix matching */ -} odph_iplookup_prefix_t; - -/** - * Create an IP lookup table - * - * @param name Name of the table to be created - * @param ODP_IGNORED_1 Unused - * @param ODP_IGNORED_2 Unused - * @param value_size Byte size of each entry in the table - * - * @return Handle of the created ip lookup table - * @retval NULL If table create failed - */ -odph_table_t odph_iplookup_table_create(const char *name, - uint32_t ODP_IGNORED_1, - uint32_t ODP_IGNORED_2, - uint32_t value_size); - -/** - * Lookup an IP lookup table by name - * - * @param name Name of the table to be located - * - * @return Handle of the located ip lookup table - * @retval NULL No table matching supplied name found - */ -odph_table_t odph_iplookup_table_lookup(const char *name); - -/** - * Destroy an IP lookup table - * - * @param table Handle of the ip lookup table to be destroyed - * - * @retval 0 Success - * @retval < 0 Failure - */ -int odph_iplookup_table_destroy(odph_table_t table); - -/** - * Insert a key/value pair into an ip lookup table - * - * @param table Table into which value is to be stored - * @param key Address of an odph_iplookup_prefix_t to be used as key - * @param value Value to be associated with specified key - * - * @retval >= 0 Success - * @retval < 0 Failure - */ -int odph_iplookup_table_put_value(odph_table_t table, void *key, void *value); - -/** - * Retrieve a value from an iplookup table - * - * @param table Table from which value is to be retrieved - * @param key Address of an odph_iplookup_prefix_t to be used as key - * @param[out] buffer Address of buffer to receive resulting value - * @param buffer_size Size of supplied buffer - * - * @retval 0 Success - * @retval 1 Success - * @retval < 0 Failure - */ -int odph_iplookup_table_get_value(odph_table_t table, void *key, - void *buffer, uint32_t buffer_size); - -/** - * Remove a value from an iplookup table - * - * @param table Table from which value is to be removed - * @param key Address of odph_iplookup_prefix_t to be used as key - * - * @retval >= 0 Success - * @retval < 0 Failure - * - */ -int odph_iplookup_table_remove_value(odph_table_t table, void *key); - -extern odph_table_ops_t odph_iplookup_table_ops; /**< @internal */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* ODPH_IPLOOKUP_TABLE_H_ */ diff --git a/helper/include/odp/helper/odph_lineartable.h b/helper/include/odp/helper/odph_lineartable.h deleted file mode 100644 index dc61113a5..000000000 --- a/helper/include/odp/helper/odph_lineartable.h +++ /dev/null @@ -1,101 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2015-2018 Linaro Limited - */ - -/** - * @file - * - * ODP Linear Table - */ - -#ifndef ODPH_LINEAR_TABLE_H_ -#define ODPH_LINEAR_TABLE_H_ - -#include <stdint.h> -#include <odp/helper/table.h> - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup odph_lineartable ODPH LINEAR TABLE - * Linear table - * - * @{ - */ - -/** - * Create a linear table - * - * @param name Name of the linear table to be created - * @param capacity Number of elements table may store - * @param ODP_IGNORED Ignored parameter - * @param value_size Size of the value stored for each element - * - * @return Handle of created linear table - * @return NULL Create failed - */ -odph_table_t odph_linear_table_create(const char *name, - uint32_t capacity, - uint32_t ODP_IGNORED, - uint32_t value_size); - -/** - * Lookup a linear table - * - * @param name Name of the table to be located - * - * @return Handle of the located linear table - * @retval NULL No table matching supplied name found - */ -odph_table_t odph_linear_table_lookup(const char *name); - -/** - * Destroy a linear table - * - * @param table Handle of linear table to be destroyed - * - * @retval 0 Success - * @retval < 0 Failure - */ -int odph_linear_table_destroy(odph_table_t table); - -/** - * Insert a value into a linear table - * - * @param table Table into which value is to be stored - * @param key Index value used as key - * @param value Value to be assoceiated with specified key index - * - * @retval >= 0 Success - * @retval < 0 Failure - */ -int odph_linear_put_value(odph_table_t table, void *key, void *value); - -/** - * Retrieve a value from a linear table - * - * @param table Table from which value is to be retrieved - * @param key Index value used as key - * @param[out] buffer Address of buffer to receive resulting value - * @param buffer_size Size of supplied buffer - * - * @retval 0 Success - * @retval 1 Success - * @retval < 0 Failure - */ -int odph_linear_get_value(odph_table_t table, void *key, void *buffer, - uint32_t buffer_size); - -extern odph_table_ops_t odph_linear_table_ops; /**< @internal */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/helper/include/odp/helper/stress.h b/helper/include/odp/helper/stress.h new file mode 100644 index 000000000..cfdc41033 --- /dev/null +++ b/helper/include/odp/helper/stress.h @@ -0,0 +1,238 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2024 Nokia + */ + +/** + * @file + * + * ODP helper stress + */ + +#ifndef ODPH_STRESS_H_ +#define ODPH_STRESS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup odph_stress ODPH STRESS + * Dummy CPU stress functions + * + * These functions may be used in test applications to create dummy CPU load. Functions are not + * highly optimized, as they try to utilize various parts of CPU instruction set (load/store, + * branch, integer/float arithmetics, vector, etc. instructions). + * + * @{ + */ + +/** + * Returns 'value' raised to the power of 2 + * + * @param value Base value + * + * @return The value raised to the power of 2 + */ +static inline uint32_t odph_stress_pow2_u32(uint32_t value) +{ + uint64_t v = (uint64_t)value; + uint64_t res = v * v; + + if (odp_unlikely(res > UINT32_MAX)) + return UINT32_MAX; + + return (uint32_t)res; +} + +/** + * Returns base 2 logarithm of 'value' + * + * @param value The value for which the logarithm is being calculated + * + * @return Base 2 logarithm of 'value' + */ +static inline uint32_t odph_stress_log2_u32(uint32_t value) +{ + uint32_t ret = 0; + + while ((value >>= 1) != 0) + ret++; + + return ret; +} + +/** + * Calculates square root of a 32-bit unsigned integer value + * + * @param value The value for which the square root is being calculated + * + * @return Square root of the value + */ +static inline uint32_t odph_stress_sqrt_u32(uint32_t value) +{ + uint64_t x; + uint64_t pow = 1; + + if (odp_unlikely(value == 0 || value == 1)) + return value; + + if (value & 0xffff0000) { + if (value & 0xff000000) { + if (value & 0xf0000000) { + x = 16384; + if (value & 0xe0000000) + x = 23170; + if (value & 0xc0000000) + x = 32768; + if (value & 0x80000000) + x = 46340; + } else { + /* value & 0x0f000000 */ + x = 4096; + if (value & 0x0e000000) + x = 5792; + if (value & 0x0c000000) + x = 8192; + if (value & 0x08000000) + x = 11585; + } + } else { + if (value & 0x00f00000) { + x = 1024; + if (value & 0x00e00000) + x = 1448; + if (value & 0x00c00000) + x = 2048; + if (value & 0x00800000) + x = 2896; + } else { + /* value & 0x000f0000 */ + x = 256; + if (value & 0x000e0000) + x = 362; + if (value & 0x000c0000) + x = 512; + if (value & 0x00080000) + x = 724; + } + } + } else { + /* value & 0xffff */ + x = 1; + + if (value >= 16384) { + x = 128; + if (value >= 25600) + x = 160; + if (value >= 36864) + x = 192; + if (value >= 50176) + x = 224; + } else { + if (value >= 1024) + x = 32; + if (value >= 4096) + x = 64; + if (value >= 9216) + x = 96; + } + } + + while (pow <= value) { + x++; + pow = x * x; + } + + return (uint32_t)(x - 1); +} + +/** + * Calculates square root of a floating point value + * + * @param value The value for which the square root is being calculated + * + * @return Square root of the value + */ +static inline float odph_stress_sqrt_f32(float value) +{ + double x; + double pow = 1; + + if (odp_unlikely(value == 0 || value == 1)) + return value; + + if (value >= 65536) { + if (value >= 16777215) { + if (value >= 268435456) { + x = 16384; + if (value >= 536870912) + x = 23170; + if (value >= 1073741824) + x = 32768; + if (value >= 2147483648) + x = 46340; + } else { + x = 4096; + if (value >= 33554432) + x = 5792; + if (value >= 67108864) + x = 8192; + if (value >= 134217728) + x = 11585; + } + } else { + if (value >= 1048576) { + x = 1024; + if (value >= 2097152) + x = 1448; + if (value >= 4194304) + x = 2048; + if (value >= 8388608) + x = 2896; + } else { + x = 256; + if (value >= 131072) + x = 362; + if (value >= 262144) + x = 512; + if (value >= 524288) + x = 724; + } + } + } else { + x = 1; + + if (value >= 16384) { + x = 128; + if (value >= 25600) + x = 160; + if (value >= 36864) + x = 192; + if (value >= 50176) + x = 224; + } else { + if (value >= 1024) + x = 32; + if (value >= 4096) + x = 64; + if (value >= 9216) + x = 96; + } + } + + while (pow <= value) { + x = x + 1; + pow = x * x; + } + + return (float)(x - 1); +} + +/** + * @} + */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/helper/include/odp/helper/string.h b/helper/include/odp/helper/string.h new file mode 100644 index 000000000..da2d61a6b --- /dev/null +++ b/helper/include/odp/helper/string.h @@ -0,0 +1,62 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright (c) 2024 Nokia + */ + +/** + * @file + * + * ODP string helper + */ + +#ifndef ODPH_STRING_H_ +#define ODPH_STRING_H_ + +#include <odp/api/hints.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @defgroup odph_string ODPH STRING + * String helper + * + * @{ + */ + +/** + * Copy a string + * + * Like strncpy(), but additionally ensures that the destination string is null + * terminated, unless sz is zero in which case returns dst without doing + * anything else. + * + * @param[out] dst Pointer to destination string. + * @param src Pointer to source string. + * @param sz Destination size. + * @return Pointer to destination string. + */ +#ifdef __cplusplus +ODP_UNUSED static char *odph_strcpy(char *dst, const char *src, size_t sz) +#else +ODP_UNUSED static char *odph_strcpy(char *restrict dst, const char *restrict src, size_t sz) +#endif +{ + if (!sz) + return dst; + + strncpy(dst, src, sz - 1); + dst[sz - 1] = 0; + return dst; +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/helper/include/odp/helper/table.h b/helper/include/odp/helper/table.h deleted file mode 100644 index 6a24e742b..000000000 --- a/helper/include/odp/helper/table.h +++ /dev/null @@ -1,244 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2015-2018 Linaro Limited - */ - -/** - * @file - * - * ODP table - */ - -#ifndef ODPH_TABLE_H_ -#define ODPH_TABLE_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * @defgroup odph_tables ODPH TABLES - * Table interface - * - * @details - * TCAM(Ternary Content Addressable Memory) is used widely in packet - * forwarding to speedup the table lookup. - * - * This file contains a simple interface for creating and using the table. - * Table here means a collection of related data held in a structured - * format. - * Some examples for table are ARP Table, Routing Table, etc.The table - * contains many entries, each consist of key and associated data - * (called key/value pair or rule/action pair in some paper.). - * Enclosed are some classical table examples, used publicly - * in data plane packet processing: - * - * <H3>Use Case: ARP table</H3> - * Once a route has been identified for an IP packet (so the output - * interface and the IP address of the next hop station are known), - * the MAC address of the next hop station is needed in order to - * send this packet onto the next leg of the journey - * towards its destination (as identified by its destination IP address). - * The MAC address of the next hop station becomes the destination - * MAC address of the outgoing Ethernet frame. - * <ol> - * <li>Key: The pair of (Output interface, Next Hop IP address) - * <li>Associated Data: MAC address of the next hop station - * <li>Algorithm: Hash - * </ol> - * - * <H3>Use Case: Routing Table</H3> - * When each router receives a packet, it searches its routing table - * to find the best match between the destination IP address of - * the packet and one of the network addresses in the routing table. - * <ol> - * <li>Key: destination IP address - * <li>Associated Data: The pair of (Output interface, Next Hop IP address) - * <li>Algorithm: LPM(Longest Prefix Match) - * </ol> - * - * <H3>Use Case: Flow Classification</H3> - * The flow classification is executed at least once for each - * input packet.This operation maps each incoming packet against - * one of the known traffic - * flows in the flow database that typically contains millions of flows. - * <ol> - * <li>Key:n-tuple of packet fields that uniquely identify a traffic flow. - * <li>Associated data: - * actions and action meta-data describing what processing to be - * applied for the packets of the current flow, such as whether - * encryption/decryption is required on this packet, what kind of cipher - * algorithm should be chosen. - * <li>Algorithm: Hash - * </ol> - * - * All these different types of lookup tables have the common operations: - * create a table, destroy a table, add (key,associated data), - * delete key and look up the associated data via the key. - * Usually these operations are software based, but also can be - * hardware accelerated such as using TCAM to implement ARP table - * or Routing Table. - * And specific alogithm can be used for specific lookup table. - * - * notes: key/value and key/associated data mean the same thing - * in this file unless otherwise mentioned. - * - * @{ - */ - -#include <stdint.h> - -/** - * @def ODPH_TABLE_NAME_LEN - * Max length of table name - */ -#define ODPH_TABLE_NAME_LEN 32 - -#include <odp/helper/strong_types.h> -/** @internal ODPH table handle @return */ -typedef ODPH_HANDLE_T(odph_table_t); - -/** -* create a table -* Generally, tables only support key-value pair both with fixed size -* -* @param name -* name of this table, max ODPH_TABLE_NAME_LEN - 1 -* May be specified as NULL for anonymous table -* @param capacity -* Max memory usage this table use, in MBytes -* @param key_size -* fixed size of the 'key' in bytes. -* @param value_size -* fixed size of the 'value' in bytes. -* @return -* Handle to table instance or NULL if failed -* @note -*/ -typedef odph_table_t (*odph_table_create)(const char *name, - uint32_t capacity, - uint32_t key_size, - uint32_t value_size); - -/** - * Find a table by name - * - * @param name Name of the table - * - * @return Handle of found table - * @retval NULL table could not be found - * - * @note This routine cannot be used to look up an anonymous - * table (one created with no name). - * This API supports Multiprocess - */ -typedef odph_table_t (*odph_table_lookup)(const char *name); - -/** - * Destroy a table previously created by odph_table_create() - * - * @param table Handle of the table to be destroyed - * - * @retval 0 Success - * @retval -1 Failure - * - * @note This routine destroys a previously created pool - * also should free any memory allocated at creation - * - */ -typedef int (*odph_table_destroy)(odph_table_t table); - -/** - * Add (key,associated data) pair into the specific table. - * When no associated data is currently associated with key, - * then the (key,assocatied data) association is created. - * When key is already associated with data0, then association (key, data0) - * will be removed and association (key, associated data) is created. - * - * @param table Handle of the table that the element be added - * - * @param key address of 'key' in key-value pair. - * User should make sure the address and 'key_size' - * bytes after are accessible - * @param value address of 'value' in key-value pair - * User should make sure the address and 'value_size' - * bytes after are accessible - * @retval 0 Success - * @retval -1 Failure - * @note Add a same key again with a new value, the older one will - * be covered. - */ -typedef int (*odph_table_put_value)(odph_table_t table, void *key, - void *value); - -/** - * Lookup the associated data via specific key. - * When no value is currently associated with key, then this operation - * restuns <0 to indicate the lookup miss. - * When key is associated with value, - * then this operation returns value. - * The (key,value) association won't change. - * - * @param table Handle of the table that the element be added - * - * @param key address of 'key' in key-value pair - * User should make sure the address and key_size bytes after - * are accessible - * - * @param buffer output The buffer address to the 'value' - * After successfully found, the content of 'value' will be - * copied to this address - * User should make sure the address and value_size bytes - * after are accessible - * @param buffer_size size of the buffer - * should be equal or bigger than value_size - * @retval 0 Success - * @retval -1 Failure - * - * @note - */ -typedef int (*odph_table_get_value)(odph_table_t table, void *key, - void *buffer, - uint32_t buffer_size); -/** - * Delete the association specified by key - * When no data is currently associated with key, this operation - * has no effect. When key is already associated data ad0, - * then (key,ad0) pair is deleted. - * - * @param table Handle of the table that the element will be removed from - * - * @param key address of 'key' in key-value pair - * User should make sure the address and key_size bytes after - * are accessible - * - * @retval 0 Success - * @retval -1 Failure - * - * @note - */ -typedef int (*odph_table_remove_value)(odph_table_t table, void *key); - -/** - * Table interface set. Defining the table operations. - */ -typedef struct odph_table_ops_t { - odph_table_create f_create; /**< Table Create */ - odph_table_lookup f_lookup; /**< Table Lookup */ - odph_table_destroy f_des; /**< Table Destroy */ - /** add (key,associated data) pair into the specific table */ - odph_table_put_value f_put; - /** lookup the associated data via specific key */ - odph_table_get_value f_get; - /** delete the association specified by key */ - odph_table_remove_value f_remove; -} odph_table_ops_t; - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/helper/include/odp/helper/threads.h b/helper/include/odp/helper/threads.h index c18a46e8a..ca420e80a 100644 --- a/helper/include/odp/helper/threads.h +++ b/helper/include/odp/helper/threads.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright (c) 2013-2018 Linaro Limited - * Copyright (c) 2019-2021 Nokia + * Copyright (c) 2019-2024 Nokia */ @@ -191,6 +191,20 @@ typedef struct { } odph_thread_common_param_t; +/** Thread join result */ +typedef struct { + /** Exit caused by signal */ + odp_bool_t is_sig; + + /** + * Exit status of the joined thread/process + * + * If 'is_sig' is true, then this is the signal number that caused + * process exit. Otherwise status of the exited thread/process. + */ + int ret; +} odph_thread_join_result_t; + /** * Initialize thread params * @@ -236,7 +250,8 @@ void odph_thread_common_param_init(odph_thread_common_param_t *param); * thread goes to the smallest CPU number of the mask, etc. * * Launched threads may be waited for exit with odph_thread_join(), or with - * direct Linux system calls. + * direct Linux system calls. If odph_thread_join() is used, the output thread + * table elements must not be modified during the life time of the threads. * * @param[out] thread Thread table for output * @param param Common parameters for all threads to be created @@ -261,10 +276,14 @@ int odph_thread_create(odph_thread_t thread[], * A function call may be used to wait any number of launched threads to exit. * A particular thread may be waited only once. * + * Threads are joined in the order they are in 'thread' table. Returns on the + * first non-zero exit status or other failure. + * * @param thread Table of threads to exit * @param num Number of threads to exit * - * @return Number of threads exited + * @return Number of threads successfully joined with zero exit status + * (0 ... num) * @retval -1 On failure * * @see odph_thread_create() @@ -272,6 +291,26 @@ int odph_thread_create(odph_thread_t thread[], int odph_thread_join(odph_thread_t thread[], int num); /** + * Wait previously launched threads to exit + * + * Similar to odph_thread_join() but outputs results of joined threads and + * stops only if the actual join operation fails for some thread. Threads are + * joined in the order they are in 'thread' table. Returns number of threads + * successfully joined and writes respective exit statuses into the 'res' + * table. + * + * @param thread Table of threads to exit + * @param[out] res Table for result output + * @param num Number of threads to exit and results to output + * + * @return Number of threads successfully joined (0 ... num) + * @retval -1 On failure + * + * @see odph_thread_create() + */ +int odph_thread_join_result(odph_thread_t thread[], odph_thread_join_result_t res[], int num); + +/** * Set CPU affinity of the current odp thread * * CPU affinity determines the CPU core on which the thread is diff --git a/helper/include/odph_list_internal.h b/helper/include/odph_list_internal.h deleted file mode 100644 index d90b07ebc..000000000 --- a/helper/include/odph_list_internal.h +++ /dev/null @@ -1,88 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2015-2018 Linaro Limited - */ - -/** - * @file - * - * ODP list - * a simple implementation of Doubly linked list - */ - -#ifndef ODPH_LIST_INTER_H_ -#define ODPH_LIST_INTER_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -/** @cond _ODP_HIDE_FROM_DOXYGEN_ */ - -typedef struct odph_list_object { - struct odph_list_object *next; - - struct odph_list_object *prev; -} odph_list_object; - -typedef odph_list_object odph_list_head; - -static inline void ODPH_INIT_LIST_HEAD(odph_list_object *list) -{ - list->next = list; - list->prev = list; -} - -static inline void __odph_list_add(odph_list_object *new, - odph_list_object *prev, - odph_list_object *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -static inline void odph_list_add(odph_list_object *new, odph_list_object *head) -{ - __odph_list_add(new, head, head->next); -} - -static inline void odph_list_add_tail(struct odph_list_object *new, - odph_list_object *head) -{ - __odph_list_add(new, head->prev, head); -} - -static inline void __odph_list_del(struct odph_list_object *prev, - odph_list_object *next) -{ - next->prev = prev; - prev->next = next; -} - -static inline void odph_list_del(struct odph_list_object *entry) -{ - __odph_list_del(entry->prev, entry->next); - ODPH_INIT_LIST_HEAD(entry); -} - -static inline int odph_list_empty(const struct odph_list_object *head) -{ - return head->next == head; -} - -#define container_of(ptr, type, list_node) \ - ((type *)(void *)((char *)ptr - offsetof(type, list_node))) - -#define ODPH_LIST_FOR_EACH(pos, list_head, type, list_node) \ - for (pos = container_of((list_head)->next, type, list_node); \ - &pos->list_node != (list_head); \ - pos = container_of(pos->list_node.next, type, list_node)) - -/** @endcond */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/helper/iplookuptable.c b/helper/iplookuptable.c deleted file mode 100644 index 31273a0a5..000000000 --- a/helper/iplookuptable.c +++ /dev/null @@ -1,990 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2016-2018 Linaro Limited - */ - -#include <string.h> -#include <stdint.h> -#include <errno.h> -#include <stdio.h> - -#include <odp/helper/odph_iplookuptable.h> -#include <odp/helper/odph_debug.h> -#include "odph_list_internal.h" -#include <odp_api.h> - -/** @magic word, write to the first byte of the memory block - * to indicate this block is used by a ip lookup table - */ -#define ODPH_IP_LOOKUP_TABLE_MAGIC_WORD 0xCFCFFCFC - -/* The length(bit) of the IPv4 address */ -#define IP_LENGTH 32 - -/* The number of L1 entries */ -#define ENTRY_NUM_L1 (1 << 16) -/* The size of one L2\L3 subtree */ -#define ENTRY_NUM_SUBTREE (1 << 8) - -#define WHICH_CHILD(ip, cidr) ((ip >> (IP_LENGTH - cidr)) & 0x00000001) - -/** @internal entry struct - * Structure store an entry of the ip prefix table. - * Because of the leaf pushing, each entry of the table must have - * either a child entry, or a nexthop info. - * If child == 0 and index != ODP_BUFFER_INVALID, this entry has - * a nexthop info, index indicates the buffer that stores the - * nexthop value, and ptr points to the address of the buffer. - * If child == 1, this entry has a subtree, index indicates - * the buffer that stores the subtree, and ptr points to the - * address of the buffer. - */ -typedef struct { - union { - odp_buffer_t nexthop; - void *ptr; - }; - union { - uint8_t u8; - struct { -#if ODP_BYTE_ORDER == ODP_BIG_ENDIAN - uint8_t child : 1; - uint8_t cidr : 7; -#else - uint8_t cidr : 7; - uint8_t child : 1; -#endif - }; - }; -} prefix_entry_t; - -#define ENTRY_SIZE (sizeof(prefix_entry_t) + sizeof(odp_buffer_t)) -#define ENTRY_BUFF_ARR(x) ((odp_buffer_t *)(void *)((char *)x \ - + sizeof(prefix_entry_t) * ENTRY_NUM_SUBTREE)) - -/** @internal trie node struct - * In this IP lookup algorithm, we use a - * binary tire to detect the overlap prefix. - */ -typedef struct trie_node { - /* tree structure */ - struct trie_node *parent; - struct trie_node *left; - struct trie_node *right; - /* IP prefix length */ - uint8_t cidr; - /* Nexthop buffer index */ - odp_buffer_t nexthop; - /* Buffer that stores this node */ - odp_buffer_t buffer; -} trie_node_t; - -/** Number of L2\L3 entries(subtrees) per cache cube. */ -#define CACHE_NUM_SUBTREE (4 * 1024) -/** Number of trie nodes per cache cube. */ -#define CACHE_NUM_TRIE (4 * 1024) - -/** @typedef cache_type_t - * Cache node type - */ -typedef enum { - CACHE_TYPE_SUBTREE = 0, - CACHE_TYPE_TRIE -} cache_type_t; - -/** A IP lookup table structure. */ -typedef struct ODP_ALIGNED_CACHE { - /**< for check */ - uint32_t magicword; - /** Name of the hash. */ - char name[ODPH_TABLE_NAME_LEN]; - /** Total L1 entries. */ - prefix_entry_t *l1e; - /** Root node of the binary trie */ - trie_node_t *trie; - /** Length of value. */ - uint32_t nexthop_len; - /** Queues of free slots (caches) - * There are two queues: - * - free_slots[CACHE_TYPE_SUBTREE] is used for L2 and - * L3 entries (subtrees). Each entry stores an 8-bit - * subtree. - * - free_slots[CACHE_TYPE_TRIE] is used for the binary - * trie. Each entry contains a trie node. - */ - odp_queue_t free_slots[2]; - /** The number of pool used by each queue. */ - uint32_t cache_count[2]; -} odph_iplookup_table_impl; - -/*********************************************************** - ***************** Cache management ******************** - ***********************************************************/ - -/** Destroy all caches */ -static void -cache_destroy(odph_iplookup_table_impl *impl) -{ - odp_queue_t queue; - odp_event_t ev; - uint32_t i = 0, count = 0; - char pool_name[ODPH_TABLE_NAME_LEN + 8]; - - /* free all buffers in the queue */ - for (; i < 2; i++) { - queue = impl->free_slots[i]; - if (queue == ODP_QUEUE_INVALID) - continue; - - while ((ev = odp_queue_deq(queue)) - != ODP_EVENT_INVALID) { - odp_buffer_free(odp_buffer_from_event(ev)); - } - odp_queue_destroy(queue); - } - - /* destroy all cache pools */ - for (i = 0; i < 2; i++) { - for (count = 0; count < impl->cache_count[i]; count++) { - sprintf( - pool_name, "%s_%d_%d", - impl->name, i, count); - (void)odp_pool_destroy(odp_pool_lookup(pool_name)); - } - } -} - -/** According to the type of cache, set the value of - * a buffer to the initial value. - */ -static void -cache_init_buffer(odp_buffer_t buffer, cache_type_t type, uint32_t size) -{ - int i = 0; - void *addr = odp_buffer_addr(buffer); - - memset(addr, 0, size); - if (type == CACHE_TYPE_SUBTREE) { - prefix_entry_t *entry = (prefix_entry_t *)addr; - - for (i = 0; i < ENTRY_NUM_SUBTREE; i++, entry++) - entry->nexthop = ODP_BUFFER_INVALID; - } else if (type == CACHE_TYPE_TRIE) { - trie_node_t *node = (trie_node_t *)addr; - - node->buffer = buffer; - node->nexthop = ODP_BUFFER_INVALID; - } -} - -/** Create a new buffer pool, and insert its buffer into the queue. */ -static int -cache_alloc_new_pool( - odph_iplookup_table_impl *tbl, cache_type_t type) -{ - odp_pool_t pool; - odp_pool_param_t param; - odp_pool_capability_t pool_capa; - odp_queue_t queue = tbl->free_slots[type]; - - odp_buffer_t buffer; - char pool_name[ODPH_TABLE_NAME_LEN + 8]; - uint32_t size = 0, num = 0; - - if (odp_pool_capability(&pool_capa)) { - ODPH_ERR("pool capa failed\n"); - return -1; - } - - if (pool_capa.buf.max_num) { - if (pool_capa.buf.max_num < CACHE_NUM_TRIE || - pool_capa.buf.max_num < CACHE_NUM_SUBTREE) { - ODPH_ERR("pool size too small\n"); - return -1; - } - } - - if (pool_capa.buf.max_size) { - if (pool_capa.buf.max_size < ENTRY_SIZE * ENTRY_NUM_SUBTREE || - pool_capa.buf.max_size < sizeof(trie_node_t)) { - ODPH_ERR("buffer size too small\n"); - return -1; - } - } - - /* Create new pool (new free buffers). */ - odp_pool_param_init(¶m); - param.type = ODP_POOL_BUFFER; - if (pool_capa.buf.max_align >= ODP_CACHE_LINE_SIZE) - param.buf.align = ODP_CACHE_LINE_SIZE; - if (type == CACHE_TYPE_SUBTREE) { - num = CACHE_NUM_SUBTREE; - size = ENTRY_SIZE * ENTRY_NUM_SUBTREE; - } else if (type == CACHE_TYPE_TRIE) { - num = CACHE_NUM_TRIE; - size = sizeof(trie_node_t); - } else { - ODPH_DBG("wrong cache_type_t.\n"); - return -1; - } - param.buf.size = size; - param.buf.num = num; - - sprintf( - pool_name, "%s_%d_%d", - tbl->name, type, tbl->cache_count[type]); - pool = odp_pool_create(pool_name, ¶m); - if (pool == ODP_POOL_INVALID) { - ODPH_DBG("failed to create a new pool.\n"); - return -1; - } - - /* insert new free buffers into queue */ - while ((buffer = odp_buffer_alloc(pool)) - != ODP_BUFFER_INVALID) { - cache_init_buffer(buffer, type, size); - if (odp_queue_enq(queue, odp_buffer_to_event(buffer))) { - ODPH_DBG("queue enqueue failed\n"); - odp_buffer_free(buffer); - break; - } - } - - tbl->cache_count[type]++; - return 0; -} - -/** Get a new buffer from a cache list. If there is no - * available buffer, allocate a new pool. - */ -static odp_buffer_t -cache_get_buffer(odph_iplookup_table_impl *tbl, cache_type_t type) -{ - odp_buffer_t buffer = ODP_BUFFER_INVALID; - odp_queue_t queue = tbl->free_slots[type]; - - /* get free buffer from queue */ - buffer = odp_buffer_from_event( - odp_queue_deq(queue)); - - /* If there is no free buffer available, allocate new pool */ - if (buffer == ODP_BUFFER_INVALID) { - cache_alloc_new_pool(tbl, type); - buffer = odp_buffer_from_event(odp_queue_deq(queue)); - } - - return buffer; -} - -/*********************************************************** - ****************** Binary trie ******************** - ***********************************************************/ - -/* Initialize the root node of the trie */ -static int -trie_init(odph_iplookup_table_impl *tbl) -{ - trie_node_t *root = NULL; - odp_buffer_t buffer = cache_get_buffer(tbl, CACHE_TYPE_TRIE); - - if (buffer != ODP_BUFFER_INVALID) { - root = (trie_node_t *)odp_buffer_addr(buffer); - root->cidr = 0; - tbl->trie = root; - return 0; - } - - return -1; -} - -/* Destroy the whole trie (recursively) */ -static void -trie_destroy(odph_iplookup_table_impl *tbl, trie_node_t *trie) -{ - if (trie->left != NULL) - trie_destroy(tbl, trie->left); - if (trie->right != NULL) - trie_destroy(tbl, trie->right); - - /* destroy this node */ - odp_queue_enq( - tbl->free_slots[CACHE_TYPE_TRIE], - odp_buffer_to_event(trie->buffer)); -} - -/* Insert a new prefix node into the trie - * If the node is already existed, update its nexthop info, - * Return 0 and set nexthop pointer to INVALID. - * If the node is not exitsed, create this target node and - * all nodes along the path from root to the target node. - * Then return 0 and set nexthop pointer points to the - * new buffer. - * Return -1 for error. - */ -static int -trie_insert_node( - odph_iplookup_table_impl *tbl, trie_node_t *root, - uint32_t ip, uint8_t cidr, odp_buffer_t nexthop) -{ - uint8_t level = 0, child; - odp_buffer_t buf; - trie_node_t *node = root, *prev = root; - - /* create/update all nodes along the path - * from root to the new node. */ - for (level = 1; level <= cidr; level++) { - child = WHICH_CHILD(ip, level); - - node = child == 0 ? prev->left : prev->right; - /* If the child node doesn't exit, create it. */ - if (node == NULL) { - buf = cache_get_buffer(tbl, CACHE_TYPE_TRIE); - if (buf == ODP_BUFFER_INVALID) - return -1; - - node = (trie_node_t *)odp_buffer_addr(buf); - node->cidr = level; - node->parent = prev; - - if (child == 0) - prev->left = node; - else - prev->right = node; - } - prev = node; - } - - /* The final one is the target. */ - node->nexthop = nexthop; - return 0; -} - -/* Delete a node */ -static int -trie_delete_node( - odph_iplookup_table_impl *tbl, - trie_node_t *root, uint32_t ip, uint8_t cidr) -{ - if (root == NULL) - return -1; - - /* The default prefix (root node) cannot be deleted. */ - if (cidr == 0) - return -1; - - trie_node_t *node = root, *prev = NULL; - uint8_t level = 1, child = 0; - odp_buffer_t tmp; - - /* Find the target node. */ - for (level = 1; level <= cidr; level++) { - child = WHICH_CHILD(ip, level); - node = (child == 0) ? node->left : node->right; - if (node == NULL) { - ODPH_DBG("Trie node is not existed\n"); - return -1; - } - } - - node->nexthop = ODP_BUFFER_INVALID; - - /* Delete all redundant nodes along the path. */ - for (level = cidr; level > 0; level--) { - if ( - node->left != NULL || node->right != NULL || - node->nexthop != ODP_BUFFER_INVALID) - break; - - child = WHICH_CHILD(ip, level); - prev = node->parent; - - /* free trie node */ - tmp = node->buffer; - cache_init_buffer( - tmp, CACHE_TYPE_TRIE, sizeof(trie_node_t)); - odp_queue_enq( - tbl->free_slots[CACHE_TYPE_TRIE], - odp_buffer_to_event(tmp)); - - if (child == 0) - prev->left = NULL; - else - prev->right = NULL; - node = prev; - } - return 0; -} - -/* Detect the longest overlapping prefix. */ -static int -trie_detect_overlap( - trie_node_t *trie, uint32_t ip, uint8_t cidr, - uint8_t leaf_push, uint8_t *over_cidr, - odp_buffer_t *over_nexthop) -{ - uint8_t child = 0; - uint32_t level, limit = cidr > leaf_push ? leaf_push + 1 : cidr; - trie_node_t *node = trie, *longest = trie; - - for (level = 1; level < limit; level++) { - child = WHICH_CHILD(ip, level); - node = (child == 0) ? node->left : node->right; - if (node->nexthop != ODP_BUFFER_INVALID) - longest = node; - } - - *over_cidr = longest->cidr; - *over_nexthop = longest->nexthop; - return 0; -} - -/*********************************************************** - *************** IP prefix lookup table **************** - ***********************************************************/ - -odph_table_t -odph_iplookup_table_lookup(const char *name) -{ - odph_iplookup_table_impl *tbl = NULL; - odp_shm_t shm; - - if (name == NULL || strlen(name) >= ODPH_TABLE_NAME_LEN) - return NULL; - - shm = odp_shm_lookup(name); - if (shm != ODP_SHM_INVALID) - tbl = (odph_iplookup_table_impl *)odp_shm_addr(shm); - - if ( - tbl != NULL && - tbl->magicword == ODPH_IP_LOOKUP_TABLE_MAGIC_WORD && - strcmp(tbl->name, name) == 0) - return (odph_table_t)tbl; - - return NULL; -} - -odph_table_t odph_iplookup_table_create(const char *name, - uint32_t p1 ODP_UNUSED, - uint32_t p2 ODP_UNUSED, - uint32_t value_size) -{ - odph_iplookup_table_impl *tbl; - odp_shm_t shm_tbl; - odp_queue_t queue; - odp_queue_param_t qparam; - odp_queue_capability_t queue_capa; - unsigned i; - uint32_t impl_size, l1_size, queue_size; - char queue_name[ODPH_TABLE_NAME_LEN + 2]; - - if (odp_queue_capability(&queue_capa)) { - ODPH_ERR("queue capa failed\n"); - return NULL; - } - - if (queue_capa.plain.max_size) { - if (queue_capa.plain.max_size < CACHE_NUM_TRIE || - queue_capa.plain.max_size < CACHE_NUM_SUBTREE) { - ODPH_ERR("queue size too small\n"); - return NULL; - } - } - - queue_size = CACHE_NUM_TRIE; - if (CACHE_NUM_SUBTREE > CACHE_NUM_TRIE) - queue_size = CACHE_NUM_SUBTREE; - - /* Check for valid parameters */ - if (strlen(name) == 0) { - ODPH_DBG("invalid parameters\n"); - return NULL; - } - - /* Guarantee there's no existing */ - tbl = (void *)odph_iplookup_table_lookup(name); - if (tbl != NULL) { - ODPH_DBG("IP prefix table %s already exists\n", name); - return NULL; - } - - /* Calculate the sizes of different parts of IP prefix table */ - impl_size = sizeof(odph_iplookup_table_impl); - l1_size = ENTRY_SIZE * ENTRY_NUM_L1; - - shm_tbl = odp_shm_reserve(name, impl_size + l1_size, ODP_CACHE_LINE_SIZE, 0); - - if (shm_tbl == ODP_SHM_INVALID) { - ODPH_DBG( - "shm allocation failed for odph_iplookup_table_impl %s\n", - name); - return NULL; - } - - tbl = (odph_iplookup_table_impl *)odp_shm_addr(shm_tbl); - memset(tbl, 0, impl_size + l1_size); - - /* header of this mem block is the table impl struct, - * then the l1 entries array. - */ - tbl->l1e = (prefix_entry_t *)(void *)((char *)tbl + impl_size); - for (i = 0; i < ENTRY_NUM_L1; i++) - tbl->l1e[i].nexthop = ODP_BUFFER_INVALID; - - /* Setup table context. */ - snprintf(tbl->name, sizeof(tbl->name), "%s", name); - tbl->magicword = ODPH_IP_LOOKUP_TABLE_MAGIC_WORD; - tbl->nexthop_len = value_size; - - /* Initialize cache */ - for (i = 0; i < 2; i++) { - tbl->cache_count[i] = 0; - - odp_queue_param_init(&qparam); - qparam.type = ODP_QUEUE_TYPE_PLAIN; - qparam.size = queue_size; - sprintf(queue_name, "%s_%d", name, i); - queue = odp_queue_create(queue_name, &qparam); - if (queue == ODP_QUEUE_INVALID) { - ODPH_DBG("failed to create queue"); - cache_destroy(tbl); - return NULL; - } - tbl->free_slots[i] = queue; - cache_alloc_new_pool(tbl, i); - } - - /* Initialize tire */ - if (trie_init(tbl) < 0) { - odp_shm_free(shm_tbl); - return NULL; - } - - return (odph_table_t)tbl; -} - -int -odph_iplookup_table_destroy(odph_table_t tbl) -{ - int i, j; - odph_iplookup_table_impl *impl = NULL; - prefix_entry_t *subtree = NULL; - odp_buffer_t *buff1 = NULL, *buff2 = NULL; - - if (tbl == NULL) - return -1; - - impl = (odph_iplookup_table_impl *)(void *)tbl; - - /* check magic word */ - if (impl->magicword != ODPH_IP_LOOKUP_TABLE_MAGIC_WORD) { - ODPH_DBG("wrong magicword for IP prefix table\n"); - return -1; - } - - /* destroy trie */ - trie_destroy(impl, impl->trie); - - /* free all L2 and L3 entries */ - buff1 = ENTRY_BUFF_ARR(impl->l1e); - for (i = 0; i < ENTRY_NUM_L1; i++) { - if ((impl->l1e[i]).child == 0) - continue; - - subtree = (prefix_entry_t *)impl->l1e[i].ptr; - buff2 = ENTRY_BUFF_ARR(subtree); - /* destroy all l3 subtrees of this l2 subtree */ - for (j = 0; j < ENTRY_NUM_SUBTREE; j++) { - if (subtree[j].child == 0) - continue; - odp_queue_enq( - impl->free_slots[CACHE_TYPE_TRIE], - odp_buffer_to_event(buff2[j])); - } - /* destroy this l2 subtree */ - odp_queue_enq( - impl->free_slots[CACHE_TYPE_TRIE], - odp_buffer_to_event(buff1[i])); - } - - /* destroy all cache */ - cache_destroy(impl); - - /* free impl */ - odp_shm_free(odp_shm_lookup(impl->name)); - return 0; -} - -/* Insert the prefix into level x - * Return: - * -1 error - * 0 the table is unmodified - * 1 the table is modified - */ -static int -prefix_insert_into_lx( - odph_iplookup_table_impl *tbl, prefix_entry_t *entry, - uint8_t cidr, odp_buffer_t nexthop, uint8_t level) -{ - int ret = 0; - uint32_t i = 0, limit = (1 << (level - cidr)); - prefix_entry_t *e = entry, *ne = NULL; - - for (i = 0; i < limit; i++, e++) { - if (e->cidr > cidr) - continue; - - if (e->child == 1) { - e->cidr = cidr; - /* push to next level */ - ne = (prefix_entry_t *)e->ptr; - ret = prefix_insert_into_lx( - tbl, ne, cidr, nexthop, cidr + 8); - if (ret == -1) - return -1; - if (ret == 0) - return ret; - } else { - e->child = 0; - e->cidr = cidr; - e->nexthop = nexthop; - ret = 1; - } - } - return ret; -} - -static int -prefix_insert_iter( - odph_iplookup_table_impl *tbl, prefix_entry_t *entry, - odp_buffer_t *buff, uint32_t ip, uint8_t cidr, - odp_buffer_t nexthop, uint8_t level, uint8_t depth) -{ - uint8_t state = 0; - prefix_entry_t *ne = NULL; - odp_buffer_t *nbuff = NULL; - - /* If child subtree is existed, get it. */ - if (entry->child) { - ne = (prefix_entry_t *)entry->ptr; - nbuff = ENTRY_BUFF_ARR(ne); - } else { - /* If the child is not existed, create a new subtree. */ - odp_buffer_t buf, push = entry->nexthop; - - buf = cache_get_buffer(tbl, CACHE_TYPE_SUBTREE); - if (buf == ODP_BUFFER_INVALID) { - ODPH_DBG("failed to get subtree buffer from cache.\n"); - return -1; - } - ne = (prefix_entry_t *)odp_buffer_addr(buf); - nbuff = ENTRY_BUFF_ARR(ne); - - entry->child = 1; - entry->ptr = ne; - *buff = buf; - - /* If this entry contains a nexthop and a small cidr, - * push it to the next level. - */ - if (entry->cidr > 0) - (void)prefix_insert_into_lx(tbl, ne, entry->cidr, - push, entry->cidr + 8); - } - - ne += (ip >> 24); - nbuff += (ip >> 24); - if (cidr <= 8) { - state = prefix_insert_into_lx( - tbl, ne, cidr + depth * 8, nexthop, level); - } else { - state = prefix_insert_iter( - tbl, ne, nbuff, ip << 8, cidr - 8, - nexthop, level + 8, depth + 1); - } - - return state; -} - -int -odph_iplookup_table_put_value(odph_table_t tbl, void *key, void *value) -{ - odph_iplookup_table_impl *impl = (void *)tbl; - odph_iplookup_prefix_t *prefix = (odph_iplookup_prefix_t *)key; - prefix_entry_t *l1e = NULL; - odp_buffer_t nexthop; - int ret = 0; - - if ((tbl == NULL) || (key == NULL) || (value == NULL)) - return -1; - - nexthop = *((odp_buffer_t *)value); - - if (prefix->cidr == 0 || prefix->cidr > 32) - return -1; - - prefix->ip = prefix->ip & (0xffffffff << (IP_LENGTH - prefix->cidr)); - - /* insert into trie */ - ret = trie_insert_node( - impl, impl->trie, - prefix->ip, prefix->cidr, nexthop); - - if (ret < 0) { - ODPH_DBG("failed to insert into trie\n"); - return -1; - } - - /* get L1 entry */ - l1e = &impl->l1e[prefix->ip >> 16]; - odp_buffer_t *buff = ENTRY_BUFF_ARR(impl->l1e) + (prefix->ip >> 16); - - if (prefix->cidr <= 16) { - ret = prefix_insert_into_lx( - impl, l1e, prefix->cidr, nexthop, 16); - } else { - ret = prefix_insert_iter( - impl, l1e, buff, - ((prefix->ip) << 16), prefix->cidr - 16, - nexthop, 24, 2); - } - - return ret; -} - -int odph_iplookup_table_get_value(odph_table_t tbl, void *key, - void *buffer ODP_UNUSED, - uint32_t buffer_size ODP_UNUSED) -{ - odph_iplookup_table_impl *impl = (void *)tbl; - uint32_t ip; - prefix_entry_t *entry; - odp_buffer_t *buff = (odp_buffer_t *)buffer; - - if ((tbl == NULL) || (key == NULL) || (buffer == NULL)) - return -EINVAL; - - ip = *((uint32_t *)key); - entry = &impl->l1e[ip >> 16]; - - if (entry == NULL) { - ODPH_DBG("failed to get L1 entry.\n"); - return -1; - } - - ip <<= 16; - while (entry->child) { - entry = (prefix_entry_t *)entry->ptr; - entry += ip >> 24; - ip <<= 8; - } - - /* copy data */ - if (entry->nexthop == ODP_BUFFER_INVALID) { - /* ONLY match the default prefix */ - printf("only match the default prefix\n"); - *buff = ODP_BUFFER_INVALID; - } else { - *buff = entry->nexthop; - } - - return 0; -} - -static int -prefix_delete_lx( - odph_iplookup_table_impl *tbl, prefix_entry_t *l1e, - odp_buffer_t *buff, uint8_t cidr, uint8_t over_cidr, - odp_buffer_t over_nexthop, uint8_t level) -{ - uint8_t ret, flag = 1; - prefix_entry_t *e = l1e; - odp_buffer_t *b = buff; - uint32_t i = 0, limit = 1 << (level - cidr); - - for (i = 0; i < limit; i++, e++, b++) { - if (e->child == 1) { - if (e->cidr > cidr) { - flag = 0; - continue; - } - - prefix_entry_t *ne = (prefix_entry_t *)e->ptr; - odp_buffer_t *nbuff = ENTRY_BUFF_ARR(ne); - - e->cidr = over_cidr; - ret = prefix_delete_lx( - tbl, ne, nbuff, cidr, over_cidr, - over_nexthop, cidr + 8); - - /* If ret == 1, the next 2^8 entries equal to - * (over_cidr, over_nexthop). In this case, we - * should not push the (over_cidr, over_nexthop) - * to the next level. In fact, we should recycle - * the next 2^8 entries. - */ - if (ret) { - /* destroy subtree */ - cache_init_buffer( - *b, CACHE_TYPE_SUBTREE, - ENTRY_SIZE * ENTRY_NUM_SUBTREE); - odp_queue_enq( - tbl->free_slots[CACHE_TYPE_SUBTREE], - odp_buffer_to_event(*b)); - e->child = 0; - e->nexthop = over_nexthop; - } else { - flag = 0; - } - } else { - if (e->cidr > cidr) { - flag = 0; - continue; - } else { - e->cidr = over_cidr; - e->nexthop = over_nexthop; - } - } - } - return flag; -} - -/* Check if the entry can be recycled. - * An entry can be recycled duo to two reasons: - * - all children of the entry are the same, - * - all children of the entry have a cidr smaller than the level - * bottom bound. - */ -static uint8_t -can_recycle(prefix_entry_t *e, uint32_t level) -{ - uint8_t recycle = 1; - int i = 1; - prefix_entry_t *ne = (prefix_entry_t *)e->ptr; - - if (ne->child) - return 0; - - uint8_t cidr = ne->cidr; - odp_buffer_t index = ne->nexthop; - - if (cidr > level) - return 0; - - ne++; - for (; i < 256; i++, ne++) { - if ( - ne->child != 0 || ne->cidr != cidr || - ne->nexthop != index) { - recycle = 0; - break; - } - } - return recycle; -} - -static uint8_t -prefix_delete_iter( - odph_iplookup_table_impl *tbl, prefix_entry_t *e, - odp_buffer_t *buff, uint32_t ip, uint8_t cidr, - uint8_t level, uint8_t depth) -{ - uint8_t ret = 0, over_cidr; - odp_buffer_t over_nexthop; - - trie_detect_overlap( - tbl->trie, ip, cidr + 8 * depth, level, - &over_cidr, &over_nexthop); - if (cidr > 8) { - prefix_entry_t *ne = - (prefix_entry_t *)e->ptr; - odp_buffer_t *nbuff = ENTRY_BUFF_ARR(ne); - - ne += ((uint32_t)(ip << level) >> 24); - nbuff += ((uint32_t)(ip << level) >> 24); - ret = prefix_delete_iter( - tbl, ne, nbuff, ip, cidr - 8, - level + 8, depth + 1); - - if (ret && can_recycle(e, level)) { - /* destroy subtree */ - cache_init_buffer( - *buff, CACHE_TYPE_SUBTREE, - ENTRY_SIZE * ENTRY_NUM_SUBTREE); - odp_queue_enq( - tbl->free_slots[CACHE_TYPE_SUBTREE], - odp_buffer_to_event(*buff)); - e->child = 0; - e->nexthop = over_nexthop; - e->cidr = over_cidr; - return 1; - } - return 0; - } - - ret = prefix_delete_lx( - tbl, e, buff, cidr + 8 * depth, - over_cidr, over_nexthop, level); - return ret; -} - -int -odph_iplookup_table_remove_value(odph_table_t tbl, void *key) -{ - odph_iplookup_table_impl *impl = (void *)tbl; - odph_iplookup_prefix_t *prefix = (odph_iplookup_prefix_t *)key; - uint32_t ip; - uint8_t cidr; - - if ((tbl == NULL) || (key == NULL)) - return -EINVAL; - - ip = prefix->ip; - cidr = prefix->cidr; - - if (cidr == 0 || cidr > 32) - return -EINVAL; - - prefix_entry_t *entry = &impl->l1e[ip >> 16]; - odp_buffer_t *buff = ENTRY_BUFF_ARR(impl->l1e) + (ip >> 16); - uint8_t over_cidr, ret; - odp_buffer_t over_nexthop; - - trie_detect_overlap( - impl->trie, ip, cidr, 16, &over_cidr, &over_nexthop); - - if (cidr <= 16) { - prefix_delete_lx( - impl, entry, buff, cidr, over_cidr, over_nexthop, 16); - } else { - prefix_entry_t *ne = (prefix_entry_t *)entry->ptr; - odp_buffer_t *nbuff = ENTRY_BUFF_ARR(ne); - - ne += ((uint32_t)(ip << 16) >> 24); - nbuff += ((uint32_t)(ip << 16) >> 24); - ret = prefix_delete_iter(impl, ne, nbuff, ip, cidr - 16, 24, 2); - - if (ret && can_recycle(entry, 16)) { - /* destroy subtree */ - cache_init_buffer( - *buff, CACHE_TYPE_SUBTREE, - sizeof(prefix_entry_t) * ENTRY_NUM_SUBTREE); - odp_queue_enq( - impl->free_slots[CACHE_TYPE_SUBTREE], - odp_buffer_to_event(*buff)); - entry->child = 0; - entry->cidr = over_cidr; - entry->nexthop = over_nexthop; - } - } - - return trie_delete_node(impl, impl->trie, ip, cidr); -} - -odph_table_ops_t odph_iplookup_table_ops = { - odph_iplookup_table_create, - odph_iplookup_table_lookup, - odph_iplookup_table_destroy, - odph_iplookup_table_put_value, - odph_iplookup_table_get_value, - odph_iplookup_table_remove_value -}; diff --git a/helper/ipsec.c b/helper/ipsec.c index bb7d5d0eb..1589d33bd 100644 --- a/helper/ipsec.c +++ b/helper/ipsec.c @@ -4,8 +4,8 @@ * Copyright (c) 2021 Nokia */ +#include <odp/helper/debug.h> #include <odp/helper/ipsec.h> -#include <odp/helper/odph_debug.h> uint32_t odph_ipsec_auth_icv_len_default(odp_auth_alg_t auth_alg) { diff --git a/helper/lineartable.c b/helper/lineartable.c deleted file mode 100644 index 290a90c02..000000000 --- a/helper/lineartable.c +++ /dev/null @@ -1,216 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2015-2018 Linaro Limited - */ - -#include <stdio.h> -#include <string.h> -#include <malloc.h> - -#include <odp/helper/odph_lineartable.h> -#include <odp/helper/odph_debug.h> -#include <odp_api.h> - -#define ODPH_SUCCESS 0 -#define ODPH_FAIL -1 - -/** @magic word, write to the first byte of the memory block - * to indicate this block is used by a linear table structure - */ -#define ODPH_LINEAR_TABLE_MAGIC_WORD 0xEFEFFEFE - -/** @internal table struct - * For linear table, value is orgnized as a big array, - * and key is the index of this array, so we just need to record the - * content of value, and make sure the key won't overflow - */ -typedef struct { - uint32_t magicword; /**< for check */ - uint32_t init_cap; /**< input param of capacity */ - /** given the capacity, calculate out the max supported nodes number */ - uint32_t node_sum; - /** size of a lineartable element,including the rwlock in the head */ - uint32_t value_size; - void *value_array; /**< value pool in array format */ - char name[ODPH_TABLE_NAME_LEN]; /**< name of the table */ -} odph_linear_table_imp; - -/** Note: for linear table, key must be an number, its size is fixed 4. - * So, we ignore the input key_size here - */ - -odph_table_t odph_linear_table_create(const char *name, uint32_t capacity, - uint32_t un ODP_UNUSED, - uint32_t value_size) -{ - uint32_t idx; - uint32_t node_num; - odp_shm_t shmem; - odph_linear_table_imp *tbl; - - if (strlen(name) >= ODPH_TABLE_NAME_LEN || capacity < 1 || - capacity >= 0x1000 || value_size == 0) { - printf("create para input error or less than !"); - return NULL; - } - /* check name conflict in shm*/ - if (odp_shm_lookup(name) != ODP_SHM_INVALID) { - ODPH_DBG("name already exist\n"); - return NULL; - } - - /* alloc memory from shm */ - shmem = odp_shm_reserve(name, capacity << 20, 64, 0); - if (shmem == ODP_SHM_INVALID) { - ODPH_DBG("shm reserve fail\n"); - return NULL; - } - tbl = (odph_linear_table_imp *)odp_shm_addr(shmem); - - /* clean this block of memory */ - memset(tbl, 0, capacity << 20); - - tbl->init_cap = capacity < 20; - - strncpy(tbl->name, name, ODPH_TABLE_NAME_LEN - 1); - - /* for linear table, the key is just the index, without conflict - * so we just need to record the value content - * there is a rwlock in the head of every node - */ - - tbl->value_size = value_size + sizeof(odp_rwlock_t); - - node_num = tbl->init_cap / tbl->value_size; - tbl->node_sum = node_num; - - tbl->value_array = (void *)((char *)tbl - + sizeof(odph_linear_table_imp)); - - /* initialize rwlock*/ - for (idx = 0; idx < tbl->node_sum; idx++) { - odp_rwlock_t *lock; - - lock = (odp_rwlock_t *)(void *)((char *)tbl->value_array - + idx * tbl->value_size); - odp_rwlock_init(lock); - } - - tbl->magicword = ODPH_LINEAR_TABLE_MAGIC_WORD; - - return (odph_table_t)(tbl); -} - -int odph_linear_table_destroy(odph_table_t table) -{ - int ret; - odph_linear_table_imp *linear_tbl = NULL; - - if (table != NULL) { - linear_tbl = (odph_linear_table_imp *)(void *)table; - - /* check magicword, make sure the memory is used by a table */ - if (linear_tbl->magicword != ODPH_LINEAR_TABLE_MAGIC_WORD) - return ODPH_FAIL; - - ret = odp_shm_free(odp_shm_lookup(linear_tbl->name)); - if (ret != 0) { - ODPH_DBG("free fail\n"); - return ret; - } - - return ODPH_SUCCESS; - } - return ODPH_FAIL; -} - -odph_table_t odph_linear_table_lookup(const char *name) -{ - odph_linear_table_imp *tbl = NULL; - odp_shm_t shm; - - if (name == NULL || strlen(name) >= ODPH_TABLE_NAME_LEN) - return NULL; - - shm = odp_shm_lookup(name); - if (shm != ODP_SHM_INVALID) - tbl = (odph_linear_table_imp *)odp_shm_addr(shm); - - /* check magicword to make sure the memory block is used by a table */ - if (tbl != NULL && - tbl->magicword == ODPH_LINEAR_TABLE_MAGIC_WORD && - strcmp(tbl->name, name) == 0) - return (odph_table_t)tbl; - - return NULL; -} - -/* should make sure the input table exists and is available */ -static int odph_lineartable_put_value(odph_table_t table, - void *key, void *value) -{ - odph_linear_table_imp *tbl; - uint32_t ikey = 0; - void *entry = NULL; - odp_rwlock_t *lock = NULL; - - if (table == NULL || key == NULL || value == NULL) - return ODPH_FAIL; - - tbl = (odph_linear_table_imp *)(void *)table; - ikey = *(uint32_t *)key; - if (ikey >= tbl->node_sum) - return ODPH_FAIL; - - entry = (void *)((char *)tbl->value_array + ikey * tbl->value_size); - lock = (odp_rwlock_t *)entry; - entry = (char *)entry + sizeof(odp_rwlock_t); - - odp_rwlock_write_lock(lock); - - memcpy(entry, value, tbl->value_size - sizeof(odp_rwlock_t)); - - odp_rwlock_write_unlock(lock); - - return ODPH_SUCCESS; -} - -/* should make sure the input table exists and is available */ -static int odph_lineartable_get_value(odph_table_t table, - void *key, void *buffer, - uint32_t buffer_size ODP_UNUSED) -{ - odph_linear_table_imp *tbl; - uint32_t ikey = 0; - void *entry = NULL; - odp_rwlock_t *lock = NULL; - - if (table == NULL || key == NULL || buffer == NULL) - return ODPH_FAIL; - - tbl = (odph_linear_table_imp *)(void *)table; - ikey = *(uint32_t *)key; - if (ikey >= tbl->node_sum) - return ODPH_FAIL; - - entry = (void *)((char *)tbl->value_array + ikey * tbl->value_size); - lock = (odp_rwlock_t *)entry; - entry = (char *)entry + sizeof(odp_rwlock_t); - - odp_rwlock_read_lock(lock); - - memcpy(buffer, entry, tbl->value_size - sizeof(odp_rwlock_t)); - - odp_rwlock_read_unlock(lock); - - return ODPH_SUCCESS; -} - -odph_table_ops_t odph_linear_table_ops = { - odph_linear_table_create, - odph_linear_table_lookup, - odph_linear_table_destroy, - odph_lineartable_put_value, - odph_lineartable_get_value, - NULL, - }; - diff --git a/helper/linux/thread.c b/helper/linux/thread.c index d5b016833..ec2847a88 100644 --- a/helper/linux/thread.c +++ b/helper/linux/thread.c @@ -18,9 +18,9 @@ #include <stdbool.h> #include <odp_api.h> +#include <odp/helper/debug.h> #include <odp/helper/linux/pthread.h> #include <odp/helper/linux/process.h> -#include <odp/helper/odph_debug.h> static void *_odph_run_start_routine(void *arg) { diff --git a/helper/m4/configure.m4 b/helper/m4/configure.m4 index 2e1076172..04768f25e 100644 --- a/helper/m4/configure.m4 +++ b/helper/m4/configure.m4 @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2016 Linaro Limited +# + ########################################################################## # Include m4 files ########################################################################## diff --git a/helper/m4/libcli.m4 b/helper/m4/libcli.m4 index 6748cbb41..7edaf3a5d 100644 --- a/helper/m4/libcli.m4 +++ b/helper/m4/libcli.m4 @@ -1,3 +1,7 @@ +# SPDX-License-Identifier: BSD-3-Clause +# Copyright (c) 2021 Nokia +# + ########################################################################## # Set optional libcli path ########################################################################## diff --git a/helper/test/.gitignore b/helper/test/.gitignore index 3db451f68..6fb54ea3b 100644 --- a/helper/test/.gitignore +++ b/helper/test/.gitignore @@ -2,13 +2,11 @@ *.log chksum cli -cuckootable -iplookuptable macros odpthreads parse process -table +stress thread pthread version diff --git a/helper/test/Makefile.am b/helper/test/Makefile.am index 9cf48d7d9..07986761c 100644 --- a/helper/test/Makefile.am +++ b/helper/test/Makefile.am @@ -3,11 +3,9 @@ include $(top_srcdir)/test/Makefile.inc EXECUTABLES = version \ debug \ chksum \ - cuckootable \ macros \ - parse\ - table \ - iplookuptable + parse \ + stress #These are platform specific extensions that are not portable #They are a convenience to app writers who have chosen to @@ -39,12 +37,10 @@ test_PROGRAMS = $(EXECUTABLES) $(COMPILE_ONLY) dist_check_SCRIPTS = odpthreads_as_processes odpthreads_as_pthreads chksum_SOURCES = chksum.c -cuckootable_SOURCES = cuckootable.c macros_SOURCES = macros.c odpthreads_SOURCES = odpthreads.c parse_SOURCES = parse.c -table_SOURCES = table.c -iplookuptable_SOURCES = iplookuptable.c +stress_SOURCES = stress.c version_SOURCES = version.c debug_SOURCES = debug.c diff --git a/helper/test/cli.c b/helper/test/cli.c index 08e750153..f7f072fef 100644 --- a/helper/test/cli.c +++ b/helper/test/cli.c @@ -1,5 +1,5 @@ /* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2021 Nokia + * Copyright (c) 2021-2024 Nokia */ #include <odp_api.h> @@ -9,7 +9,7 @@ static int cli_server(void *arg ODP_UNUSED) { if (odph_cli_run()) { ODPH_ERR("odph_cli_run() failed.\n"); - exit(EXIT_FAILURE); + return -1; } return 0; @@ -55,6 +55,7 @@ int main(int argc, char *argv[]) odph_thread_common_param_t thr_common; odph_thread_param_t thr_param; odph_thread_t thr_server; + odph_thread_join_result_t res; if (odp_cpumask_default_control(&cpumask, 1) != 1) { ODPH_ERR("Failed to get default CPU mask.\n"); @@ -86,8 +87,14 @@ int main(int argc, char *argv[]) exit(EXIT_FAILURE); } - if (odph_thread_join(&thr_server, 1) != 1) { - ODPH_ERR("Failed to join server thread.\n"); + if (odph_thread_join_result(&thr_server, &res, 1) != 1) { + ODPH_ERR("Error: failed to join server thread.\n"); + exit(EXIT_FAILURE); + } + + if (res.is_sig || res.ret != 0) { + ODPH_ERR("Error: worker thread failure%s: %d.\n", res.is_sig ? " (signaled)" : "", + res.ret); exit(EXIT_FAILURE); } diff --git a/helper/test/cuckootable.c b/helper/test/cuckootable.c deleted file mode 100644 index d17f79562..000000000 --- a/helper/test/cuckootable.c +++ /dev/null @@ -1,577 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2016-2018 Linaro Limited - */ - -/*- - * BSD LICENSE - * - * Copyright(c) 2010-2016 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. - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <errno.h> -#include <sys/queue.h> -#include <sys/time.h> -#include <time.h> - -#include <odp_api.h> -#include <odp/helper/odph_api.h> - -/******************************************************************************* - * Hash function performance test configuration section. - * - * The five arrays below control what tests are performed. Every combination - * from the array entries is tested. - */ -/******************************************************************************/ - -/* 5-tuple key type */ -struct flow_key { - uint32_t ip_src; - uint32_t ip_dst; - uint16_t port_src; - uint16_t port_dst; - uint8_t proto; -} __packed; - -/* - * Print out result of unit test hash operation. - */ -static void print_key_info( - const char *msg, const struct flow_key *key) -{ - const uint8_t *p = (const uint8_t *)key; - unsigned i; - - printf("%s key:0x", msg); - for (i = 0; i < sizeof(struct flow_key); i++) - printf("%02X", p[i]); - printf("\n"); -} - -static double get_time_diff(struct timeval *start, struct timeval *end) -{ - int sec = end->tv_sec - start->tv_sec; - int usec = end->tv_usec - start->tv_usec; - - if (usec < 0) { - sec--; - usec += 1000000; - } - double diff = sec + (double)usec / 1000000; - - return diff; -} - -/** Create IPv4 address */ -#define IPv4(a, b, c, d) ((uint32_t)(((a) & 0xff) << 24) | \ - (((b) & 0xff) << 16) | \ - (((c) & 0xff) << 8) | \ - ((d) & 0xff)) - -/* Keys used by unit test functions */ -static struct flow_key keys[5] = { { - .ip_src = IPv4(0x03, 0x02, 0x01, 0x00), - .ip_dst = IPv4(0x07, 0x06, 0x05, 0x04), - .port_src = 0x0908, - .port_dst = 0x0b0a, - .proto = 0x0c, -}, { - .ip_src = IPv4(0x13, 0x12, 0x11, 0x10), - .ip_dst = IPv4(0x17, 0x16, 0x15, 0x14), - .port_src = 0x1918, - .port_dst = 0x1b1a, - .proto = 0x1c, -}, { - .ip_src = IPv4(0x23, 0x22, 0x21, 0x20), - .ip_dst = IPv4(0x27, 0x26, 0x25, 0x24), - .port_src = 0x2928, - .port_dst = 0x2b2a, - .proto = 0x2c, -}, { - .ip_src = IPv4(0x33, 0x32, 0x31, 0x30), - .ip_dst = IPv4(0x37, 0x36, 0x35, 0x34), - .port_src = 0x3938, - .port_dst = 0x3b3a, - .proto = 0x3c, -}, { - .ip_src = IPv4(0x43, 0x42, 0x41, 0x40), - .ip_dst = IPv4(0x47, 0x46, 0x45, 0x44), - .port_src = 0x4948, - .port_dst = 0x4b4a, - .proto = 0x4c, -} }; - -/* - * Basic sequence of operations for a single key: - * - put - * - get (hit) - * - remove - * - get (miss) - */ -static int test_put_remove(void) -{ - odph_table_t table; - odph_table_ops_t *ops; - - ops = &odph_cuckoo_table_ops; - - /* test with standard put/get/remove functions */ - int ret; - - table = ops->f_create("put_remove", 10, sizeof(struct flow_key), 0); - if (table == NULL) { - printf("cuckoo hash table creation failed\n"); - return -1; - } - - ret = odph_cuckoo_table_put_value(table, &keys[0], NULL); - print_key_info("Add", &keys[0]); - if (ret < 0) { - printf("failed to add key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_get_value(table, &keys[0], NULL, 0); - print_key_info("Lkp", &keys[0]); - if (ret < 0) { - printf("failed to find key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_remove_value(table, &keys[0]); - print_key_info("Del", &keys[0]); - if (ret < 0) { - printf("failed to delete key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_get_value(table, &keys[0], NULL, 0); - print_key_info("Lkp", &keys[0]); - if (ret >= 0) { - printf("error: found key after deleting!\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - odph_cuckoo_table_destroy(table); - return 0; -} - -/* - * Sequence of operations for a single key: - * key type : struct flow_key - * value type: uint8_t - * - remove: miss - * - put - * - get: hit - * - put: update - * - get: hit (updated data) - * - remove: hit - * - remove: miss - */ -static int test_put_update_remove(void) -{ - odph_table_t table; - int ret; - uint8_t val1 = 1, val2 = 2, val = 0; - - table = odph_cuckoo_table_create( - "put_update_remove", - 10, sizeof(struct flow_key), sizeof(uint8_t)); - if (table == NULL) { - printf("failed to create table\n"); - return -1; - } - - ret = odph_cuckoo_table_remove_value(table, &keys[0]); - print_key_info("Del", &keys[0]); - if (ret >= 0) { - printf("error: found non-existent key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_put_value(table, &keys[0], &val1); - print_key_info("Add", &keys[0]); - if (ret < 0) { - printf("failed to add key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_get_value( - table, &keys[0], &val, sizeof(uint8_t)); - print_key_info("Lkp", &keys[0]); - if (ret < 0) { - printf("failed to find key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_put_value(table, &keys[0], &val2); - if (ret < 0) { - printf("failed to re-add key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_get_value( - table, &keys[0], &val, sizeof(uint8_t)); - print_key_info("Lkp", &keys[0]); - if (ret < 0) { - printf("failed to find key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_remove_value(table, &keys[0]); - print_key_info("Del", &keys[0]); - if (ret < 0) { - printf("failed to delete key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - ret = odph_cuckoo_table_remove_value(table, &keys[0]); - print_key_info("Del", &keys[0]); - if (ret >= 0) { - printf("error: deleted already deleted key\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - odph_cuckoo_table_destroy(table); - return 0; -} - -/* - * Sequence of operations for find existing hash table - * - * - create table - * - find existing table: hit - * - find non-existing table: miss - * - */ -static int test_table_lookup(void) -{ - odph_table_t table, result; - - /* Create cuckoo hash table. */ - table = odph_cuckoo_table_create("table_lookup", 10, 4, 0); - if (table == NULL) { - printf("failed to create table\n"); - return -1; - } - - /* Try to find existing hash table */ - result = odph_cuckoo_table_lookup("table_lookup"); - if (result != table) { - printf("error: could not find existing table\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - /* Try to find non-existing hash table */ - result = odph_cuckoo_table_lookup("non_existing"); - if (result != NULL) { - printf("error: found table that shouldn't exist.\n"); - odph_cuckoo_table_destroy(table); - return -1; - } - - /* Cleanup. */ - odph_cuckoo_table_destroy(table); - return 0; -} - -/* - * Sequence of operations for 5 keys - * - put keys - * - get keys: hit - * - remove keys : hit - * - get keys: miss - */ -static int test_five_keys(void) -{ - odph_table_t table; - unsigned i; - int ret; - - table = odph_cuckoo_table_create( - "five_keys", 10, sizeof(struct flow_key), 0); - if (table == NULL) { - printf("failed to create table\n"); - return -1; - } - - /* put */ - for (i = 0; i < 5; i++) { - ret = odph_cuckoo_table_put_value(table, &keys[i], NULL); - print_key_info("Add", &keys[i]); - if (ret < 0) { - printf("failed to add key %d\n", i); - odph_cuckoo_table_destroy(table); - return -1; - } - } - - /* get */ - for (i = 0; i < 5; i++) { - ret = odph_cuckoo_table_get_value(table, &keys[i], NULL, 0); - print_key_info("Lkp", &keys[i]); - if (ret < 0) { - printf("failed to find key %d\n", i); - odph_cuckoo_table_destroy(table); - return -1; - } - } - - /* remove */ - for (i = 0; i < 5; i++) { - ret = odph_cuckoo_table_remove_value(table, &keys[i]); - print_key_info("Del", &keys[i]); - if (ret < 0) { - printf("failed to delete key %d\n", i); - odph_cuckoo_table_destroy(table); - return -1; - } - } - - /* get */ - for (i = 0; i < 5; i++) { - ret = odph_cuckoo_table_get_value(table, &keys[i], NULL, 0); - print_key_info("Lkp", &keys[i]); - if (ret >= 0) { - printf("found non-existing key %d\n", i); - odph_cuckoo_table_destroy(table); - return -1; - } - } - - odph_cuckoo_table_destroy(table); - return 0; -} - -#define BUCKET_ENTRIES 4 -#define HASH_ENTRIES_MAX 1048576 -/* - * Do tests for cuchoo table creation with bad parameters. - */ -static int test_creation_with_bad_parameters(void) -{ - odph_table_t table; - - table = odph_cuckoo_table_create( - "bad_param_0", HASH_ENTRIES_MAX + 1, 4, 0); - if (table != NULL) { - odph_cuckoo_table_destroy(table); - printf("Impossible creating table successfully with entries in parameter exceeded\n"); - return -1; - } - - table = odph_cuckoo_table_create( - "bad_param_1", BUCKET_ENTRIES - 1, 4, 0); - if (table != NULL) { - odph_cuckoo_table_destroy(table); - printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n"); - return -1; - } - - table = odph_cuckoo_table_create("bad_param_2", 10, 0, 0); - if (table != NULL) { - odph_cuckoo_table_destroy(table); - printf("Impossible creating hash successfully if key_len in parameter is zero\n"); - return -1; - } - - printf("# Test successful. No more errors expected\n"); - - return 0; -} - -#define PERFORMANCE_CAPACITY 4000 - -/* - * Test the performance of cuckoo hash table. - * table capacity : 1,000,000 - * key size : 4 bytes - * value size : 0 - * Insert at most number random keys into the table. If one - * insertion is failed, the rest insertions will be cancelled. - * The table utilization of the report will show actual number - * of items inserted. - * Then search all inserted items. - */ -static int test_performance(int number) -{ - odph_table_t table; - - /* generate random keys */ - uint8_t *key_space = NULL; - const void **key_ptr = NULL; - unsigned key_len = 4, j; - unsigned elem_num = (number > PERFORMANCE_CAPACITY) ? - PERFORMANCE_CAPACITY : number; - unsigned key_num = key_len * elem_num; - - key_space = (uint8_t *)malloc(key_num); - if (key_space == NULL) - return -ENOENT; - - key_ptr = (const void **)malloc(sizeof(void *) * elem_num); - if (key_ptr == NULL) { - free(key_space); - return -ENOENT; - } - - for (j = 0; j < key_num; j++) { - key_space[j] = rand() % 255; - if (j % key_len == 0) - key_ptr[j / key_len] = &key_space[j]; - } - - unsigned num; - int ret = 0; - struct timeval start, end; - double add_time = 0; - - fflush(stdout); - table = odph_cuckoo_table_create( - "performance_test", PERFORMANCE_CAPACITY, key_len, 0); - if (table == NULL) { - printf("cuckoo table creation failed\n"); - free(key_ptr); - free(key_space); - return -ENOENT; - } - - /* insert (put) */ - gettimeofday(&start, 0); - for (j = 0; j < elem_num; j++) { - ret = odph_cuckoo_table_put_value( - table, &key_space[j * key_len], NULL); - if (ret < 0) - break; - } - gettimeofday(&end, 0); - num = j; - add_time = get_time_diff(&start, &end); - printf( - "add %u/%u (%.2f) items, time = %.9lfs\n", - num, PERFORMANCE_CAPACITY, - (double)num / PERFORMANCE_CAPACITY, add_time); - - /* search (get) */ - gettimeofday(&start, 0); - for (j = 0; j < num; j++) { - ret = odph_cuckoo_table_get_value( - table, &key_space[j * key_len], NULL, 0); - - if (ret < 0) - printf("lookup error\n"); - } - gettimeofday(&end, 0); - printf( - "lookup %u items, time = %.9lfs\n", - num, get_time_diff(&start, &end)); - - odph_cuckoo_table_destroy(table); - free(key_ptr); - free(key_space); - return ret; -} - -/* - * Do all unit and performance tests. - */ -static int -test_cuckoo_hash_table(void) -{ - if (test_put_remove() < 0) - return -1; - if (test_table_lookup() < 0) - return -1; - if (test_put_update_remove() < 0) - return -1; - if (test_five_keys() < 0) - return -1; - if (test_creation_with_bad_parameters() < 0) - return -1; - if (test_performance(950000) < 0) - return -1; - - return 0; -} - -int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) -{ - odp_instance_t instance; - int ret = 0; - - ret = odp_init_global(&instance, NULL, NULL); - if (ret != 0) { - fprintf(stderr, "Error: ODP global init failed.\n"); - exit(EXIT_FAILURE); - } - - ret = odp_init_local(instance, ODP_THREAD_WORKER); - if (ret != 0) { - fprintf(stderr, "Error: ODP local init failed.\n"); - exit(EXIT_FAILURE); - } - - srand(time(0)); - ret = test_cuckoo_hash_table(); - - if (ret < 0) - printf("cuckoo hash table test fail!!\n"); - else - printf("All Tests pass!!\n"); - - if (odp_term_local()) { - fprintf(stderr, "Error: ODP local term failed.\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_global(instance)) { - fprintf(stderr, "Error: ODP global term failed.\n"); - exit(EXIT_FAILURE); - } - - return ret; -} diff --git a/helper/test/iplookuptable.c b/helper/test/iplookuptable.c deleted file mode 100644 index 669d334dd..000000000 --- a/helper/test/iplookuptable.c +++ /dev/null @@ -1,170 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2016-2018 Linaro Limited - */ - -#include <stdio.h> -#include <stdint.h> -#include <string.h> -#include <stdlib.h> -#include <errno.h> - -#include <odp_api.h> -#include <odp/helper/odph_api.h> - -static void print_prefix_info( - const char *msg, uint32_t ip, uint8_t cidr) -{ - int i = 0; - uint8_t *ptr = (uint8_t *)(&ip); - - printf("%s IP prefix: ", msg); - for (i = 3; i >= 0; i--) { - if (i != 3) - printf("."); - printf("%d", ptr[i]); - } - printf("/%d\n", cidr); -} - -/* - * Basic sequence of operations for a single key: - * - put short prefix - * - put long prefix - * - get (hit long prefix) - * - remove long prefix - * - get (hit short prefix) - */ -static int test_ip_lookup_table(void) -{ - odph_iplookup_prefix_t prefix1, prefix2; - odph_table_t table; - int ret; - uint64_t value1 = 1, value2 = 2, result = 0; - uint32_t lkp_ip = 0; - - table = odph_iplookup_table_create( - "prefix_test", 0, 0, sizeof(uint32_t)); - if (table == NULL) { - printf("IP prefix lookup table creation failed\n"); - return -1; - } - - ret = odph_ipv4_addr_parse(&prefix1.ip, "192.168.0.0"); - if (ret < 0) { - printf("Failed to get IP addr from str\n"); - odph_iplookup_table_destroy(table); - return -1; - } - prefix1.cidr = 11; - - ret = odph_ipv4_addr_parse(&prefix2.ip, "192.168.0.0"); - if (ret < 0) { - printf("Failed to get IP addr from str\n"); - odph_iplookup_table_destroy(table); - return -1; - } - prefix2.cidr = 24; - - ret = odph_ipv4_addr_parse(&lkp_ip, "192.168.0.1"); - if (ret < 0) { - printf("Failed to get IP addr from str\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - /* test with standard put/get/remove functions */ - ret = odph_iplookup_table_put_value(table, &prefix1, &value1); - print_prefix_info("Add", prefix1.ip, prefix1.cidr); - if (ret < 0) { - printf("Failed to add ip prefix\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - ret = odph_iplookup_table_get_value(table, &lkp_ip, &result, 0); - print_prefix_info("Lkp", lkp_ip, 32); - if (ret < 0 || result != 1) { - printf("Failed to find longest prefix\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - /* add a longer prefix */ - ret = odph_iplookup_table_put_value(table, &prefix2, &value2); - print_prefix_info("Add", prefix2.ip, prefix2.cidr); - if (ret < 0) { - printf("Failed to add ip prefix\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - ret = odph_iplookup_table_get_value(table, &lkp_ip, &result, 0); - print_prefix_info("Lkp", lkp_ip, 32); - if (ret < 0 || result != 2) { - printf("Failed to find longest prefix\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - ret = odph_iplookup_table_remove_value(table, &prefix2); - print_prefix_info("Del", prefix2.ip, prefix2.cidr); - if (ret < 0) { - printf("Failed to delete ip prefix\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - ret = odph_iplookup_table_get_value(table, &lkp_ip, &result, 0); - print_prefix_info("Lkp", lkp_ip, 32); - if (ret < 0 || result != 1) { - printf("Error: found result ater deleting\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - ret = odph_iplookup_table_remove_value(table, &prefix1); - print_prefix_info("Del", prefix1.ip, prefix1.cidr); - if (ret < 0) { - printf("Failed to delete prefix\n"); - odph_iplookup_table_destroy(table); - return -1; - } - - odph_iplookup_table_destroy(table); - return 0; -} - -int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) -{ - odp_instance_t instance; - int ret = 0; - - ret = odp_init_global(&instance, NULL, NULL); - if (ret != 0) { - fprintf(stderr, "Error: ODP global init failed.\n"); - exit(EXIT_FAILURE); - } - - ret = odp_init_local(instance, ODP_THREAD_WORKER); - if (ret != 0) { - fprintf(stderr, "Error: ODP local init failed.\n"); - exit(EXIT_FAILURE); - } - - if (test_ip_lookup_table() < 0) - printf("Test failed\n"); - else - printf("All tests passed\n"); - - if (odp_term_local()) { - fprintf(stderr, "Error: ODP local term failed.\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_global(instance)) { - fprintf(stderr, "Error: ODP global term failed.\n"); - exit(EXIT_FAILURE); - } - - return ret; -} diff --git a/helper/test/odpthreads.c b/helper/test/odpthreads.c index bf623569b..158b1d3c3 100644 --- a/helper/test/odpthreads.c +++ b/helper/test/odpthreads.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright (c) 2016-2018 Linaro Limited - * Copyright (c) 2021 Nokia + * Copyright (c) 2021-2024 Nokia */ /* @@ -73,7 +73,6 @@ int main(int argc, char *argv[]) odp_init_t init_param; int num_workers; int cpu, affinity; - int ret; char cpumaskstr[ODP_CPUMASK_STR_SIZE]; struct rlimit rlimit; pthread_attr_t attr; @@ -161,11 +160,25 @@ int main(int argc, char *argv[]) thr_param.arg = NULL; thr_param.thr_type = ODP_THREAD_WORKER; - odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers); + if (odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers) != num_workers) { + ODPH_ERR("Error: failed to create worker threads.\n"); + exit(EXIT_FAILURE); + } + + odph_thread_join_result_t res[num_workers]; - ret = odph_thread_join(thread_tbl, num_workers); - if (ret < 0) + if (odph_thread_join_result(thread_tbl, res, num_workers) != num_workers) { + ODPH_ERR("Error: failed to join worker threads.\n"); exit(EXIT_FAILURE); + } + + for (int i = 0; i < num_workers; i++) { + if (res[i].is_sig || res[i].ret != 0) { + ODPH_ERR("Error: worker thread failure%s: %d.\n", res[i].is_sig ? + " (signaled)" : "", res[i].ret); + exit(EXIT_FAILURE); + } + } /* Test threads with non-default stack size and sync timeout. */ @@ -195,11 +208,23 @@ int main(int argc, char *argv[]) printf("use sync timeout: %" PRIu64 "\n", thr_common.sync_timeout); printf("\n"); - if (odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers) != num_workers) + if (odph_thread_create(thread_tbl, &thr_common, &thr_param, num_workers) != num_workers) { + ODPH_ERR("Error: failed to create worker threads.\n"); exit(EXIT_FAILURE); + } - if (odph_thread_join(thread_tbl, num_workers) != num_workers) + if (odph_thread_join_result(thread_tbl, res, num_workers) != num_workers) { + ODPH_ERR("Error: failed to join worker threads.\n"); exit(EXIT_FAILURE); + } + + for (int i = 0; i < num_workers; i++) { + if (res[i].is_sig || res[i].ret != 0) { + ODPH_ERR("Error: worker thread failure%s: %d.\n", res[i].is_sig ? + " (signaled)" : "", res[i].ret); + exit(EXIT_FAILURE); + } + } return 0; } diff --git a/helper/test/stress.c b/helper/test/stress.c new file mode 100644 index 000000000..e66a0447d --- /dev/null +++ b/helper/test/stress.c @@ -0,0 +1,118 @@ +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright(C) 2024 Nokia + */ + +#include <odp_api.h> +#include <odp/helper/odph_api.h> + +#include <stdio.h> +#include <stdlib.h> + +static int test_pow2(void) +{ + uint32_t in[] = {0, 1, 2, 3, 4, 0xff, 0x100, 0xfffe, 0xffff, 0x10000}; + uint32_t out[] = {0, 1, 4, 9, 16, 0xfe01, 0x10000, 0xfffc0004, 0xfffe0001, 0xffffffff}; + uint32_t num = ODPH_ARRAY_SIZE(out); + int ret = 0; + + printf(" odph_stress_pow2_u32() ... "); + + for (uint32_t i = 0; i < num; i++) + if (odph_stress_pow2_u32(in[i]) != out[i]) + ret++; + + if (ret) + printf("%i tests failed\n", ret); + else + printf("passed\n"); + + return ret; +} + +static int test_log2(void) +{ + uint32_t in[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 15, 16, 255, 256, 257, 512, 513, 1023, 1024}; + uint32_t out[] = {0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 4, 7, 8, 8, 9, 9, 9, 10}; + uint32_t num = ODPH_ARRAY_SIZE(out); + int ret = 0; + + printf(" odph_stress_log2_u32() ... "); + + for (uint32_t i = 0; i < num; i++) + if (odph_stress_log2_u32(in[i]) != out[i]) + ret++; + + if (ret) + printf("%i tests failed\n", ret); + else + printf("passed\n"); + + return ret; +} + +static int test_sqrt_u32(void) +{ + uint32_t in[] = {0, 1, 2, 3, 4, 7, 8, 9, 100, 1500, 2900, 4096, 6213, 8191, 16384, 100000, + 1000000, 4036587, 0x42c1d80, 0x8000000, 0x1fffffff, 0x2faf0800, + 0xffffffff}; + uint32_t out[] = {0, 1, 1, 1, 2, 2, 2, 3, 10, 38, 53, 64, 78, 90, 128, 316, 1000, 2009, + 8366, 11585, 23170, 28284, 65535}; + uint32_t num = ODPH_ARRAY_SIZE(out); + int ret = 0; + + printf(" odph_stress_sqrt_u32() ... "); + + for (uint32_t i = 0; i < num; i++) + if (odph_stress_sqrt_u32(in[i]) != out[i]) + ret++; + + if (ret) + printf("%i tests failed\n", ret); + else + printf("passed\n"); + + return ret; +} + +/* + * 32-bit floating point can represent integers between 0 and 16777216 exactly, and integers + * between 16777216 and 33554432 in multiples of 2, etc. + */ +static int test_sqrt_f32(void) +{ + float in[] = {0, 1, 2, 3, 4, 7, 8, 9, 100, 1500, 2900, 4096, 6213, 8191, 16384, 100000, + 1000000, 4036587, 16777216, 33554432, 134217728, 3000000000, 4294967296}; + float out[] = {0, 1, 1, 1, 2, 2, 2, 3, 10, 38, 53, 64, 78, 90, 128, 316, 1000, 2009, 4096, + 5792, 11585, 54772, 65536}; + uint32_t num = ODPH_ARRAY_SIZE(out); + int ret = 0; + + printf(" odph_stress_sqrt_f32() ... "); + + for (uint32_t i = 0; i < num; i++) + if (odph_stress_sqrt_f32(in[i]) != out[i]) + ret++; + + if (ret) + printf("%i tests failed\n", ret); + else + printf("passed\n"); + + return ret; +} + +int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) +{ + int ret = 0; + + printf("Running helper algorithm tests:\n"); + + ret += test_pow2(); + ret += test_log2(); + ret += test_sqrt_u32(); + ret += test_sqrt_f32(); + + printf("\n"); + + return ret ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/helper/test/table.c b/helper/test/table.c deleted file mode 100644 index fb17e8a37..000000000 --- a/helper/test/table.c +++ /dev/null @@ -1,130 +0,0 @@ -/* SPDX-License-Identifier: BSD-3-Clause - * Copyright (c) 2015-2018 Linaro Limited - */ - -#include <odp_api.h> -#include <odp/helper/odph_api.h> - -/** - * Address Resolution Protocol (ARP) - * Description: Once a route has been identified for an IP packet (so the - * output interface and the IP address of the next hop station are known), - * the MAC address of the next hop station is needed in order to send this - * packet onto the next leg of the journey towards its destination - * (as identified by its destination IP address). The MAC address of the next - * hop station becomes the destination MAC address of the outgoing - * Ethernet frame. - * Hash table name: ARP table - * Number of keys: Thousands - * Key format: The pair of (Output interface, Next Hop IP address), - * which is typically 5 bytes for IPv4 and 17 bytes for IPv6. - * value (data): MAC address of the next hop station (6 bytes). - */ - -int main(int argc ODP_UNUSED, char *argv[] ODP_UNUSED) -{ - odp_instance_t instance; - int ret = 0; - odph_table_t table; - odph_table_t tmp_tbl; - odph_table_ops_t *test_ops; - char tmp[32]; - char ip_addr1[] = "12345678"; - char ip_addr2[] = "11223344"; - char ip_addr3[] = "55667788"; - char mac_addr1[] = "0A1122334401"; - char mac_addr2[] = "0A1122334402"; - char mac_addr3[] = "0B4433221101"; - char mac_addr4[] = "0B4433221102"; - - ret = odp_init_global(&instance, NULL, NULL); - if (ret != 0) { - ODPH_ERR("odp_shm_init_global fail\n"); - exit(EXIT_FAILURE); - } - ret = odp_init_local(instance, ODP_THREAD_WORKER); - if (ret != 0) { - ODPH_ERR("odp_shm_init_local fail\n"); - exit(EXIT_FAILURE); - } - - printf("test hash table:\n"); - test_ops = &odph_hash_table_ops; - - table = test_ops->f_create("test", 2, 4, 16); - if (table == NULL) { - printf("table create fail\n"); - return -1; - } - ret += test_ops->f_put(table, &ip_addr1, mac_addr1); - - ret += test_ops->f_put(table, &ip_addr2, mac_addr2); - - ret += test_ops->f_put(table, &ip_addr3, mac_addr3); - - if (ret != 0) { - printf("put value fail\n"); - return -1; - } - - ret = test_ops->f_get(table, &ip_addr1, &tmp, 32); - if (ret != 0) { - printf("get value fail\n"); - return -1; - } - printf("\t1 get '123' tmp = %s,\n", tmp); - - ret = test_ops->f_put(table, &ip_addr1, mac_addr4); - if (ret != 0) { - printf("repeat put value fail\n"); - return -1; - } - - ret = test_ops->f_get(table, &ip_addr1, &tmp, 32); - if (ret != 0 || strcmp(tmp, mac_addr4) != 0) { - printf("get value fail\n"); - return -1; - } - - printf("\t2 repeat get '123' value = %s\n", tmp); - - ret = test_ops->f_remove(table, &ip_addr1); - if (ret != 0) { - printf("remove value fail\n"); - return -1; - } - ret = test_ops->f_get(table, &ip_addr1, tmp, 32); - if (ret == 0) { - printf("remove value fail actually\n"); - return -1; - } - printf("\t3 remove success!\n"); - - tmp_tbl = test_ops->f_lookup("test"); - if (tmp_tbl != table) { - printf("lookup table fail!!!\n"); - return -1; - } - printf("\t4 lookup table success!\n"); - - ret = test_ops->f_des(table); - if (ret != 0) { - printf("destroy table fail!!!\n"); - exit(EXIT_FAILURE); - } - printf("\t5 destroy table success!\n"); - - printf("all test finished success!!\n"); - - if (odp_term_local()) { - ODPH_ERR("Error: ODP local term failed.\n"); - exit(EXIT_FAILURE); - } - - if (odp_term_global(instance)) { - ODPH_ERR("Error: ODP global term failed.\n"); - exit(EXIT_FAILURE); - } - - return 0; -} diff --git a/helper/threads.c b/helper/threads.c index 72003d0f4..5063725b2 100644 --- a/helper/threads.c +++ b/helper/threads.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: BSD-3-Clause * Copyright (c) 2013-2018 Linaro Limited - * Copyright (c) 2019-2022 Nokia + * Copyright (c) 2019-2024 Nokia */ #ifndef _GNU_SOURCE @@ -21,8 +21,8 @@ #include <inttypes.h> #include <odp_api.h> +#include <odp/helper/debug.h> #include <odp/helper/threads.h> -#include <odp/helper/odph_debug.h> #define FAILED_CPU -1 @@ -144,10 +144,10 @@ static int create_process(odph_thread_t *thread, int cpu, uint64_t stack_size) /* * Wait single process to exit */ -static int wait_process(odph_thread_t *thread) +static int wait_process(odph_thread_t *thread, odph_thread_join_result_t *res) { pid_t pid; - int status = 0; + int status = 0, estatus; pid = waitpid(thread->proc.pid, &status, 0); @@ -157,19 +157,27 @@ static int wait_process(odph_thread_t *thread) } /* Examine the child process' termination status */ - if (WIFEXITED(status) && - WEXITSTATUS(status) != EXIT_SUCCESS) { - ODPH_ERR("Child exit status:%d (pid:%d)\n", - WEXITSTATUS(status), (int)pid); - return -1; - } - - if (WIFSIGNALED(status)) { + if (WIFEXITED(status)) { + estatus = WEXITSTATUS(status); + + if (res != NULL) { + res->is_sig = false; + res->ret = estatus; + } else if (estatus != EXIT_SUCCESS) { + ODPH_ERR("Child exit status:%d (pid:%d)\n", estatus, (int)pid); + return -1; + } + } else { int signo = WTERMSIG(status); - ODPH_ERR("Child term signo:%d - %s (pid:%d)\n", - signo, strsignal(signo), (int)pid); - return -1; + if (res != NULL) { + res->is_sig = true; + res->ret = signo; + } else { + ODPH_ERR("Child term signo:%d - %s (pid:%d)\n", signo, strsignal(signo), + (int)pid); + return -1; + } } return 0; @@ -229,7 +237,7 @@ static int create_pthread(odph_thread_t *thread, int cpu, uint64_t stack_size) /* * Wait single pthread to exit */ -static int wait_pthread(odph_thread_t *thread) +static int wait_pthread(odph_thread_t *thread, odph_thread_join_result_t *res) { int ret; void *thread_ret = NULL; @@ -243,9 +251,11 @@ static int wait_pthread(odph_thread_t *thread) return -1; } - if (thread_ret) { - ODPH_ERR("Bad exit status cpu #%i %p\n", - thread->cpu, thread_ret); + if (res != NULL) { + res->is_sig = false; + res->ret = (int)(intptr_t)thread_ret; + } else if (thread_ret) { + ODPH_ERR("Bad exit status cpu #%i %p\n", thread->cpu, thread_ret); return -1; } @@ -254,7 +264,9 @@ static int wait_pthread(odph_thread_t *thread) if (ret) { ODPH_ERR("pthread_attr_destroy failed (%i) from cpu #%i\n", ret, thread->cpu); - return -1; + + if (res == NULL) + return -1; } return 0; @@ -380,7 +392,7 @@ int odph_thread_create(odph_thread_t thread[], return i; } -int odph_thread_join(odph_thread_t thread[], int num) +static int join_threads(odph_thread_t thread[], odph_thread_join_result_t res[], int num) { odph_thread_start_args_t *start_args; int i; @@ -389,15 +401,15 @@ int odph_thread_join(odph_thread_t thread[], int num) start_args = &thread[i].start_args; if (start_args->status != STARTED) { - ODPH_DBG("Thread (i:%i) not started.\n", i); + ODPH_ERR("Thread (i:%i) not started.\n", i); break; } if (thread[i].start_args.mem_model == ODP_MEM_MODEL_THREAD) { - if (wait_pthread(&thread[i])) + if (wait_pthread(&thread[i], res != NULL ? &res[i] : NULL)) break; } else { - if (wait_process(&thread[i])) + if (wait_process(&thread[i], res != NULL ? &res[i] : NULL)) break; } @@ -407,6 +419,31 @@ int odph_thread_join(odph_thread_t thread[], int num) return i; } +int odph_thread_join(odph_thread_t thread[], int num) +{ + if (thread == NULL) { + ODPH_ERR("Bad thread table pointer\n"); + return -1; + } + + return join_threads(thread, NULL, num); +} + +int odph_thread_join_result(odph_thread_t thread[], odph_thread_join_result_t res[], int num) +{ + if (thread == NULL) { + ODPH_ERR("Bad thread table pointer\n"); + return -1; + } + + if (res == NULL) { + ODPH_ERR("Bad result table pointer\n"); + return -1; + } + + return join_threads(thread, res, num); +} + /* man gettid() notes: * Glibc does not provide a wrapper for this system call; */ |