14418919fSjohnjiang /* SPDX-License-Identifier: BSD-3-Clause
24418919fSjohnjiang * Copyright(c) 2010-2015 Intel Corporation
34418919fSjohnjiang */
44418919fSjohnjiang
54418919fSjohnjiang #include <stdio.h>
64418919fSjohnjiang #include <stdint.h>
74418919fSjohnjiang #include <string.h>
84418919fSjohnjiang #include <stdlib.h>
94418919fSjohnjiang #include <stdarg.h>
104418919fSjohnjiang #include <errno.h>
114418919fSjohnjiang #include <sys/queue.h>
124418919fSjohnjiang
134418919fSjohnjiang #include <rte_common.h>
144418919fSjohnjiang #include <rte_malloc.h>
154418919fSjohnjiang #include <rte_cycles.h>
164418919fSjohnjiang #include <rte_random.h>
174418919fSjohnjiang #include <rte_memory.h>
184418919fSjohnjiang #include <rte_eal.h>
194418919fSjohnjiang #include <rte_ip.h>
204418919fSjohnjiang #include <rte_string_fns.h>
214418919fSjohnjiang
224418919fSjohnjiang #include "test.h"
234418919fSjohnjiang
244418919fSjohnjiang #include <rte_hash.h>
254418919fSjohnjiang #include <rte_fbk_hash.h>
264418919fSjohnjiang #include <rte_jhash.h>
274418919fSjohnjiang #include <rte_hash_crc.h>
284418919fSjohnjiang
294418919fSjohnjiang /*******************************************************************************
304418919fSjohnjiang * Hash function performance test configuration section. Each performance test
314418919fSjohnjiang * will be performed HASHTEST_ITERATIONS times.
324418919fSjohnjiang *
334418919fSjohnjiang * The five arrays below control what tests are performed. Every combination
344418919fSjohnjiang * from the array entries is tested.
354418919fSjohnjiang */
364418919fSjohnjiang static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
374418919fSjohnjiang static uint32_t hashtest_initvals[] = {0};
384418919fSjohnjiang static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64};
394418919fSjohnjiang #define MAX_KEYSIZE 64
404418919fSjohnjiang /******************************************************************************/
414418919fSjohnjiang #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
424418919fSjohnjiang
434418919fSjohnjiang /*
444418919fSjohnjiang * Check condition and return an error if true. Assumes that "handle" is the
454418919fSjohnjiang * name of the hash structure pointer to be freed.
464418919fSjohnjiang */
474418919fSjohnjiang #define RETURN_IF_ERROR(cond, str, ...) do { \
484418919fSjohnjiang if (cond) { \
494418919fSjohnjiang printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
504418919fSjohnjiang if (handle) rte_hash_free(handle); \
514418919fSjohnjiang return -1; \
524418919fSjohnjiang } \
534418919fSjohnjiang } while(0)
544418919fSjohnjiang
554418919fSjohnjiang #define RETURN_IF_ERROR_FBK(cond, str, ...) do { \
564418919fSjohnjiang if (cond) { \
574418919fSjohnjiang printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
584418919fSjohnjiang if (handle) rte_fbk_hash_free(handle); \
594418919fSjohnjiang return -1; \
604418919fSjohnjiang } \
614418919fSjohnjiang } while(0)
624418919fSjohnjiang
63*2d9fd380Sjfb8856606 #define RETURN_IF_ERROR_RCU_QSBR(cond, str, ...) do { \
64*2d9fd380Sjfb8856606 if (cond) { \
65*2d9fd380Sjfb8856606 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
66*2d9fd380Sjfb8856606 if (rcu_cfg.mode == RTE_HASH_QSBR_MODE_SYNC) { \
67*2d9fd380Sjfb8856606 writer_done = 1; \
68*2d9fd380Sjfb8856606 /* Wait until reader exited. */ \
69*2d9fd380Sjfb8856606 rte_eal_mp_wait_lcore(); \
70*2d9fd380Sjfb8856606 } \
71*2d9fd380Sjfb8856606 rte_hash_free(g_handle); \
72*2d9fd380Sjfb8856606 rte_free(g_qsv); \
73*2d9fd380Sjfb8856606 return -1; \
74*2d9fd380Sjfb8856606 } \
75*2d9fd380Sjfb8856606 } while (0)
76*2d9fd380Sjfb8856606
774418919fSjohnjiang /* 5-tuple key type */
784418919fSjohnjiang struct flow_key {
794418919fSjohnjiang uint32_t ip_src;
804418919fSjohnjiang uint32_t ip_dst;
814418919fSjohnjiang uint16_t port_src;
824418919fSjohnjiang uint16_t port_dst;
834418919fSjohnjiang uint8_t proto;
84*2d9fd380Sjfb8856606 } __rte_packed;
854418919fSjohnjiang
864418919fSjohnjiang /*
874418919fSjohnjiang * Hash function that always returns the same value, to easily test what
884418919fSjohnjiang * happens when a bucket is full.
894418919fSjohnjiang */
pseudo_hash(__rte_unused const void * keys,__rte_unused uint32_t key_len,__rte_unused uint32_t init_val)90*2d9fd380Sjfb8856606 static uint32_t pseudo_hash(__rte_unused const void *keys,
91*2d9fd380Sjfb8856606 __rte_unused uint32_t key_len,
92*2d9fd380Sjfb8856606 __rte_unused uint32_t init_val)
934418919fSjohnjiang {
944418919fSjohnjiang return 3;
954418919fSjohnjiang }
964418919fSjohnjiang
97*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(hash_logtype_test, test.hash, INFO);
984418919fSjohnjiang
994418919fSjohnjiang /*
1004418919fSjohnjiang * Print out result of unit test hash operation.
1014418919fSjohnjiang */
print_key_info(const char * msg,const struct flow_key * key,int32_t pos)1024418919fSjohnjiang static void print_key_info(const char *msg, const struct flow_key *key,
1034418919fSjohnjiang int32_t pos)
1044418919fSjohnjiang {
1054418919fSjohnjiang const uint8_t *p = (const uint8_t *)key;
1064418919fSjohnjiang unsigned int i;
1074418919fSjohnjiang
1084418919fSjohnjiang rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%s key:0x", msg);
1094418919fSjohnjiang for (i = 0; i < sizeof(struct flow_key); i++)
1104418919fSjohnjiang rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%02X", p[i]);
1114418919fSjohnjiang rte_log(RTE_LOG_DEBUG, hash_logtype_test, " @ pos %d\n", pos);
1124418919fSjohnjiang }
1134418919fSjohnjiang
1144418919fSjohnjiang /* Keys used by unit test functions */
1154418919fSjohnjiang static struct flow_key keys[5] = { {
1164418919fSjohnjiang .ip_src = RTE_IPV4(0x03, 0x02, 0x01, 0x00),
1174418919fSjohnjiang .ip_dst = RTE_IPV4(0x07, 0x06, 0x05, 0x04),
1184418919fSjohnjiang .port_src = 0x0908,
1194418919fSjohnjiang .port_dst = 0x0b0a,
1204418919fSjohnjiang .proto = 0x0c,
1214418919fSjohnjiang }, {
1224418919fSjohnjiang .ip_src = RTE_IPV4(0x13, 0x12, 0x11, 0x10),
1234418919fSjohnjiang .ip_dst = RTE_IPV4(0x17, 0x16, 0x15, 0x14),
1244418919fSjohnjiang .port_src = 0x1918,
1254418919fSjohnjiang .port_dst = 0x1b1a,
1264418919fSjohnjiang .proto = 0x1c,
1274418919fSjohnjiang }, {
1284418919fSjohnjiang .ip_src = RTE_IPV4(0x23, 0x22, 0x21, 0x20),
1294418919fSjohnjiang .ip_dst = RTE_IPV4(0x27, 0x26, 0x25, 0x24),
1304418919fSjohnjiang .port_src = 0x2928,
1314418919fSjohnjiang .port_dst = 0x2b2a,
1324418919fSjohnjiang .proto = 0x2c,
1334418919fSjohnjiang }, {
1344418919fSjohnjiang .ip_src = RTE_IPV4(0x33, 0x32, 0x31, 0x30),
1354418919fSjohnjiang .ip_dst = RTE_IPV4(0x37, 0x36, 0x35, 0x34),
1364418919fSjohnjiang .port_src = 0x3938,
1374418919fSjohnjiang .port_dst = 0x3b3a,
1384418919fSjohnjiang .proto = 0x3c,
1394418919fSjohnjiang }, {
1404418919fSjohnjiang .ip_src = RTE_IPV4(0x43, 0x42, 0x41, 0x40),
1414418919fSjohnjiang .ip_dst = RTE_IPV4(0x47, 0x46, 0x45, 0x44),
1424418919fSjohnjiang .port_src = 0x4948,
1434418919fSjohnjiang .port_dst = 0x4b4a,
1444418919fSjohnjiang .proto = 0x4c,
1454418919fSjohnjiang } };
1464418919fSjohnjiang
1474418919fSjohnjiang /* Parameters used for hash table in unit test functions. Name set later. */
1484418919fSjohnjiang static struct rte_hash_parameters ut_params = {
1494418919fSjohnjiang .entries = 64,
1504418919fSjohnjiang .key_len = sizeof(struct flow_key), /* 13 */
1514418919fSjohnjiang .hash_func = rte_jhash,
1524418919fSjohnjiang .hash_func_init_val = 0,
1534418919fSjohnjiang .socket_id = 0,
1544418919fSjohnjiang };
1554418919fSjohnjiang
1564418919fSjohnjiang #define CRC32_ITERATIONS (1U << 10)
1574418919fSjohnjiang #define CRC32_DWORDS (1U << 6)
1584418919fSjohnjiang /*
1594418919fSjohnjiang * Test if all CRC32 implementations yield the same hash value
1604418919fSjohnjiang */
1614418919fSjohnjiang static int
test_crc32_hash_alg_equiv(void)1624418919fSjohnjiang test_crc32_hash_alg_equiv(void)
1634418919fSjohnjiang {
1644418919fSjohnjiang uint32_t hash_val;
1654418919fSjohnjiang uint32_t init_val;
1664418919fSjohnjiang uint64_t data64[CRC32_DWORDS];
1674418919fSjohnjiang unsigned i, j;
1684418919fSjohnjiang size_t data_len;
1694418919fSjohnjiang
1704418919fSjohnjiang printf("\n# CRC32 implementations equivalence test\n");
1714418919fSjohnjiang for (i = 0; i < CRC32_ITERATIONS; i++) {
1724418919fSjohnjiang /* Randomizing data_len of data set */
1734418919fSjohnjiang data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
1744418919fSjohnjiang init_val = (uint32_t) rte_rand();
1754418919fSjohnjiang
1764418919fSjohnjiang /* Fill the data set */
1774418919fSjohnjiang for (j = 0; j < CRC32_DWORDS; j++)
1784418919fSjohnjiang data64[j] = rte_rand();
1794418919fSjohnjiang
1804418919fSjohnjiang /* Calculate software CRC32 */
1814418919fSjohnjiang rte_hash_crc_set_alg(CRC32_SW);
1824418919fSjohnjiang hash_val = rte_hash_crc(data64, data_len, init_val);
1834418919fSjohnjiang
1844418919fSjohnjiang /* Check against 4-byte-operand sse4.2 CRC32 if available */
1854418919fSjohnjiang rte_hash_crc_set_alg(CRC32_SSE42);
1864418919fSjohnjiang if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
1874418919fSjohnjiang printf("Failed checking CRC32_SW against CRC32_SSE42\n");
1884418919fSjohnjiang break;
1894418919fSjohnjiang }
1904418919fSjohnjiang
1914418919fSjohnjiang /* Check against 8-byte-operand sse4.2 CRC32 if available */
1924418919fSjohnjiang rte_hash_crc_set_alg(CRC32_SSE42_x64);
1934418919fSjohnjiang if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
1944418919fSjohnjiang printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
1954418919fSjohnjiang break;
1964418919fSjohnjiang }
1974418919fSjohnjiang
1984418919fSjohnjiang /* Check against 8-byte-operand ARM64 CRC32 if available */
1994418919fSjohnjiang rte_hash_crc_set_alg(CRC32_ARM64);
2004418919fSjohnjiang if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
2014418919fSjohnjiang printf("Failed checking CRC32_SW against CRC32_ARM64\n");
2024418919fSjohnjiang break;
2034418919fSjohnjiang }
2044418919fSjohnjiang }
2054418919fSjohnjiang
2064418919fSjohnjiang /* Resetting to best available algorithm */
2074418919fSjohnjiang rte_hash_crc_set_alg(CRC32_SSE42_x64);
2084418919fSjohnjiang
2094418919fSjohnjiang if (i == CRC32_ITERATIONS)
2104418919fSjohnjiang return 0;
2114418919fSjohnjiang
2124418919fSjohnjiang printf("Failed test data (hex, %zu bytes total):\n", data_len);
2134418919fSjohnjiang for (j = 0; j < data_len; j++)
2144418919fSjohnjiang printf("%02X%c", ((uint8_t *)data64)[j],
2154418919fSjohnjiang ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
2164418919fSjohnjiang
2174418919fSjohnjiang return -1;
2184418919fSjohnjiang }
2194418919fSjohnjiang
2204418919fSjohnjiang /*
2214418919fSjohnjiang * Test a hash function.
2224418919fSjohnjiang */
run_hash_func_test(rte_hash_function f,uint32_t init_val,uint32_t key_len)2234418919fSjohnjiang static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
2244418919fSjohnjiang uint32_t key_len)
2254418919fSjohnjiang {
2264418919fSjohnjiang static uint8_t key[MAX_KEYSIZE];
2274418919fSjohnjiang unsigned i;
2284418919fSjohnjiang
2294418919fSjohnjiang
2304418919fSjohnjiang for (i = 0; i < key_len; i++)
2314418919fSjohnjiang key[i] = (uint8_t) rte_rand();
2324418919fSjohnjiang
2334418919fSjohnjiang /* just to be on the safe side */
2344418919fSjohnjiang if (!f)
2354418919fSjohnjiang return;
2364418919fSjohnjiang
2374418919fSjohnjiang f(key, key_len, init_val);
2384418919fSjohnjiang }
2394418919fSjohnjiang
2404418919fSjohnjiang /*
2414418919fSjohnjiang * Test all hash functions.
2424418919fSjohnjiang */
run_hash_func_tests(void)2434418919fSjohnjiang static void run_hash_func_tests(void)
2444418919fSjohnjiang {
2454418919fSjohnjiang unsigned i, j, k;
2464418919fSjohnjiang
247*2d9fd380Sjfb8856606 for (i = 0; i < RTE_DIM(hashtest_funcs); i++) {
248*2d9fd380Sjfb8856606 for (j = 0; j < RTE_DIM(hashtest_initvals); j++) {
249*2d9fd380Sjfb8856606 for (k = 0; k < RTE_DIM(hashtest_key_lens); k++) {
2504418919fSjohnjiang run_hash_func_test(hashtest_funcs[i],
2514418919fSjohnjiang hashtest_initvals[j],
2524418919fSjohnjiang hashtest_key_lens[k]);
2534418919fSjohnjiang }
2544418919fSjohnjiang }
2554418919fSjohnjiang }
2564418919fSjohnjiang }
2574418919fSjohnjiang
2584418919fSjohnjiang /*
2594418919fSjohnjiang * Basic sequence of operations for a single key:
2604418919fSjohnjiang * - add
2614418919fSjohnjiang * - lookup (hit)
2624418919fSjohnjiang * - delete
2634418919fSjohnjiang * - lookup (miss)
2644418919fSjohnjiang *
2654418919fSjohnjiang * Repeat the test case when 'free on delete' is disabled.
2664418919fSjohnjiang * - add
2674418919fSjohnjiang * - lookup (hit)
2684418919fSjohnjiang * - delete
2694418919fSjohnjiang * - lookup (miss)
2704418919fSjohnjiang * - free
2714418919fSjohnjiang */
test_add_delete(void)2724418919fSjohnjiang static int test_add_delete(void)
2734418919fSjohnjiang {
2744418919fSjohnjiang struct rte_hash *handle;
2754418919fSjohnjiang /* test with standard add/lookup/delete functions */
2764418919fSjohnjiang int pos0, expectedPos0;
2774418919fSjohnjiang
2784418919fSjohnjiang ut_params.name = "test1";
2794418919fSjohnjiang handle = rte_hash_create(&ut_params);
2804418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
2814418919fSjohnjiang
2824418919fSjohnjiang pos0 = rte_hash_add_key(handle, &keys[0]);
2834418919fSjohnjiang print_key_info("Add", &keys[0], pos0);
2844418919fSjohnjiang RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
2854418919fSjohnjiang expectedPos0 = pos0;
2864418919fSjohnjiang
2874418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
2884418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
2894418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
2904418919fSjohnjiang "failed to find key (pos0=%d)", pos0);
2914418919fSjohnjiang
2924418919fSjohnjiang pos0 = rte_hash_del_key(handle, &keys[0]);
2934418919fSjohnjiang print_key_info("Del", &keys[0], pos0);
2944418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
2954418919fSjohnjiang "failed to delete key (pos0=%d)", pos0);
2964418919fSjohnjiang
2974418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
2984418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
2994418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
3004418919fSjohnjiang "fail: found key after deleting! (pos0=%d)", pos0);
3014418919fSjohnjiang
3024418919fSjohnjiang rte_hash_free(handle);
3034418919fSjohnjiang
3044418919fSjohnjiang /* repeat test with precomputed hash functions */
3054418919fSjohnjiang hash_sig_t hash_value;
3064418919fSjohnjiang int pos1, expectedPos1, delPos1;
3074418919fSjohnjiang
3084418919fSjohnjiang ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
3094418919fSjohnjiang handle = rte_hash_create(&ut_params);
3104418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
3114418919fSjohnjiang ut_params.extra_flag = 0;
3124418919fSjohnjiang
3134418919fSjohnjiang hash_value = rte_hash_hash(handle, &keys[0]);
3144418919fSjohnjiang pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
3154418919fSjohnjiang print_key_info("Add", &keys[0], pos1);
3164418919fSjohnjiang RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
3174418919fSjohnjiang expectedPos1 = pos1;
3184418919fSjohnjiang
3194418919fSjohnjiang pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
3204418919fSjohnjiang print_key_info("Lkp", &keys[0], pos1);
3214418919fSjohnjiang RETURN_IF_ERROR(pos1 != expectedPos1,
3224418919fSjohnjiang "failed to find key (pos1=%d)", pos1);
3234418919fSjohnjiang
3244418919fSjohnjiang pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
3254418919fSjohnjiang print_key_info("Del", &keys[0], pos1);
3264418919fSjohnjiang RETURN_IF_ERROR(pos1 != expectedPos1,
3274418919fSjohnjiang "failed to delete key (pos1=%d)", pos1);
3284418919fSjohnjiang delPos1 = pos1;
3294418919fSjohnjiang
3304418919fSjohnjiang pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
3314418919fSjohnjiang print_key_info("Lkp", &keys[0], pos1);
3324418919fSjohnjiang RETURN_IF_ERROR(pos1 != -ENOENT,
3334418919fSjohnjiang "fail: found key after deleting! (pos1=%d)", pos1);
3344418919fSjohnjiang
3354418919fSjohnjiang pos1 = rte_hash_free_key_with_position(handle, delPos1);
3364418919fSjohnjiang print_key_info("Free", &keys[0], delPos1);
3374418919fSjohnjiang RETURN_IF_ERROR(pos1 != 0,
3384418919fSjohnjiang "failed to free key (pos1=%d)", delPos1);
3394418919fSjohnjiang
3404418919fSjohnjiang rte_hash_free(handle);
3414418919fSjohnjiang
3424418919fSjohnjiang return 0;
3434418919fSjohnjiang }
3444418919fSjohnjiang
3454418919fSjohnjiang /*
3464418919fSjohnjiang * Sequence of operations for a single key:
3474418919fSjohnjiang * - delete: miss
3484418919fSjohnjiang * - add
3494418919fSjohnjiang * - lookup: hit
3504418919fSjohnjiang * - add: update
3514418919fSjohnjiang * - lookup: hit (updated data)
3524418919fSjohnjiang * - delete: hit
3534418919fSjohnjiang * - delete: miss
3544418919fSjohnjiang * - lookup: miss
3554418919fSjohnjiang */
test_add_update_delete(void)3564418919fSjohnjiang static int test_add_update_delete(void)
3574418919fSjohnjiang {
3584418919fSjohnjiang struct rte_hash *handle;
3594418919fSjohnjiang int pos0, expectedPos0;
3604418919fSjohnjiang
3614418919fSjohnjiang ut_params.name = "test2";
3624418919fSjohnjiang handle = rte_hash_create(&ut_params);
3634418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
3644418919fSjohnjiang
3654418919fSjohnjiang pos0 = rte_hash_del_key(handle, &keys[0]);
3664418919fSjohnjiang print_key_info("Del", &keys[0], pos0);
3674418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
3684418919fSjohnjiang "fail: found non-existent key (pos0=%d)", pos0);
3694418919fSjohnjiang
3704418919fSjohnjiang pos0 = rte_hash_add_key(handle, &keys[0]);
3714418919fSjohnjiang print_key_info("Add", &keys[0], pos0);
3724418919fSjohnjiang RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
3734418919fSjohnjiang expectedPos0 = pos0;
3744418919fSjohnjiang
3754418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
3764418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
3774418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
3784418919fSjohnjiang "failed to find key (pos0=%d)", pos0);
3794418919fSjohnjiang
3804418919fSjohnjiang pos0 = rte_hash_add_key(handle, &keys[0]);
3814418919fSjohnjiang print_key_info("Add", &keys[0], pos0);
3824418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
3834418919fSjohnjiang "failed to re-add key (pos0=%d)", pos0);
3844418919fSjohnjiang
3854418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
3864418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
3874418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
3884418919fSjohnjiang "failed to find key (pos0=%d)", pos0);
3894418919fSjohnjiang
3904418919fSjohnjiang pos0 = rte_hash_del_key(handle, &keys[0]);
3914418919fSjohnjiang print_key_info("Del", &keys[0], pos0);
3924418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
3934418919fSjohnjiang "failed to delete key (pos0=%d)", pos0);
3944418919fSjohnjiang
3954418919fSjohnjiang pos0 = rte_hash_del_key(handle, &keys[0]);
3964418919fSjohnjiang print_key_info("Del", &keys[0], pos0);
3974418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
3984418919fSjohnjiang "fail: deleted already deleted key (pos0=%d)", pos0);
3994418919fSjohnjiang
4004418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
4014418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
4024418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
4034418919fSjohnjiang "fail: found key after deleting! (pos0=%d)", pos0);
4044418919fSjohnjiang
4054418919fSjohnjiang rte_hash_free(handle);
4064418919fSjohnjiang return 0;
4074418919fSjohnjiang }
4084418919fSjohnjiang
4094418919fSjohnjiang /*
4104418919fSjohnjiang * Sequence of operations for a single key with 'disable free on del' set:
4114418919fSjohnjiang * - delete: miss
4124418919fSjohnjiang * - add
4134418919fSjohnjiang * - lookup: hit
4144418919fSjohnjiang * - add: update
4154418919fSjohnjiang * - lookup: hit (updated data)
4164418919fSjohnjiang * - delete: hit
4174418919fSjohnjiang * - delete: miss
4184418919fSjohnjiang * - lookup: miss
4194418919fSjohnjiang * - free: hit
4204418919fSjohnjiang * - lookup: miss
4214418919fSjohnjiang */
test_add_update_delete_free(void)4224418919fSjohnjiang static int test_add_update_delete_free(void)
4234418919fSjohnjiang {
4244418919fSjohnjiang struct rte_hash *handle;
4254418919fSjohnjiang int pos0, expectedPos0, delPos0, result;
4264418919fSjohnjiang
4274418919fSjohnjiang ut_params.name = "test2";
4284418919fSjohnjiang ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
4294418919fSjohnjiang handle = rte_hash_create(&ut_params);
4304418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
4314418919fSjohnjiang ut_params.extra_flag = 0;
4324418919fSjohnjiang
4334418919fSjohnjiang pos0 = rte_hash_del_key(handle, &keys[0]);
4344418919fSjohnjiang print_key_info("Del", &keys[0], pos0);
4354418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
4364418919fSjohnjiang "fail: found non-existent key (pos0=%d)", pos0);
4374418919fSjohnjiang
4384418919fSjohnjiang pos0 = rte_hash_add_key(handle, &keys[0]);
4394418919fSjohnjiang print_key_info("Add", &keys[0], pos0);
4404418919fSjohnjiang RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
4414418919fSjohnjiang expectedPos0 = pos0;
4424418919fSjohnjiang
4434418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
4444418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
4454418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
4464418919fSjohnjiang "failed to find key (pos0=%d)", pos0);
4474418919fSjohnjiang
4484418919fSjohnjiang pos0 = rte_hash_add_key(handle, &keys[0]);
4494418919fSjohnjiang print_key_info("Add", &keys[0], pos0);
4504418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
4514418919fSjohnjiang "failed to re-add key (pos0=%d)", pos0);
4524418919fSjohnjiang
4534418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
4544418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
4554418919fSjohnjiang RETURN_IF_ERROR(pos0 != expectedPos0,
4564418919fSjohnjiang "failed to find key (pos0=%d)", pos0);
4574418919fSjohnjiang
4584418919fSjohnjiang delPos0 = rte_hash_del_key(handle, &keys[0]);
4594418919fSjohnjiang print_key_info("Del", &keys[0], delPos0);
4604418919fSjohnjiang RETURN_IF_ERROR(delPos0 != expectedPos0,
4614418919fSjohnjiang "failed to delete key (pos0=%d)", delPos0);
4624418919fSjohnjiang
4634418919fSjohnjiang pos0 = rte_hash_del_key(handle, &keys[0]);
4644418919fSjohnjiang print_key_info("Del", &keys[0], pos0);
4654418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
4664418919fSjohnjiang "fail: deleted already deleted key (pos0=%d)", pos0);
4674418919fSjohnjiang
4684418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
4694418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
4704418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
4714418919fSjohnjiang "fail: found key after deleting! (pos0=%d)", pos0);
4724418919fSjohnjiang
4734418919fSjohnjiang result = rte_hash_free_key_with_position(handle, delPos0);
4744418919fSjohnjiang print_key_info("Free", &keys[0], delPos0);
4754418919fSjohnjiang RETURN_IF_ERROR(result != 0,
4764418919fSjohnjiang "failed to free key (pos1=%d)", delPos0);
4774418919fSjohnjiang
4784418919fSjohnjiang pos0 = rte_hash_lookup(handle, &keys[0]);
4794418919fSjohnjiang print_key_info("Lkp", &keys[0], pos0);
4804418919fSjohnjiang RETURN_IF_ERROR(pos0 != -ENOENT,
4814418919fSjohnjiang "fail: found key after deleting! (pos0=%d)", pos0);
4824418919fSjohnjiang
4834418919fSjohnjiang rte_hash_free(handle);
4844418919fSjohnjiang return 0;
4854418919fSjohnjiang }
4864418919fSjohnjiang
4874418919fSjohnjiang /*
4884418919fSjohnjiang * Sequence of operations for a single key with 'rw concurrency lock free' set:
4894418919fSjohnjiang * - add
4904418919fSjohnjiang * - delete: hit
4914418919fSjohnjiang * - free: hit
4924418919fSjohnjiang * Repeat the test case when 'multi writer add' is enabled.
4934418919fSjohnjiang * - add
4944418919fSjohnjiang * - delete: hit
4954418919fSjohnjiang * - free: hit
4964418919fSjohnjiang */
test_add_delete_free_lf(void)4974418919fSjohnjiang static int test_add_delete_free_lf(void)
4984418919fSjohnjiang {
4994418919fSjohnjiang /* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */
5004418919fSjohnjiang #define LCORE_CACHE_SIZE 64
5014418919fSjohnjiang struct rte_hash *handle;
5024418919fSjohnjiang hash_sig_t hash_value;
5034418919fSjohnjiang int pos, expectedPos, delPos;
5044418919fSjohnjiang uint8_t extra_flag;
5054418919fSjohnjiang uint32_t i, ip_src;
5064418919fSjohnjiang
5074418919fSjohnjiang extra_flag = ut_params.extra_flag;
5084418919fSjohnjiang ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
5094418919fSjohnjiang handle = rte_hash_create(&ut_params);
5104418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
5114418919fSjohnjiang ut_params.extra_flag = extra_flag;
5124418919fSjohnjiang
5134418919fSjohnjiang /*
5144418919fSjohnjiang * The number of iterations is at least the same as the number of slots
5154418919fSjohnjiang * rte_hash allocates internally. This is to reveal potential issues of
5164418919fSjohnjiang * not freeing keys successfully.
5174418919fSjohnjiang */
5184418919fSjohnjiang for (i = 0; i < ut_params.entries + 1; i++) {
5194418919fSjohnjiang hash_value = rte_hash_hash(handle, &keys[0]);
5204418919fSjohnjiang pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
5214418919fSjohnjiang print_key_info("Add", &keys[0], pos);
5224418919fSjohnjiang RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
5234418919fSjohnjiang expectedPos = pos;
5244418919fSjohnjiang
5254418919fSjohnjiang pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
5264418919fSjohnjiang print_key_info("Del", &keys[0], pos);
5274418919fSjohnjiang RETURN_IF_ERROR(pos != expectedPos,
5284418919fSjohnjiang "failed to delete key (pos=%d)", pos);
5294418919fSjohnjiang delPos = pos;
5304418919fSjohnjiang
5314418919fSjohnjiang pos = rte_hash_free_key_with_position(handle, delPos);
5324418919fSjohnjiang print_key_info("Free", &keys[0], delPos);
5334418919fSjohnjiang RETURN_IF_ERROR(pos != 0,
5344418919fSjohnjiang "failed to free key (pos=%d)", delPos);
5354418919fSjohnjiang }
5364418919fSjohnjiang
5374418919fSjohnjiang rte_hash_free(handle);
5384418919fSjohnjiang
5394418919fSjohnjiang extra_flag = ut_params.extra_flag;
5404418919fSjohnjiang ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
5414418919fSjohnjiang RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
5424418919fSjohnjiang handle = rte_hash_create(&ut_params);
5434418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
5444418919fSjohnjiang ut_params.extra_flag = extra_flag;
5454418919fSjohnjiang
5464418919fSjohnjiang ip_src = keys[0].ip_src;
5474418919fSjohnjiang /*
5484418919fSjohnjiang * The number of iterations is at least the same as the number of slots
5494418919fSjohnjiang * rte_hash allocates internally. This is to reveal potential issues of
5504418919fSjohnjiang * not freeing keys successfully.
5514418919fSjohnjiang */
5524418919fSjohnjiang for (i = 0; i < ut_params.entries + (RTE_MAX_LCORE - 1) *
5534418919fSjohnjiang (LCORE_CACHE_SIZE - 1) + 1; i++) {
5544418919fSjohnjiang keys[0].ip_src++;
5554418919fSjohnjiang hash_value = rte_hash_hash(handle, &keys[0]);
5564418919fSjohnjiang pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
5574418919fSjohnjiang print_key_info("Add", &keys[0], pos);
5584418919fSjohnjiang RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
5594418919fSjohnjiang expectedPos = pos;
5604418919fSjohnjiang
5614418919fSjohnjiang pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
5624418919fSjohnjiang print_key_info("Del", &keys[0], pos);
5634418919fSjohnjiang RETURN_IF_ERROR(pos != expectedPos,
5644418919fSjohnjiang "failed to delete key (pos=%d)", pos);
5654418919fSjohnjiang delPos = pos;
5664418919fSjohnjiang
5674418919fSjohnjiang pos = rte_hash_free_key_with_position(handle, delPos);
5684418919fSjohnjiang print_key_info("Free", &keys[0], delPos);
5694418919fSjohnjiang RETURN_IF_ERROR(pos != 0,
5704418919fSjohnjiang "failed to free key (pos=%d)", delPos);
5714418919fSjohnjiang }
5724418919fSjohnjiang keys[0].ip_src = ip_src;
5734418919fSjohnjiang
5744418919fSjohnjiang rte_hash_free(handle);
5754418919fSjohnjiang
5764418919fSjohnjiang return 0;
5774418919fSjohnjiang }
5784418919fSjohnjiang
5794418919fSjohnjiang /*
5804418919fSjohnjiang * Sequence of operations for retrieving a key with its position
5814418919fSjohnjiang *
5824418919fSjohnjiang * - create table
5834418919fSjohnjiang * - add key
5844418919fSjohnjiang * - get the key with its position: hit
5854418919fSjohnjiang * - delete key
5864418919fSjohnjiang * - try to get the deleted key: miss
5874418919fSjohnjiang *
5884418919fSjohnjiang * Repeat the test case when 'free on delete' is disabled.
5894418919fSjohnjiang * - create table
5904418919fSjohnjiang * - add key
5914418919fSjohnjiang * - get the key with its position: hit
5924418919fSjohnjiang * - delete key
5934418919fSjohnjiang * - try to get the deleted key: hit
5944418919fSjohnjiang * - free key
5954418919fSjohnjiang * - try to get the deleted key: miss
5964418919fSjohnjiang *
5974418919fSjohnjiang */
test_hash_get_key_with_position(void)5984418919fSjohnjiang static int test_hash_get_key_with_position(void)
5994418919fSjohnjiang {
6004418919fSjohnjiang struct rte_hash *handle = NULL;
6014418919fSjohnjiang int pos, expectedPos, delPos, result;
6024418919fSjohnjiang void *key;
6034418919fSjohnjiang
6044418919fSjohnjiang ut_params.name = "hash_get_key_w_pos";
6054418919fSjohnjiang handle = rte_hash_create(&ut_params);
6064418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
6074418919fSjohnjiang
6084418919fSjohnjiang pos = rte_hash_add_key(handle, &keys[0]);
6094418919fSjohnjiang print_key_info("Add", &keys[0], pos);
6104418919fSjohnjiang RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
6114418919fSjohnjiang expectedPos = pos;
6124418919fSjohnjiang
6134418919fSjohnjiang result = rte_hash_get_key_with_position(handle, pos, &key);
6144418919fSjohnjiang RETURN_IF_ERROR(result != 0, "error retrieving a key");
6154418919fSjohnjiang
6164418919fSjohnjiang pos = rte_hash_del_key(handle, &keys[0]);
6174418919fSjohnjiang print_key_info("Del", &keys[0], pos);
6184418919fSjohnjiang RETURN_IF_ERROR(pos != expectedPos,
6194418919fSjohnjiang "failed to delete key (pos0=%d)", pos);
6204418919fSjohnjiang
6214418919fSjohnjiang result = rte_hash_get_key_with_position(handle, pos, &key);
6224418919fSjohnjiang RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
6234418919fSjohnjiang
6244418919fSjohnjiang rte_hash_free(handle);
6254418919fSjohnjiang
6264418919fSjohnjiang ut_params.name = "hash_get_key_w_pos";
6274418919fSjohnjiang ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
6284418919fSjohnjiang handle = rte_hash_create(&ut_params);
6294418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
6304418919fSjohnjiang ut_params.extra_flag = 0;
6314418919fSjohnjiang
6324418919fSjohnjiang pos = rte_hash_add_key(handle, &keys[0]);
6334418919fSjohnjiang print_key_info("Add", &keys[0], pos);
6344418919fSjohnjiang RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
6354418919fSjohnjiang expectedPos = pos;
6364418919fSjohnjiang
6374418919fSjohnjiang result = rte_hash_get_key_with_position(handle, pos, &key);
6384418919fSjohnjiang RETURN_IF_ERROR(result != 0, "error retrieving a key");
6394418919fSjohnjiang
6404418919fSjohnjiang delPos = rte_hash_del_key(handle, &keys[0]);
6414418919fSjohnjiang print_key_info("Del", &keys[0], delPos);
6424418919fSjohnjiang RETURN_IF_ERROR(delPos != expectedPos,
6434418919fSjohnjiang "failed to delete key (pos0=%d)", delPos);
6444418919fSjohnjiang
6454418919fSjohnjiang result = rte_hash_get_key_with_position(handle, delPos, &key);
6464418919fSjohnjiang RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
6474418919fSjohnjiang
6484418919fSjohnjiang result = rte_hash_free_key_with_position(handle, delPos);
6494418919fSjohnjiang print_key_info("Free", &keys[0], delPos);
6504418919fSjohnjiang RETURN_IF_ERROR(result != 0,
6514418919fSjohnjiang "failed to free key (pos1=%d)", delPos);
6524418919fSjohnjiang
6534418919fSjohnjiang result = rte_hash_get_key_with_position(handle, delPos, &key);
6544418919fSjohnjiang RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
6554418919fSjohnjiang
6564418919fSjohnjiang rte_hash_free(handle);
6574418919fSjohnjiang return 0;
6584418919fSjohnjiang }
6594418919fSjohnjiang
6604418919fSjohnjiang /*
6614418919fSjohnjiang * Sequence of operations for find existing hash table
6624418919fSjohnjiang *
6634418919fSjohnjiang * - create table
6644418919fSjohnjiang * - find existing table: hit
6654418919fSjohnjiang * - find non-existing table: miss
6664418919fSjohnjiang *
6674418919fSjohnjiang */
test_hash_find_existing(void)6684418919fSjohnjiang static int test_hash_find_existing(void)
6694418919fSjohnjiang {
6704418919fSjohnjiang struct rte_hash *handle = NULL, *result = NULL;
6714418919fSjohnjiang
6724418919fSjohnjiang /* Create hash table. */
6734418919fSjohnjiang ut_params.name = "hash_find_existing";
6744418919fSjohnjiang handle = rte_hash_create(&ut_params);
6754418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
6764418919fSjohnjiang
6774418919fSjohnjiang /* Try to find existing hash table */
6784418919fSjohnjiang result = rte_hash_find_existing("hash_find_existing");
6794418919fSjohnjiang RETURN_IF_ERROR(result != handle, "could not find existing hash table");
6804418919fSjohnjiang
6814418919fSjohnjiang /* Try to find non-existing hash table */
6824418919fSjohnjiang result = rte_hash_find_existing("hash_find_non_existing");
6834418919fSjohnjiang RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
6844418919fSjohnjiang
6854418919fSjohnjiang /* Cleanup. */
6864418919fSjohnjiang rte_hash_free(handle);
6874418919fSjohnjiang
6884418919fSjohnjiang return 0;
6894418919fSjohnjiang }
6904418919fSjohnjiang
6914418919fSjohnjiang /*
6924418919fSjohnjiang * Sequence of operations for 5 keys
6934418919fSjohnjiang * - add keys
6944418919fSjohnjiang * - lookup keys: hit
6954418919fSjohnjiang * - add keys (update)
6964418919fSjohnjiang * - lookup keys: hit (updated data)
6974418919fSjohnjiang * - delete keys : hit
6984418919fSjohnjiang * - lookup keys: miss
6994418919fSjohnjiang */
test_five_keys(void)7004418919fSjohnjiang static int test_five_keys(void)
7014418919fSjohnjiang {
7024418919fSjohnjiang struct rte_hash *handle;
7034418919fSjohnjiang const void *key_array[5] = {0};
7044418919fSjohnjiang int pos[5];
7054418919fSjohnjiang int expected_pos[5];
7064418919fSjohnjiang unsigned i;
7074418919fSjohnjiang int ret;
7084418919fSjohnjiang
7094418919fSjohnjiang ut_params.name = "test3";
7104418919fSjohnjiang handle = rte_hash_create(&ut_params);
7114418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
7124418919fSjohnjiang
7134418919fSjohnjiang /* Add */
7144418919fSjohnjiang for (i = 0; i < 5; i++) {
7154418919fSjohnjiang pos[i] = rte_hash_add_key(handle, &keys[i]);
7164418919fSjohnjiang print_key_info("Add", &keys[i], pos[i]);
7174418919fSjohnjiang RETURN_IF_ERROR(pos[i] < 0,
7184418919fSjohnjiang "failed to add key (pos[%u]=%d)", i, pos[i]);
7194418919fSjohnjiang expected_pos[i] = pos[i];
7204418919fSjohnjiang }
7214418919fSjohnjiang
7224418919fSjohnjiang /* Lookup */
7234418919fSjohnjiang for(i = 0; i < 5; i++)
7244418919fSjohnjiang key_array[i] = &keys[i];
7254418919fSjohnjiang
7264418919fSjohnjiang ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
7274418919fSjohnjiang if(ret == 0)
7284418919fSjohnjiang for(i = 0; i < 5; i++) {
7294418919fSjohnjiang print_key_info("Lkp", key_array[i], pos[i]);
7304418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
7314418919fSjohnjiang "failed to find key (pos[%u]=%d)", i, pos[i]);
7324418919fSjohnjiang }
7334418919fSjohnjiang
7344418919fSjohnjiang /* Add - update */
7354418919fSjohnjiang for (i = 0; i < 5; i++) {
7364418919fSjohnjiang pos[i] = rte_hash_add_key(handle, &keys[i]);
7374418919fSjohnjiang print_key_info("Add", &keys[i], pos[i]);
7384418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
7394418919fSjohnjiang "failed to add key (pos[%u]=%d)", i, pos[i]);
7404418919fSjohnjiang }
7414418919fSjohnjiang
7424418919fSjohnjiang /* Lookup */
7434418919fSjohnjiang for (i = 0; i < 5; i++) {
7444418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &keys[i]);
7454418919fSjohnjiang print_key_info("Lkp", &keys[i], pos[i]);
7464418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
7474418919fSjohnjiang "failed to find key (pos[%u]=%d)", i, pos[i]);
7484418919fSjohnjiang }
7494418919fSjohnjiang
7504418919fSjohnjiang /* Delete */
7514418919fSjohnjiang for (i = 0; i < 5; i++) {
7524418919fSjohnjiang pos[i] = rte_hash_del_key(handle, &keys[i]);
7534418919fSjohnjiang print_key_info("Del", &keys[i], pos[i]);
7544418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
7554418919fSjohnjiang "failed to delete key (pos[%u]=%d)", i, pos[i]);
7564418919fSjohnjiang }
7574418919fSjohnjiang
7584418919fSjohnjiang /* Lookup */
7594418919fSjohnjiang for (i = 0; i < 5; i++) {
7604418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &keys[i]);
7614418919fSjohnjiang print_key_info("Lkp", &keys[i], pos[i]);
7624418919fSjohnjiang RETURN_IF_ERROR(pos[i] != -ENOENT,
7634418919fSjohnjiang "found non-existent key (pos[%u]=%d)", i, pos[i]);
7644418919fSjohnjiang }
7654418919fSjohnjiang
7664418919fSjohnjiang /* Lookup multi */
7674418919fSjohnjiang ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
7684418919fSjohnjiang if (ret == 0)
7694418919fSjohnjiang for (i = 0; i < 5; i++) {
7704418919fSjohnjiang print_key_info("Lkp", key_array[i], pos[i]);
7714418919fSjohnjiang RETURN_IF_ERROR(pos[i] != -ENOENT,
7724418919fSjohnjiang "found not-existent key (pos[%u]=%d)", i, pos[i]);
7734418919fSjohnjiang }
7744418919fSjohnjiang
7754418919fSjohnjiang rte_hash_free(handle);
7764418919fSjohnjiang
7774418919fSjohnjiang return 0;
7784418919fSjohnjiang }
7794418919fSjohnjiang
7804418919fSjohnjiang /*
7814418919fSjohnjiang * Add keys to the same bucket until bucket full.
7824418919fSjohnjiang * - add 5 keys to the same bucket (hash created with 4 keys per bucket):
7834418919fSjohnjiang * first 4 successful, 5th successful, pushing existing item in bucket
7844418919fSjohnjiang * - lookup the 5 keys: 5 hits
7854418919fSjohnjiang * - add the 5 keys again: 5 OK
7864418919fSjohnjiang * - lookup the 5 keys: 5 hits (updated data)
7874418919fSjohnjiang * - delete the 5 keys: 5 OK
7884418919fSjohnjiang * - lookup the 5 keys: 5 misses
7894418919fSjohnjiang */
test_full_bucket(void)7904418919fSjohnjiang static int test_full_bucket(void)
7914418919fSjohnjiang {
7924418919fSjohnjiang struct rte_hash_parameters params_pseudo_hash = {
7934418919fSjohnjiang .name = "test4",
7944418919fSjohnjiang .entries = 64,
7954418919fSjohnjiang .key_len = sizeof(struct flow_key), /* 13 */
7964418919fSjohnjiang .hash_func = pseudo_hash,
7974418919fSjohnjiang .hash_func_init_val = 0,
7984418919fSjohnjiang .socket_id = 0,
7994418919fSjohnjiang };
8004418919fSjohnjiang struct rte_hash *handle;
8014418919fSjohnjiang int pos[5];
8024418919fSjohnjiang int expected_pos[5];
8034418919fSjohnjiang unsigned i;
8044418919fSjohnjiang
8054418919fSjohnjiang handle = rte_hash_create(¶ms_pseudo_hash);
8064418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
8074418919fSjohnjiang
8084418919fSjohnjiang /* Fill bucket */
8094418919fSjohnjiang for (i = 0; i < 4; i++) {
8104418919fSjohnjiang pos[i] = rte_hash_add_key(handle, &keys[i]);
8114418919fSjohnjiang print_key_info("Add", &keys[i], pos[i]);
8124418919fSjohnjiang RETURN_IF_ERROR(pos[i] < 0,
8134418919fSjohnjiang "failed to add key (pos[%u]=%d)", i, pos[i]);
8144418919fSjohnjiang expected_pos[i] = pos[i];
8154418919fSjohnjiang }
8164418919fSjohnjiang /*
8174418919fSjohnjiang * This should work and will push one of the items
8184418919fSjohnjiang * in the bucket because it is full
8194418919fSjohnjiang */
8204418919fSjohnjiang pos[4] = rte_hash_add_key(handle, &keys[4]);
8214418919fSjohnjiang print_key_info("Add", &keys[4], pos[4]);
8224418919fSjohnjiang RETURN_IF_ERROR(pos[4] < 0,
8234418919fSjohnjiang "failed to add key (pos[4]=%d)", pos[4]);
8244418919fSjohnjiang expected_pos[4] = pos[4];
8254418919fSjohnjiang
8264418919fSjohnjiang /* Lookup */
8274418919fSjohnjiang for (i = 0; i < 5; i++) {
8284418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &keys[i]);
8294418919fSjohnjiang print_key_info("Lkp", &keys[i], pos[i]);
8304418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
8314418919fSjohnjiang "failed to find key (pos[%u]=%d)", i, pos[i]);
8324418919fSjohnjiang }
8334418919fSjohnjiang
8344418919fSjohnjiang /* Add - update */
8354418919fSjohnjiang for (i = 0; i < 5; i++) {
8364418919fSjohnjiang pos[i] = rte_hash_add_key(handle, &keys[i]);
8374418919fSjohnjiang print_key_info("Add", &keys[i], pos[i]);
8384418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
8394418919fSjohnjiang "failed to add key (pos[%u]=%d)", i, pos[i]);
8404418919fSjohnjiang }
8414418919fSjohnjiang
8424418919fSjohnjiang /* Lookup */
8434418919fSjohnjiang for (i = 0; i < 5; i++) {
8444418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &keys[i]);
8454418919fSjohnjiang print_key_info("Lkp", &keys[i], pos[i]);
8464418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
8474418919fSjohnjiang "failed to find key (pos[%u]=%d)", i, pos[i]);
8484418919fSjohnjiang }
8494418919fSjohnjiang
8504418919fSjohnjiang /* Delete 1 key, check other keys are still found */
8514418919fSjohnjiang pos[1] = rte_hash_del_key(handle, &keys[1]);
8524418919fSjohnjiang print_key_info("Del", &keys[1], pos[1]);
8534418919fSjohnjiang RETURN_IF_ERROR(pos[1] != expected_pos[1],
8544418919fSjohnjiang "failed to delete key (pos[1]=%d)", pos[1]);
8554418919fSjohnjiang pos[3] = rte_hash_lookup(handle, &keys[3]);
8564418919fSjohnjiang print_key_info("Lkp", &keys[3], pos[3]);
8574418919fSjohnjiang RETURN_IF_ERROR(pos[3] != expected_pos[3],
8584418919fSjohnjiang "failed lookup after deleting key from same bucket "
8594418919fSjohnjiang "(pos[3]=%d)", pos[3]);
8604418919fSjohnjiang
8614418919fSjohnjiang /* Go back to previous state */
8624418919fSjohnjiang pos[1] = rte_hash_add_key(handle, &keys[1]);
8634418919fSjohnjiang print_key_info("Add", &keys[1], pos[1]);
8644418919fSjohnjiang expected_pos[1] = pos[1];
8654418919fSjohnjiang RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
8664418919fSjohnjiang
8674418919fSjohnjiang /* Delete */
8684418919fSjohnjiang for (i = 0; i < 5; i++) {
8694418919fSjohnjiang pos[i] = rte_hash_del_key(handle, &keys[i]);
8704418919fSjohnjiang print_key_info("Del", &keys[i], pos[i]);
8714418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
8724418919fSjohnjiang "failed to delete key (pos[%u]=%d)", i, pos[i]);
8734418919fSjohnjiang }
8744418919fSjohnjiang
8754418919fSjohnjiang /* Lookup */
8764418919fSjohnjiang for (i = 0; i < 5; i++) {
8774418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &keys[i]);
8784418919fSjohnjiang print_key_info("Lkp", &keys[i], pos[i]);
8794418919fSjohnjiang RETURN_IF_ERROR(pos[i] != -ENOENT,
8804418919fSjohnjiang "fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
8814418919fSjohnjiang }
8824418919fSjohnjiang
8834418919fSjohnjiang rte_hash_free(handle);
8844418919fSjohnjiang
8854418919fSjohnjiang /* Cover the NULL case. */
8864418919fSjohnjiang rte_hash_free(0);
8874418919fSjohnjiang return 0;
8884418919fSjohnjiang }
8894418919fSjohnjiang
8904418919fSjohnjiang /*
8914418919fSjohnjiang * Similar to the test above (full bucket test), but for extendable buckets.
8924418919fSjohnjiang */
test_extendable_bucket(void)8934418919fSjohnjiang static int test_extendable_bucket(void)
8944418919fSjohnjiang {
8954418919fSjohnjiang struct rte_hash_parameters params_pseudo_hash = {
8964418919fSjohnjiang .name = "test5",
8974418919fSjohnjiang .entries = 64,
8984418919fSjohnjiang .key_len = sizeof(struct flow_key), /* 13 */
8994418919fSjohnjiang .hash_func = pseudo_hash,
9004418919fSjohnjiang .hash_func_init_val = 0,
9014418919fSjohnjiang .socket_id = 0,
9024418919fSjohnjiang .extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE
9034418919fSjohnjiang };
9044418919fSjohnjiang struct rte_hash *handle;
9054418919fSjohnjiang int pos[64];
9064418919fSjohnjiang int expected_pos[64];
9074418919fSjohnjiang unsigned int i;
9084418919fSjohnjiang struct flow_key rand_keys[64];
9094418919fSjohnjiang
9104418919fSjohnjiang for (i = 0; i < 64; i++) {
9114418919fSjohnjiang rand_keys[i].port_dst = i;
9124418919fSjohnjiang rand_keys[i].port_src = i+1;
9134418919fSjohnjiang }
9144418919fSjohnjiang
9154418919fSjohnjiang handle = rte_hash_create(¶ms_pseudo_hash);
9164418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
9174418919fSjohnjiang
9184418919fSjohnjiang /* Fill bucket */
9194418919fSjohnjiang for (i = 0; i < 64; i++) {
9204418919fSjohnjiang pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
9214418919fSjohnjiang print_key_info("Add", &rand_keys[i], pos[i]);
9224418919fSjohnjiang RETURN_IF_ERROR(pos[i] < 0,
9234418919fSjohnjiang "failed to add key (pos[%u]=%d)", i, pos[i]);
9244418919fSjohnjiang expected_pos[i] = pos[i];
9254418919fSjohnjiang }
9264418919fSjohnjiang
9274418919fSjohnjiang /* Lookup */
9284418919fSjohnjiang for (i = 0; i < 64; i++) {
9294418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
9304418919fSjohnjiang print_key_info("Lkp", &rand_keys[i], pos[i]);
9314418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
9324418919fSjohnjiang "failed to find key (pos[%u]=%d)", i, pos[i]);
9334418919fSjohnjiang }
9344418919fSjohnjiang
9354418919fSjohnjiang /* Add - update */
9364418919fSjohnjiang for (i = 0; i < 64; i++) {
9374418919fSjohnjiang pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
9384418919fSjohnjiang print_key_info("Add", &rand_keys[i], pos[i]);
9394418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
9404418919fSjohnjiang "failed to add key (pos[%u]=%d)", i, pos[i]);
9414418919fSjohnjiang }
9424418919fSjohnjiang
9434418919fSjohnjiang /* Lookup */
9444418919fSjohnjiang for (i = 0; i < 64; i++) {
9454418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
9464418919fSjohnjiang print_key_info("Lkp", &rand_keys[i], pos[i]);
9474418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
9484418919fSjohnjiang "failed to find key (pos[%u]=%d)", i, pos[i]);
9494418919fSjohnjiang }
9504418919fSjohnjiang
9514418919fSjohnjiang /* Delete 1 key, check other keys are still found */
9524418919fSjohnjiang pos[35] = rte_hash_del_key(handle, &rand_keys[35]);
9534418919fSjohnjiang print_key_info("Del", &rand_keys[35], pos[35]);
9544418919fSjohnjiang RETURN_IF_ERROR(pos[35] != expected_pos[35],
9554418919fSjohnjiang "failed to delete key (pos[1]=%d)", pos[35]);
9564418919fSjohnjiang pos[20] = rte_hash_lookup(handle, &rand_keys[20]);
9574418919fSjohnjiang print_key_info("Lkp", &rand_keys[20], pos[20]);
9584418919fSjohnjiang RETURN_IF_ERROR(pos[20] != expected_pos[20],
9594418919fSjohnjiang "failed lookup after deleting key from same bucket "
9604418919fSjohnjiang "(pos[20]=%d)", pos[20]);
9614418919fSjohnjiang
9624418919fSjohnjiang /* Go back to previous state */
9634418919fSjohnjiang pos[35] = rte_hash_add_key(handle, &rand_keys[35]);
9644418919fSjohnjiang print_key_info("Add", &rand_keys[35], pos[35]);
9654418919fSjohnjiang expected_pos[35] = pos[35];
9664418919fSjohnjiang RETURN_IF_ERROR(pos[35] < 0, "failed to add key (pos[1]=%d)", pos[35]);
9674418919fSjohnjiang
9684418919fSjohnjiang /* Delete */
9694418919fSjohnjiang for (i = 0; i < 64; i++) {
9704418919fSjohnjiang pos[i] = rte_hash_del_key(handle, &rand_keys[i]);
9714418919fSjohnjiang print_key_info("Del", &rand_keys[i], pos[i]);
9724418919fSjohnjiang RETURN_IF_ERROR(pos[i] != expected_pos[i],
9734418919fSjohnjiang "failed to delete key (pos[%u]=%d)", i, pos[i]);
9744418919fSjohnjiang }
9754418919fSjohnjiang
9764418919fSjohnjiang /* Lookup */
9774418919fSjohnjiang for (i = 0; i < 64; i++) {
9784418919fSjohnjiang pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
9794418919fSjohnjiang print_key_info("Lkp", &rand_keys[i], pos[i]);
9804418919fSjohnjiang RETURN_IF_ERROR(pos[i] != -ENOENT,
9814418919fSjohnjiang "fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
9824418919fSjohnjiang }
9834418919fSjohnjiang
9844418919fSjohnjiang /* Add again */
9854418919fSjohnjiang for (i = 0; i < 64; i++) {
9864418919fSjohnjiang pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
9874418919fSjohnjiang print_key_info("Add", &rand_keys[i], pos[i]);
9884418919fSjohnjiang RETURN_IF_ERROR(pos[i] < 0,
9894418919fSjohnjiang "failed to add key (pos[%u]=%d)", i, pos[i]);
9904418919fSjohnjiang expected_pos[i] = pos[i];
9914418919fSjohnjiang }
9924418919fSjohnjiang
9934418919fSjohnjiang rte_hash_free(handle);
9944418919fSjohnjiang
9954418919fSjohnjiang /* Cover the NULL case. */
9964418919fSjohnjiang rte_hash_free(0);
9974418919fSjohnjiang return 0;
9984418919fSjohnjiang }
9994418919fSjohnjiang
10004418919fSjohnjiang /******************************************************************************/
10014418919fSjohnjiang static int
fbk_hash_unit_test(void)10024418919fSjohnjiang fbk_hash_unit_test(void)
10034418919fSjohnjiang {
10044418919fSjohnjiang struct rte_fbk_hash_params params = {
10054418919fSjohnjiang .name = "fbk_hash_test",
10064418919fSjohnjiang .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
10074418919fSjohnjiang .entries_per_bucket = 4,
10084418919fSjohnjiang .socket_id = 0,
10094418919fSjohnjiang };
10104418919fSjohnjiang
10114418919fSjohnjiang struct rte_fbk_hash_params invalid_params_1 = {
10124418919fSjohnjiang .name = "invalid_1",
10134418919fSjohnjiang .entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
10144418919fSjohnjiang .entries_per_bucket = 4,
10154418919fSjohnjiang .socket_id = 0,
10164418919fSjohnjiang };
10174418919fSjohnjiang
10184418919fSjohnjiang struct rte_fbk_hash_params invalid_params_2 = {
10194418919fSjohnjiang .name = "invalid_2",
10204418919fSjohnjiang .entries = 4,
10214418919fSjohnjiang .entries_per_bucket = 3, /* Not power of 2 */
10224418919fSjohnjiang .socket_id = 0,
10234418919fSjohnjiang };
10244418919fSjohnjiang
10254418919fSjohnjiang struct rte_fbk_hash_params invalid_params_3 = {
10264418919fSjohnjiang .name = "invalid_3",
10274418919fSjohnjiang .entries = 0, /* Entries is 0 */
10284418919fSjohnjiang .entries_per_bucket = 4,
10294418919fSjohnjiang .socket_id = 0,
10304418919fSjohnjiang };
10314418919fSjohnjiang
10324418919fSjohnjiang struct rte_fbk_hash_params invalid_params_4 = {
10334418919fSjohnjiang .name = "invalid_4",
10344418919fSjohnjiang .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
10354418919fSjohnjiang .entries_per_bucket = 0, /* Entries per bucket is 0 */
10364418919fSjohnjiang .socket_id = 0,
10374418919fSjohnjiang };
10384418919fSjohnjiang
10394418919fSjohnjiang struct rte_fbk_hash_params invalid_params_5 = {
10404418919fSjohnjiang .name = "invalid_5",
10414418919fSjohnjiang .entries = 4,
10424418919fSjohnjiang .entries_per_bucket = 8, /* Entries per bucket > entries */
10434418919fSjohnjiang .socket_id = 0,
10444418919fSjohnjiang };
10454418919fSjohnjiang
10464418919fSjohnjiang struct rte_fbk_hash_params invalid_params_6 = {
10474418919fSjohnjiang .name = "invalid_6",
10484418919fSjohnjiang .entries = RTE_FBK_HASH_ENTRIES_MAX * 2, /* Entries > max allowed */
10494418919fSjohnjiang .entries_per_bucket = 4,
10504418919fSjohnjiang .socket_id = 0,
10514418919fSjohnjiang };
10524418919fSjohnjiang
10534418919fSjohnjiang struct rte_fbk_hash_params invalid_params_7 = {
10544418919fSjohnjiang .name = "invalid_7",
10554418919fSjohnjiang .entries = RTE_FBK_HASH_ENTRIES_MAX,
10564418919fSjohnjiang .entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2, /* Entries > max allowed */
10574418919fSjohnjiang .socket_id = 0,
10584418919fSjohnjiang };
10594418919fSjohnjiang
10604418919fSjohnjiang struct rte_fbk_hash_params invalid_params_8 = {
10614418919fSjohnjiang .name = "invalid_7",
10624418919fSjohnjiang .entries = RTE_FBK_HASH_ENTRIES_MAX,
10634418919fSjohnjiang .entries_per_bucket = 4,
10644418919fSjohnjiang .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
10654418919fSjohnjiang };
10664418919fSjohnjiang
10674418919fSjohnjiang /* try to create two hashes with identical names
10684418919fSjohnjiang * in this case, trying to create a second one will not
10694418919fSjohnjiang * fail but will simply return pointer to the existing
10704418919fSjohnjiang * hash with that name. sort of like a "find hash by name" :-)
10714418919fSjohnjiang */
10724418919fSjohnjiang struct rte_fbk_hash_params invalid_params_same_name_1 = {
10734418919fSjohnjiang .name = "same_name", /* hash with identical name */
10744418919fSjohnjiang .entries = 4,
10754418919fSjohnjiang .entries_per_bucket = 2,
10764418919fSjohnjiang .socket_id = 0,
10774418919fSjohnjiang };
10784418919fSjohnjiang
10794418919fSjohnjiang /* trying to create this hash should return a pointer to an existing hash */
10804418919fSjohnjiang struct rte_fbk_hash_params invalid_params_same_name_2 = {
10814418919fSjohnjiang .name = "same_name", /* hash with identical name */
10824418919fSjohnjiang .entries = RTE_FBK_HASH_ENTRIES_MAX,
10834418919fSjohnjiang .entries_per_bucket = 4,
10844418919fSjohnjiang .socket_id = 0,
10854418919fSjohnjiang };
10864418919fSjohnjiang
10874418919fSjohnjiang /* this is a sanity check for "same name" test
10884418919fSjohnjiang * creating this hash will check if we are actually able to create
10894418919fSjohnjiang * multiple hashes with different names (instead of having just one).
10904418919fSjohnjiang */
10914418919fSjohnjiang struct rte_fbk_hash_params different_name = {
10924418919fSjohnjiang .name = "different_name", /* different name */
10934418919fSjohnjiang .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
10944418919fSjohnjiang .entries_per_bucket = 4,
10954418919fSjohnjiang .socket_id = 0,
10964418919fSjohnjiang };
10974418919fSjohnjiang
10984418919fSjohnjiang struct rte_fbk_hash_params params_jhash = {
10994418919fSjohnjiang .name = "valid",
11004418919fSjohnjiang .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
11014418919fSjohnjiang .entries_per_bucket = 4,
11024418919fSjohnjiang .socket_id = 0,
11034418919fSjohnjiang .hash_func = rte_jhash_1word, /* Tests for different hash_func */
11044418919fSjohnjiang .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
11054418919fSjohnjiang };
11064418919fSjohnjiang
11074418919fSjohnjiang struct rte_fbk_hash_params params_nohash = {
11084418919fSjohnjiang .name = "valid nohash",
11094418919fSjohnjiang .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
11104418919fSjohnjiang .entries_per_bucket = 4,
11114418919fSjohnjiang .socket_id = 0,
11124418919fSjohnjiang .hash_func = NULL, /* Tests for null hash_func */
11134418919fSjohnjiang .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
11144418919fSjohnjiang };
11154418919fSjohnjiang
11164418919fSjohnjiang struct rte_fbk_hash_table *handle, *tmp;
11174418919fSjohnjiang uint32_t keys[5] =
11184418919fSjohnjiang {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
11194418919fSjohnjiang uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
11204418919fSjohnjiang int status;
11214418919fSjohnjiang unsigned i;
11224418919fSjohnjiang double used_entries;
11234418919fSjohnjiang
11244418919fSjohnjiang /* Try creating hashes with invalid parameters */
11254418919fSjohnjiang printf("# Testing hash creation with invalid parameters "
11264418919fSjohnjiang "- expect error msgs\n");
11274418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_1);
11284418919fSjohnjiang RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
11294418919fSjohnjiang
11304418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_2);
11314418919fSjohnjiang RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
11324418919fSjohnjiang
11334418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_3);
11344418919fSjohnjiang RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
11354418919fSjohnjiang
11364418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_4);
11374418919fSjohnjiang RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
11384418919fSjohnjiang
11394418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_5);
11404418919fSjohnjiang RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
11414418919fSjohnjiang
11424418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_6);
11434418919fSjohnjiang RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
11444418919fSjohnjiang
11454418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_7);
11464418919fSjohnjiang RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
11474418919fSjohnjiang
11480c6bd470Sfengbojiang if (rte_eal_has_hugepages()) {
11494418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_8);
11500c6bd470Sfengbojiang RETURN_IF_ERROR_FBK(handle != NULL,
11510c6bd470Sfengbojiang "fbk hash creation should have failed");
11520c6bd470Sfengbojiang }
11534418919fSjohnjiang
11544418919fSjohnjiang handle = rte_fbk_hash_create(&invalid_params_same_name_1);
11554418919fSjohnjiang RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
11564418919fSjohnjiang
11574418919fSjohnjiang tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
11584418919fSjohnjiang if (tmp != NULL)
11594418919fSjohnjiang rte_fbk_hash_free(tmp);
11604418919fSjohnjiang RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
11614418919fSjohnjiang
11624418919fSjohnjiang /* we are not freeing handle here because we need a hash list
11634418919fSjohnjiang * to be not empty for the next test */
11644418919fSjohnjiang
11654418919fSjohnjiang /* create a hash in non-empty list - good for coverage */
11664418919fSjohnjiang tmp = rte_fbk_hash_create(&different_name);
11674418919fSjohnjiang RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
11684418919fSjohnjiang
11694418919fSjohnjiang /* free both hashes */
11704418919fSjohnjiang rte_fbk_hash_free(handle);
11714418919fSjohnjiang rte_fbk_hash_free(tmp);
11724418919fSjohnjiang
11734418919fSjohnjiang /* Create empty jhash hash. */
11744418919fSjohnjiang handle = rte_fbk_hash_create(¶ms_jhash);
11754418919fSjohnjiang RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
11764418919fSjohnjiang
11774418919fSjohnjiang /* Cleanup. */
11784418919fSjohnjiang rte_fbk_hash_free(handle);
11794418919fSjohnjiang
11804418919fSjohnjiang /* Create empty jhash hash. */
11814418919fSjohnjiang handle = rte_fbk_hash_create(¶ms_nohash);
11824418919fSjohnjiang RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
11834418919fSjohnjiang
11844418919fSjohnjiang /* Cleanup. */
11854418919fSjohnjiang rte_fbk_hash_free(handle);
11864418919fSjohnjiang
11874418919fSjohnjiang /* Create empty hash. */
11884418919fSjohnjiang handle = rte_fbk_hash_create(¶ms);
11894418919fSjohnjiang RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
11904418919fSjohnjiang
11914418919fSjohnjiang used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
11924418919fSjohnjiang RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
11934418919fSjohnjiang "load factor right after creation is not zero but it should be");
11944418919fSjohnjiang /* Add keys. */
11954418919fSjohnjiang for (i = 0; i < 5; i++) {
11964418919fSjohnjiang status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
11974418919fSjohnjiang RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
11984418919fSjohnjiang }
11994418919fSjohnjiang
12004418919fSjohnjiang used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
12014418919fSjohnjiang RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
12024418919fSjohnjiang "load factor now is not as expected");
12034418919fSjohnjiang /* Find value of added keys. */
12044418919fSjohnjiang for (i = 0; i < 5; i++) {
12054418919fSjohnjiang status = rte_fbk_hash_lookup(handle, keys[i]);
12064418919fSjohnjiang RETURN_IF_ERROR_FBK(status != vals[i],
12074418919fSjohnjiang "fbk hash lookup failed");
12084418919fSjohnjiang }
12094418919fSjohnjiang
12104418919fSjohnjiang /* Change value of added keys. */
12114418919fSjohnjiang for (i = 0; i < 5; i++) {
12124418919fSjohnjiang status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
12134418919fSjohnjiang RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
12144418919fSjohnjiang }
12154418919fSjohnjiang
12164418919fSjohnjiang /* Find new values. */
12174418919fSjohnjiang for (i = 0; i < 5; i++) {
12184418919fSjohnjiang status = rte_fbk_hash_lookup(handle, keys[i]);
12194418919fSjohnjiang RETURN_IF_ERROR_FBK(status != vals[4-i],
12204418919fSjohnjiang "fbk hash lookup failed");
12214418919fSjohnjiang }
12224418919fSjohnjiang
12234418919fSjohnjiang /* Delete keys individually. */
12244418919fSjohnjiang for (i = 0; i < 5; i++) {
12254418919fSjohnjiang status = rte_fbk_hash_delete_key(handle, keys[i]);
12264418919fSjohnjiang RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
12274418919fSjohnjiang }
12284418919fSjohnjiang
12294418919fSjohnjiang used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
12304418919fSjohnjiang RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
12314418919fSjohnjiang "load factor right after deletion is not zero but it should be");
12324418919fSjohnjiang /* Lookup should now fail. */
12334418919fSjohnjiang for (i = 0; i < 5; i++) {
12344418919fSjohnjiang status = rte_fbk_hash_lookup(handle, keys[i]);
12354418919fSjohnjiang RETURN_IF_ERROR_FBK(status == 0,
12364418919fSjohnjiang "fbk hash lookup should have failed");
12374418919fSjohnjiang }
12384418919fSjohnjiang
12394418919fSjohnjiang /* Add keys again. */
12404418919fSjohnjiang for (i = 0; i < 5; i++) {
12414418919fSjohnjiang status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
12424418919fSjohnjiang RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
12434418919fSjohnjiang }
12444418919fSjohnjiang
12454418919fSjohnjiang /* Make sure they were added. */
12464418919fSjohnjiang for (i = 0; i < 5; i++) {
12474418919fSjohnjiang status = rte_fbk_hash_lookup(handle, keys[i]);
12484418919fSjohnjiang RETURN_IF_ERROR_FBK(status != vals[i],
12494418919fSjohnjiang "fbk hash lookup failed");
12504418919fSjohnjiang }
12514418919fSjohnjiang
12524418919fSjohnjiang /* Clear all entries. */
12534418919fSjohnjiang rte_fbk_hash_clear_all(handle);
12544418919fSjohnjiang
12554418919fSjohnjiang /* Lookup should fail. */
12564418919fSjohnjiang for (i = 0; i < 5; i++) {
12574418919fSjohnjiang status = rte_fbk_hash_lookup(handle, keys[i]);
12584418919fSjohnjiang RETURN_IF_ERROR_FBK(status == 0,
12594418919fSjohnjiang "fbk hash lookup should have failed");
12604418919fSjohnjiang }
12614418919fSjohnjiang
12624418919fSjohnjiang /* coverage */
12634418919fSjohnjiang
12644418919fSjohnjiang /* fill up the hash_table */
12654418919fSjohnjiang for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
12664418919fSjohnjiang rte_fbk_hash_add_key(handle, i, (uint16_t) i);
12674418919fSjohnjiang
12684418919fSjohnjiang /* Find non-existent key in a full hashtable */
12694418919fSjohnjiang status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
12704418919fSjohnjiang RETURN_IF_ERROR_FBK(status != -ENOENT,
12714418919fSjohnjiang "fbk hash lookup succeeded");
12724418919fSjohnjiang
12734418919fSjohnjiang /* Delete non-existent key in a full hashtable */
12744418919fSjohnjiang status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
12754418919fSjohnjiang RETURN_IF_ERROR_FBK(status != -ENOENT,
12764418919fSjohnjiang "fbk hash delete succeeded");
12774418919fSjohnjiang
12784418919fSjohnjiang /* Delete one key from a full hashtable */
12794418919fSjohnjiang status = rte_fbk_hash_delete_key(handle, 1);
12804418919fSjohnjiang RETURN_IF_ERROR_FBK(status != 0,
12814418919fSjohnjiang "fbk hash delete failed");
12824418919fSjohnjiang
12834418919fSjohnjiang /* Clear all entries. */
12844418919fSjohnjiang rte_fbk_hash_clear_all(handle);
12854418919fSjohnjiang
12864418919fSjohnjiang /* Cleanup. */
12874418919fSjohnjiang rte_fbk_hash_free(handle);
12884418919fSjohnjiang
12894418919fSjohnjiang /* Cover the NULL case. */
12904418919fSjohnjiang rte_fbk_hash_free(0);
12914418919fSjohnjiang
12924418919fSjohnjiang return 0;
12934418919fSjohnjiang }
12944418919fSjohnjiang
12954418919fSjohnjiang /*
12964418919fSjohnjiang * Sequence of operations for find existing fbk hash table
12974418919fSjohnjiang *
12984418919fSjohnjiang * - create table
12994418919fSjohnjiang * - find existing table: hit
13004418919fSjohnjiang * - find non-existing table: miss
13014418919fSjohnjiang *
13024418919fSjohnjiang */
test_fbk_hash_find_existing(void)13034418919fSjohnjiang static int test_fbk_hash_find_existing(void)
13044418919fSjohnjiang {
13054418919fSjohnjiang struct rte_fbk_hash_params params = {
13064418919fSjohnjiang .name = "fbk_hash_find_existing",
13074418919fSjohnjiang .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
13084418919fSjohnjiang .entries_per_bucket = 4,
13094418919fSjohnjiang .socket_id = 0,
13104418919fSjohnjiang };
13114418919fSjohnjiang struct rte_fbk_hash_table *handle = NULL, *result = NULL;
13124418919fSjohnjiang
13134418919fSjohnjiang /* Create hash table. */
13144418919fSjohnjiang handle = rte_fbk_hash_create(¶ms);
13154418919fSjohnjiang RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
13164418919fSjohnjiang
13174418919fSjohnjiang /* Try to find existing fbk hash table */
13184418919fSjohnjiang result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
13194418919fSjohnjiang RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
13204418919fSjohnjiang
13214418919fSjohnjiang /* Try to find non-existing fbk hash table */
13224418919fSjohnjiang result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
13234418919fSjohnjiang RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
13244418919fSjohnjiang
13254418919fSjohnjiang /* Cleanup. */
13264418919fSjohnjiang rte_fbk_hash_free(handle);
13274418919fSjohnjiang
13284418919fSjohnjiang return 0;
13294418919fSjohnjiang }
13304418919fSjohnjiang
13314418919fSjohnjiang #define BUCKET_ENTRIES 4
13324418919fSjohnjiang /*
13334418919fSjohnjiang * Do tests for hash creation with bad parameters.
13344418919fSjohnjiang */
test_hash_creation_with_bad_parameters(void)13354418919fSjohnjiang static int test_hash_creation_with_bad_parameters(void)
13364418919fSjohnjiang {
13374418919fSjohnjiang struct rte_hash *handle, *tmp;
13384418919fSjohnjiang struct rte_hash_parameters params;
13394418919fSjohnjiang
13404418919fSjohnjiang handle = rte_hash_create(NULL);
13414418919fSjohnjiang if (handle != NULL) {
13424418919fSjohnjiang rte_hash_free(handle);
13434418919fSjohnjiang printf("Impossible creating hash successfully without any parameter\n");
13444418919fSjohnjiang return -1;
13454418919fSjohnjiang }
13464418919fSjohnjiang
13474418919fSjohnjiang memcpy(¶ms, &ut_params, sizeof(params));
13484418919fSjohnjiang params.name = "creation_with_bad_parameters_0";
13494418919fSjohnjiang params.entries = RTE_HASH_ENTRIES_MAX + 1;
13504418919fSjohnjiang handle = rte_hash_create(¶ms);
13514418919fSjohnjiang if (handle != NULL) {
13524418919fSjohnjiang rte_hash_free(handle);
13534418919fSjohnjiang printf("Impossible creating hash successfully with entries in parameter exceeded\n");
13544418919fSjohnjiang return -1;
13554418919fSjohnjiang }
13564418919fSjohnjiang
13574418919fSjohnjiang memcpy(¶ms, &ut_params, sizeof(params));
13584418919fSjohnjiang params.name = "creation_with_bad_parameters_2";
13594418919fSjohnjiang params.entries = BUCKET_ENTRIES - 1;
13604418919fSjohnjiang handle = rte_hash_create(¶ms);
13614418919fSjohnjiang if (handle != NULL) {
13624418919fSjohnjiang rte_hash_free(handle);
13634418919fSjohnjiang printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n");
13644418919fSjohnjiang return -1;
13654418919fSjohnjiang }
13664418919fSjohnjiang
13674418919fSjohnjiang memcpy(¶ms, &ut_params, sizeof(params));
13684418919fSjohnjiang params.name = "creation_with_bad_parameters_3";
13694418919fSjohnjiang params.key_len = 0;
13704418919fSjohnjiang handle = rte_hash_create(¶ms);
13714418919fSjohnjiang if (handle != NULL) {
13724418919fSjohnjiang rte_hash_free(handle);
13734418919fSjohnjiang printf("Impossible creating hash successfully if key_len in parameter is zero\n");
13744418919fSjohnjiang return -1;
13754418919fSjohnjiang }
13764418919fSjohnjiang
13774418919fSjohnjiang memcpy(¶ms, &ut_params, sizeof(params));
13784418919fSjohnjiang params.name = "creation_with_bad_parameters_4";
13794418919fSjohnjiang params.socket_id = RTE_MAX_NUMA_NODES + 1;
13804418919fSjohnjiang handle = rte_hash_create(¶ms);
13814418919fSjohnjiang if (handle != NULL) {
13824418919fSjohnjiang rte_hash_free(handle);
13834418919fSjohnjiang printf("Impossible creating hash successfully with invalid socket\n");
13844418919fSjohnjiang return -1;
13854418919fSjohnjiang }
13864418919fSjohnjiang
13874418919fSjohnjiang /* test with same name should fail */
13884418919fSjohnjiang memcpy(¶ms, &ut_params, sizeof(params));
13894418919fSjohnjiang params.name = "same_name";
13904418919fSjohnjiang handle = rte_hash_create(¶ms);
13914418919fSjohnjiang if (handle == NULL) {
13924418919fSjohnjiang printf("Cannot create first hash table with 'same_name'\n");
13934418919fSjohnjiang return -1;
13944418919fSjohnjiang }
13954418919fSjohnjiang tmp = rte_hash_create(¶ms);
13964418919fSjohnjiang if (tmp != NULL) {
13974418919fSjohnjiang printf("Creation of hash table with same name should fail\n");
13984418919fSjohnjiang rte_hash_free(handle);
13994418919fSjohnjiang rte_hash_free(tmp);
14004418919fSjohnjiang return -1;
14014418919fSjohnjiang }
14024418919fSjohnjiang rte_hash_free(handle);
14034418919fSjohnjiang
14044418919fSjohnjiang printf("# Test successful. No more errors expected\n");
14054418919fSjohnjiang
14064418919fSjohnjiang return 0;
14074418919fSjohnjiang }
14084418919fSjohnjiang
14094418919fSjohnjiang /*
14104418919fSjohnjiang * Do tests for hash creation with parameters that look incorrect
14114418919fSjohnjiang * but are actually valid.
14124418919fSjohnjiang */
14134418919fSjohnjiang static int
test_hash_creation_with_good_parameters(void)14144418919fSjohnjiang test_hash_creation_with_good_parameters(void)
14154418919fSjohnjiang {
14164418919fSjohnjiang struct rte_hash *handle;
14174418919fSjohnjiang struct rte_hash_parameters params;
14184418919fSjohnjiang
14194418919fSjohnjiang /* create with null hash function - should choose DEFAULT_HASH_FUNC */
14204418919fSjohnjiang memcpy(¶ms, &ut_params, sizeof(params));
14214418919fSjohnjiang params.name = "name";
14224418919fSjohnjiang params.hash_func = NULL;
14234418919fSjohnjiang handle = rte_hash_create(¶ms);
14244418919fSjohnjiang if (handle == NULL) {
14254418919fSjohnjiang printf("Creating hash with null hash_func failed\n");
14264418919fSjohnjiang return -1;
14274418919fSjohnjiang }
14284418919fSjohnjiang
14294418919fSjohnjiang rte_hash_free(handle);
14304418919fSjohnjiang
14314418919fSjohnjiang return 0;
14324418919fSjohnjiang }
14334418919fSjohnjiang
14344418919fSjohnjiang #define ITERATIONS 3
14354418919fSjohnjiang /*
14364418919fSjohnjiang * Test to see the average table utilization (entries added/max entries)
14374418919fSjohnjiang * before hitting a random entry that cannot be added
14384418919fSjohnjiang */
test_average_table_utilization(uint32_t ext_table)14394418919fSjohnjiang static int test_average_table_utilization(uint32_t ext_table)
14404418919fSjohnjiang {
14414418919fSjohnjiang struct rte_hash *handle;
14424418919fSjohnjiang uint8_t simple_key[MAX_KEYSIZE];
14434418919fSjohnjiang unsigned i, j;
14444418919fSjohnjiang unsigned added_keys, average_keys_added = 0;
14454418919fSjohnjiang int ret;
14464418919fSjohnjiang unsigned int cnt;
14474418919fSjohnjiang
14484418919fSjohnjiang printf("\n# Running test to determine average utilization"
14494418919fSjohnjiang "\n before adding elements begins to fail\n");
14504418919fSjohnjiang if (ext_table)
14514418919fSjohnjiang printf("ext table is enabled\n");
14524418919fSjohnjiang else
14534418919fSjohnjiang printf("ext table is disabled\n");
14544418919fSjohnjiang
14554418919fSjohnjiang printf("Measuring performance, please wait");
14564418919fSjohnjiang fflush(stdout);
14574418919fSjohnjiang ut_params.entries = 1 << 16;
14584418919fSjohnjiang ut_params.name = "test_average_utilization";
14594418919fSjohnjiang ut_params.hash_func = rte_jhash;
14604418919fSjohnjiang if (ext_table)
14614418919fSjohnjiang ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
14624418919fSjohnjiang else
14634418919fSjohnjiang ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
14644418919fSjohnjiang
14654418919fSjohnjiang handle = rte_hash_create(&ut_params);
14664418919fSjohnjiang
14674418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
14684418919fSjohnjiang
14694418919fSjohnjiang for (j = 0; j < ITERATIONS; j++) {
14704418919fSjohnjiang ret = 0;
14714418919fSjohnjiang /* Add random entries until key cannot be added */
14724418919fSjohnjiang for (added_keys = 0; ret >= 0; added_keys++) {
14734418919fSjohnjiang for (i = 0; i < ut_params.key_len; i++)
14744418919fSjohnjiang simple_key[i] = rte_rand() % 255;
14754418919fSjohnjiang ret = rte_hash_add_key(handle, simple_key);
14764418919fSjohnjiang if (ret < 0)
14774418919fSjohnjiang break;
14784418919fSjohnjiang }
14794418919fSjohnjiang
14804418919fSjohnjiang if (ret != -ENOSPC) {
14814418919fSjohnjiang printf("Unexpected error when adding keys\n");
14824418919fSjohnjiang rte_hash_free(handle);
14834418919fSjohnjiang return -1;
14844418919fSjohnjiang }
14854418919fSjohnjiang
14864418919fSjohnjiang cnt = rte_hash_count(handle);
14874418919fSjohnjiang if (cnt != added_keys) {
14884418919fSjohnjiang printf("rte_hash_count returned wrong value %u, %u,"
14894418919fSjohnjiang "%u\n", j, added_keys, cnt);
14904418919fSjohnjiang rte_hash_free(handle);
14914418919fSjohnjiang return -1;
14924418919fSjohnjiang }
14934418919fSjohnjiang if (ext_table) {
14944418919fSjohnjiang if (cnt != ut_params.entries) {
14954418919fSjohnjiang printf("rte_hash_count returned wrong value "
14964418919fSjohnjiang "%u, %u, %u\n", j, added_keys, cnt);
14974418919fSjohnjiang rte_hash_free(handle);
14984418919fSjohnjiang return -1;
14994418919fSjohnjiang }
15004418919fSjohnjiang }
15014418919fSjohnjiang
15024418919fSjohnjiang average_keys_added += added_keys;
15034418919fSjohnjiang
15044418919fSjohnjiang /* Reset the table */
15054418919fSjohnjiang rte_hash_reset(handle);
15064418919fSjohnjiang
15074418919fSjohnjiang /* Print a dot to show progress on operations */
15084418919fSjohnjiang printf(".");
15094418919fSjohnjiang fflush(stdout);
15104418919fSjohnjiang }
15114418919fSjohnjiang
15124418919fSjohnjiang average_keys_added /= ITERATIONS;
15134418919fSjohnjiang
15144418919fSjohnjiang printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
15154418919fSjohnjiang ((double) average_keys_added / ut_params.entries * 100),
15164418919fSjohnjiang average_keys_added, ut_params.entries);
15174418919fSjohnjiang rte_hash_free(handle);
15184418919fSjohnjiang
15194418919fSjohnjiang return 0;
15204418919fSjohnjiang }
15214418919fSjohnjiang
15224418919fSjohnjiang #define NUM_ENTRIES 256
test_hash_iteration(uint32_t ext_table)15234418919fSjohnjiang static int test_hash_iteration(uint32_t ext_table)
15244418919fSjohnjiang {
15254418919fSjohnjiang struct rte_hash *handle;
15264418919fSjohnjiang unsigned i;
15274418919fSjohnjiang uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE];
15284418919fSjohnjiang const void *next_key;
15294418919fSjohnjiang void *next_data;
15304418919fSjohnjiang void *data[NUM_ENTRIES];
15314418919fSjohnjiang unsigned added_keys;
15324418919fSjohnjiang uint32_t iter = 0;
15334418919fSjohnjiang int ret = 0;
15344418919fSjohnjiang
15354418919fSjohnjiang ut_params.entries = NUM_ENTRIES;
15364418919fSjohnjiang ut_params.name = "test_hash_iteration";
15374418919fSjohnjiang ut_params.hash_func = rte_jhash;
15384418919fSjohnjiang ut_params.key_len = 16;
15394418919fSjohnjiang if (ext_table)
15404418919fSjohnjiang ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
15414418919fSjohnjiang else
15424418919fSjohnjiang ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
15434418919fSjohnjiang
15444418919fSjohnjiang handle = rte_hash_create(&ut_params);
15454418919fSjohnjiang RETURN_IF_ERROR(handle == NULL, "hash creation failed");
15464418919fSjohnjiang
15474418919fSjohnjiang /* Add random entries until key cannot be added */
15484418919fSjohnjiang for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
15494418919fSjohnjiang data[added_keys] = (void *) ((uintptr_t) rte_rand());
15504418919fSjohnjiang for (i = 0; i < ut_params.key_len; i++)
15514418919fSjohnjiang keys[added_keys][i] = rte_rand() % 255;
15524418919fSjohnjiang ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]);
15534418919fSjohnjiang if (ret < 0) {
15544418919fSjohnjiang if (ext_table) {
15554418919fSjohnjiang printf("Insertion failed for ext table\n");
15564418919fSjohnjiang goto err;
15574418919fSjohnjiang }
15584418919fSjohnjiang break;
15594418919fSjohnjiang }
15604418919fSjohnjiang }
15614418919fSjohnjiang
15624418919fSjohnjiang /* Iterate through the hash table */
15634418919fSjohnjiang while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
15644418919fSjohnjiang /* Search for the key in the list of keys added */
15654418919fSjohnjiang for (i = 0; i < NUM_ENTRIES; i++) {
15664418919fSjohnjiang if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
15674418919fSjohnjiang if (next_data != data[i]) {
15684418919fSjohnjiang printf("Data found in the hash table is"
15694418919fSjohnjiang "not the data added with the key\n");
15704418919fSjohnjiang goto err;
15714418919fSjohnjiang }
15724418919fSjohnjiang added_keys--;
15734418919fSjohnjiang break;
15744418919fSjohnjiang }
15754418919fSjohnjiang }
15764418919fSjohnjiang if (i == NUM_ENTRIES) {
15774418919fSjohnjiang printf("Key found in the hash table was not added\n");
15784418919fSjohnjiang goto err;
15794418919fSjohnjiang }
15804418919fSjohnjiang }
15814418919fSjohnjiang
15824418919fSjohnjiang /* Check if all keys have been iterated */
15834418919fSjohnjiang if (added_keys != 0) {
15844418919fSjohnjiang printf("There were still %u keys to iterate\n", added_keys);
15854418919fSjohnjiang goto err;
15864418919fSjohnjiang }
15874418919fSjohnjiang
15884418919fSjohnjiang rte_hash_free(handle);
15894418919fSjohnjiang return 0;
15904418919fSjohnjiang
15914418919fSjohnjiang err:
15924418919fSjohnjiang rte_hash_free(handle);
15934418919fSjohnjiang return -1;
15944418919fSjohnjiang }
15954418919fSjohnjiang
15964418919fSjohnjiang static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
15974418919fSjohnjiang 0x04, 0x05, 0x06, 0x07,
15984418919fSjohnjiang 0x08, 0x09, 0x0a, 0x0b,
15994418919fSjohnjiang 0x0c, 0x0d, 0x0e, 0x0f};
16004418919fSjohnjiang static struct rte_hash_parameters hash_params_ex = {
16014418919fSjohnjiang .name = NULL,
16024418919fSjohnjiang .entries = 64,
16034418919fSjohnjiang .key_len = 0,
16044418919fSjohnjiang .hash_func = NULL,
16054418919fSjohnjiang .hash_func_init_val = 0,
16064418919fSjohnjiang .socket_id = 0,
16074418919fSjohnjiang };
16084418919fSjohnjiang
16094418919fSjohnjiang /*
16104418919fSjohnjiang * add/delete key with jhash2
16114418919fSjohnjiang */
16124418919fSjohnjiang static int
test_hash_add_delete_jhash2(void)16134418919fSjohnjiang test_hash_add_delete_jhash2(void)
16144418919fSjohnjiang {
16154418919fSjohnjiang int ret = -1;
16164418919fSjohnjiang struct rte_hash *handle;
16174418919fSjohnjiang int32_t pos1, pos2;
16184418919fSjohnjiang
16194418919fSjohnjiang hash_params_ex.name = "hash_test_jhash2";
16204418919fSjohnjiang hash_params_ex.key_len = 4;
16214418919fSjohnjiang hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b;
16224418919fSjohnjiang
16234418919fSjohnjiang handle = rte_hash_create(&hash_params_ex);
16244418919fSjohnjiang if (handle == NULL) {
16254418919fSjohnjiang printf("test_hash_add_delete_jhash2 fail to create hash\n");
16264418919fSjohnjiang goto fail_jhash2;
16274418919fSjohnjiang }
16284418919fSjohnjiang pos1 = rte_hash_add_key(handle, (void *)&key[0]);
16294418919fSjohnjiang if (pos1 < 0) {
16304418919fSjohnjiang printf("test_hash_add_delete_jhash2 fail to add hash key\n");
16314418919fSjohnjiang goto fail_jhash2;
16324418919fSjohnjiang }
16334418919fSjohnjiang
16344418919fSjohnjiang pos2 = rte_hash_del_key(handle, (void *)&key[0]);
16354418919fSjohnjiang if (pos2 < 0 || pos1 != pos2) {
16364418919fSjohnjiang printf("test_hash_add_delete_jhash2 delete different key from being added\n");
16374418919fSjohnjiang goto fail_jhash2;
16384418919fSjohnjiang }
16394418919fSjohnjiang ret = 0;
16404418919fSjohnjiang
16414418919fSjohnjiang fail_jhash2:
16424418919fSjohnjiang if (handle != NULL)
16434418919fSjohnjiang rte_hash_free(handle);
16444418919fSjohnjiang
16454418919fSjohnjiang return ret;
16464418919fSjohnjiang }
16474418919fSjohnjiang
16484418919fSjohnjiang /*
16494418919fSjohnjiang * add/delete (2) key with jhash2
16504418919fSjohnjiang */
16514418919fSjohnjiang static int
test_hash_add_delete_2_jhash2(void)16524418919fSjohnjiang test_hash_add_delete_2_jhash2(void)
16534418919fSjohnjiang {
16544418919fSjohnjiang int ret = -1;
16554418919fSjohnjiang struct rte_hash *handle;
16564418919fSjohnjiang int32_t pos1, pos2;
16574418919fSjohnjiang
16584418919fSjohnjiang hash_params_ex.name = "hash_test_2_jhash2";
16594418919fSjohnjiang hash_params_ex.key_len = 8;
16604418919fSjohnjiang hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b;
16614418919fSjohnjiang
16624418919fSjohnjiang handle = rte_hash_create(&hash_params_ex);
16634418919fSjohnjiang if (handle == NULL)
16644418919fSjohnjiang goto fail_2_jhash2;
16654418919fSjohnjiang
16664418919fSjohnjiang pos1 = rte_hash_add_key(handle, (void *)&key[0]);
16674418919fSjohnjiang if (pos1 < 0)
16684418919fSjohnjiang goto fail_2_jhash2;
16694418919fSjohnjiang
16704418919fSjohnjiang pos2 = rte_hash_del_key(handle, (void *)&key[0]);
16714418919fSjohnjiang if (pos2 < 0 || pos1 != pos2)
16724418919fSjohnjiang goto fail_2_jhash2;
16734418919fSjohnjiang
16744418919fSjohnjiang ret = 0;
16754418919fSjohnjiang
16764418919fSjohnjiang fail_2_jhash2:
16774418919fSjohnjiang if (handle != NULL)
16784418919fSjohnjiang rte_hash_free(handle);
16794418919fSjohnjiang
16804418919fSjohnjiang return ret;
16814418919fSjohnjiang }
16824418919fSjohnjiang
16834418919fSjohnjiang static uint32_t
test_hash_jhash_1word(const void * key,uint32_t length,uint32_t initval)16844418919fSjohnjiang test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
16854418919fSjohnjiang {
16864418919fSjohnjiang const uint32_t *k = key;
16874418919fSjohnjiang
16884418919fSjohnjiang RTE_SET_USED(length);
16894418919fSjohnjiang
16904418919fSjohnjiang return rte_jhash_1word(k[0], initval);
16914418919fSjohnjiang }
16924418919fSjohnjiang
16934418919fSjohnjiang static uint32_t
test_hash_jhash_2word(const void * key,uint32_t length,uint32_t initval)16944418919fSjohnjiang test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
16954418919fSjohnjiang {
16964418919fSjohnjiang const uint32_t *k = key;
16974418919fSjohnjiang
16984418919fSjohnjiang RTE_SET_USED(length);
16994418919fSjohnjiang
17004418919fSjohnjiang return rte_jhash_2words(k[0], k[1], initval);
17014418919fSjohnjiang }
17024418919fSjohnjiang
17034418919fSjohnjiang static uint32_t
test_hash_jhash_3word(const void * key,uint32_t length,uint32_t initval)17044418919fSjohnjiang test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
17054418919fSjohnjiang {
17064418919fSjohnjiang const uint32_t *k = key;
17074418919fSjohnjiang
17084418919fSjohnjiang RTE_SET_USED(length);
17094418919fSjohnjiang
17104418919fSjohnjiang return rte_jhash_3words(k[0], k[1], k[2], initval);
17114418919fSjohnjiang }
17124418919fSjohnjiang
17134418919fSjohnjiang /*
17144418919fSjohnjiang * add/delete key with jhash 1word
17154418919fSjohnjiang */
17164418919fSjohnjiang static int
test_hash_add_delete_jhash_1word(void)17174418919fSjohnjiang test_hash_add_delete_jhash_1word(void)
17184418919fSjohnjiang {
17194418919fSjohnjiang int ret = -1;
17204418919fSjohnjiang struct rte_hash *handle;
17214418919fSjohnjiang int32_t pos1, pos2;
17224418919fSjohnjiang
17234418919fSjohnjiang hash_params_ex.name = "hash_test_jhash_1word";
17244418919fSjohnjiang hash_params_ex.key_len = 4;
17254418919fSjohnjiang hash_params_ex.hash_func = test_hash_jhash_1word;
17264418919fSjohnjiang
17274418919fSjohnjiang handle = rte_hash_create(&hash_params_ex);
17284418919fSjohnjiang if (handle == NULL)
17294418919fSjohnjiang goto fail_jhash_1word;
17304418919fSjohnjiang
17314418919fSjohnjiang pos1 = rte_hash_add_key(handle, (void *)&key[0]);
17324418919fSjohnjiang if (pos1 < 0)
17334418919fSjohnjiang goto fail_jhash_1word;
17344418919fSjohnjiang
17354418919fSjohnjiang pos2 = rte_hash_del_key(handle, (void *)&key[0]);
17364418919fSjohnjiang if (pos2 < 0 || pos1 != pos2)
17374418919fSjohnjiang goto fail_jhash_1word;
17384418919fSjohnjiang
17394418919fSjohnjiang ret = 0;
17404418919fSjohnjiang
17414418919fSjohnjiang fail_jhash_1word:
17424418919fSjohnjiang if (handle != NULL)
17434418919fSjohnjiang rte_hash_free(handle);
17444418919fSjohnjiang
17454418919fSjohnjiang return ret;
17464418919fSjohnjiang }
17474418919fSjohnjiang
17484418919fSjohnjiang /*
17494418919fSjohnjiang * add/delete key with jhash 2word
17504418919fSjohnjiang */
17514418919fSjohnjiang static int
test_hash_add_delete_jhash_2word(void)17524418919fSjohnjiang test_hash_add_delete_jhash_2word(void)
17534418919fSjohnjiang {
17544418919fSjohnjiang int ret = -1;
17554418919fSjohnjiang struct rte_hash *handle;
17564418919fSjohnjiang int32_t pos1, pos2;
17574418919fSjohnjiang
17584418919fSjohnjiang hash_params_ex.name = "hash_test_jhash_2word";
17594418919fSjohnjiang hash_params_ex.key_len = 8;
17604418919fSjohnjiang hash_params_ex.hash_func = test_hash_jhash_2word;
17614418919fSjohnjiang
17624418919fSjohnjiang handle = rte_hash_create(&hash_params_ex);
17634418919fSjohnjiang if (handle == NULL)
17644418919fSjohnjiang goto fail_jhash_2word;
17654418919fSjohnjiang
17664418919fSjohnjiang pos1 = rte_hash_add_key(handle, (void *)&key[0]);
17674418919fSjohnjiang if (pos1 < 0)
17684418919fSjohnjiang goto fail_jhash_2word;
17694418919fSjohnjiang
17704418919fSjohnjiang pos2 = rte_hash_del_key(handle, (void *)&key[0]);
17714418919fSjohnjiang if (pos2 < 0 || pos1 != pos2)
17724418919fSjohnjiang goto fail_jhash_2word;
17734418919fSjohnjiang
17744418919fSjohnjiang ret = 0;
17754418919fSjohnjiang
17764418919fSjohnjiang fail_jhash_2word:
17774418919fSjohnjiang if (handle != NULL)
17784418919fSjohnjiang rte_hash_free(handle);
17794418919fSjohnjiang
17804418919fSjohnjiang return ret;
17814418919fSjohnjiang }
17824418919fSjohnjiang
17834418919fSjohnjiang /*
17844418919fSjohnjiang * add/delete key with jhash 3word
17854418919fSjohnjiang */
17864418919fSjohnjiang static int
test_hash_add_delete_jhash_3word(void)17874418919fSjohnjiang test_hash_add_delete_jhash_3word(void)
17884418919fSjohnjiang {
17894418919fSjohnjiang int ret = -1;
17904418919fSjohnjiang struct rte_hash *handle;
17914418919fSjohnjiang int32_t pos1, pos2;
17924418919fSjohnjiang
17934418919fSjohnjiang hash_params_ex.name = "hash_test_jhash_3word";
17944418919fSjohnjiang hash_params_ex.key_len = 12;
17954418919fSjohnjiang hash_params_ex.hash_func = test_hash_jhash_3word;
17964418919fSjohnjiang
17974418919fSjohnjiang handle = rte_hash_create(&hash_params_ex);
17984418919fSjohnjiang if (handle == NULL)
17994418919fSjohnjiang goto fail_jhash_3word;
18004418919fSjohnjiang
18014418919fSjohnjiang pos1 = rte_hash_add_key(handle, (void *)&key[0]);
18024418919fSjohnjiang if (pos1 < 0)
18034418919fSjohnjiang goto fail_jhash_3word;
18044418919fSjohnjiang
18054418919fSjohnjiang pos2 = rte_hash_del_key(handle, (void *)&key[0]);
18064418919fSjohnjiang if (pos2 < 0 || pos1 != pos2)
18074418919fSjohnjiang goto fail_jhash_3word;
18084418919fSjohnjiang
18094418919fSjohnjiang ret = 0;
18104418919fSjohnjiang
18114418919fSjohnjiang fail_jhash_3word:
18124418919fSjohnjiang if (handle != NULL)
18134418919fSjohnjiang rte_hash_free(handle);
18144418919fSjohnjiang
18154418919fSjohnjiang return ret;
18164418919fSjohnjiang }
18174418919fSjohnjiang
1818*2d9fd380Sjfb8856606 static struct rte_hash *g_handle;
1819*2d9fd380Sjfb8856606 static struct rte_rcu_qsbr *g_qsv;
1820*2d9fd380Sjfb8856606 static volatile uint8_t writer_done;
1821*2d9fd380Sjfb8856606 struct flow_key g_rand_keys[9];
1822*2d9fd380Sjfb8856606
1823*2d9fd380Sjfb8856606 /*
1824*2d9fd380Sjfb8856606 * rte_hash_rcu_qsbr_add positive and negative tests.
1825*2d9fd380Sjfb8856606 * - Add RCU QSBR variable to Hash
1826*2d9fd380Sjfb8856606 * - Add another RCU QSBR variable to Hash
1827*2d9fd380Sjfb8856606 * - Check returns
1828*2d9fd380Sjfb8856606 */
1829*2d9fd380Sjfb8856606 static int
test_hash_rcu_qsbr_add(void)1830*2d9fd380Sjfb8856606 test_hash_rcu_qsbr_add(void)
1831*2d9fd380Sjfb8856606 {
1832*2d9fd380Sjfb8856606 size_t sz;
1833*2d9fd380Sjfb8856606 struct rte_rcu_qsbr *qsv2 = NULL;
1834*2d9fd380Sjfb8856606 int32_t status;
1835*2d9fd380Sjfb8856606 struct rte_hash_rcu_config rcu_cfg = {0};
1836*2d9fd380Sjfb8856606 struct rte_hash_parameters params;
1837*2d9fd380Sjfb8856606
1838*2d9fd380Sjfb8856606 printf("\n# Running RCU QSBR add tests\n");
1839*2d9fd380Sjfb8856606 memcpy(¶ms, &ut_params, sizeof(params));
1840*2d9fd380Sjfb8856606 params.name = "test_hash_rcu_qsbr_add";
1841*2d9fd380Sjfb8856606 params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
1842*2d9fd380Sjfb8856606 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
1843*2d9fd380Sjfb8856606 g_handle = rte_hash_create(¶ms);
1844*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
1845*2d9fd380Sjfb8856606
1846*2d9fd380Sjfb8856606 /* Create RCU QSBR variable */
1847*2d9fd380Sjfb8856606 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
1848*2d9fd380Sjfb8856606 g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
1849*2d9fd380Sjfb8856606 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1850*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
1851*2d9fd380Sjfb8856606 "RCU QSBR variable creation failed");
1852*2d9fd380Sjfb8856606
1853*2d9fd380Sjfb8856606 status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
1854*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status != 0,
1855*2d9fd380Sjfb8856606 "RCU QSBR variable initialization failed");
1856*2d9fd380Sjfb8856606
1857*2d9fd380Sjfb8856606 rcu_cfg.v = g_qsv;
1858*2d9fd380Sjfb8856606 /* Invalid QSBR mode */
1859*2d9fd380Sjfb8856606 rcu_cfg.mode = 0xff;
1860*2d9fd380Sjfb8856606 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1861*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status == 0, "Invalid QSBR mode test failed");
1862*2d9fd380Sjfb8856606
1863*2d9fd380Sjfb8856606 rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
1864*2d9fd380Sjfb8856606 /* Attach RCU QSBR to hash table */
1865*2d9fd380Sjfb8856606 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1866*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status != 0,
1867*2d9fd380Sjfb8856606 "Attach RCU QSBR to hash table failed");
1868*2d9fd380Sjfb8856606
1869*2d9fd380Sjfb8856606 /* Create and attach another RCU QSBR to hash table */
1870*2d9fd380Sjfb8856606 qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
1871*2d9fd380Sjfb8856606 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1872*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(qsv2 == NULL,
1873*2d9fd380Sjfb8856606 "RCU QSBR variable creation failed");
1874*2d9fd380Sjfb8856606
1875*2d9fd380Sjfb8856606 rcu_cfg.v = qsv2;
1876*2d9fd380Sjfb8856606 rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
1877*2d9fd380Sjfb8856606 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1878*2d9fd380Sjfb8856606 rte_free(qsv2);
1879*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status == 0,
1880*2d9fd380Sjfb8856606 "Attach RCU QSBR to hash table succeeded where failure"
1881*2d9fd380Sjfb8856606 " is expected");
1882*2d9fd380Sjfb8856606
1883*2d9fd380Sjfb8856606 rte_hash_free(g_handle);
1884*2d9fd380Sjfb8856606 rte_free(g_qsv);
1885*2d9fd380Sjfb8856606
1886*2d9fd380Sjfb8856606 return 0;
1887*2d9fd380Sjfb8856606 }
1888*2d9fd380Sjfb8856606
1889*2d9fd380Sjfb8856606 /*
1890*2d9fd380Sjfb8856606 * rte_hash_rcu_qsbr_add DQ mode functional test.
1891*2d9fd380Sjfb8856606 * Reader and writer are in the same thread in this test.
1892*2d9fd380Sjfb8856606 * - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
1893*2d9fd380Sjfb8856606 * - Add RCU QSBR variable to hash
1894*2d9fd380Sjfb8856606 * - Add 8 hash entries and fill the bucket
1895*2d9fd380Sjfb8856606 * - If ext bkt is enabled, add 1 extra entry that is available in the ext bkt
1896*2d9fd380Sjfb8856606 * - Register a reader thread (not a real thread)
1897*2d9fd380Sjfb8856606 * - Reader lookup existing entry
1898*2d9fd380Sjfb8856606 * - Writer deletes the entry
1899*2d9fd380Sjfb8856606 * - Reader lookup the entry
1900*2d9fd380Sjfb8856606 * - Writer re-add the entry (no available free index)
1901*2d9fd380Sjfb8856606 * - Reader report quiescent state and unregister
1902*2d9fd380Sjfb8856606 * - Writer re-add the entry
1903*2d9fd380Sjfb8856606 * - Reader lookup the entry
1904*2d9fd380Sjfb8856606 */
1905*2d9fd380Sjfb8856606 static int
test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt)1906*2d9fd380Sjfb8856606 test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt)
1907*2d9fd380Sjfb8856606 {
1908*2d9fd380Sjfb8856606 uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
1909*2d9fd380Sjfb8856606
1910*2d9fd380Sjfb8856606 uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
1911*2d9fd380Sjfb8856606
1912*2d9fd380Sjfb8856606 if (ext_bkt)
1913*2d9fd380Sjfb8856606 hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1914*2d9fd380Sjfb8856606
1915*2d9fd380Sjfb8856606 struct rte_hash_parameters params_pseudo_hash = {
1916*2d9fd380Sjfb8856606 .name = "test_hash_rcu_qsbr_dq_mode",
1917*2d9fd380Sjfb8856606 .entries = total_entries,
1918*2d9fd380Sjfb8856606 .key_len = sizeof(struct flow_key), /* 13 */
1919*2d9fd380Sjfb8856606 .hash_func = pseudo_hash,
1920*2d9fd380Sjfb8856606 .hash_func_init_val = 0,
1921*2d9fd380Sjfb8856606 .socket_id = 0,
1922*2d9fd380Sjfb8856606 .extra_flag = hash_extra_flag,
1923*2d9fd380Sjfb8856606 };
1924*2d9fd380Sjfb8856606 int pos[total_entries];
1925*2d9fd380Sjfb8856606 int expected_pos[total_entries];
1926*2d9fd380Sjfb8856606 unsigned int i;
1927*2d9fd380Sjfb8856606 size_t sz;
1928*2d9fd380Sjfb8856606 int32_t status;
1929*2d9fd380Sjfb8856606 struct rte_hash_rcu_config rcu_cfg = {0};
1930*2d9fd380Sjfb8856606
1931*2d9fd380Sjfb8856606 g_qsv = NULL;
1932*2d9fd380Sjfb8856606 g_handle = NULL;
1933*2d9fd380Sjfb8856606
1934*2d9fd380Sjfb8856606 for (i = 0; i < total_entries; i++) {
1935*2d9fd380Sjfb8856606 g_rand_keys[i].port_dst = i;
1936*2d9fd380Sjfb8856606 g_rand_keys[i].port_src = i+1;
1937*2d9fd380Sjfb8856606 }
1938*2d9fd380Sjfb8856606
1939*2d9fd380Sjfb8856606 if (ext_bkt)
1940*2d9fd380Sjfb8856606 printf("\n# Running RCU QSBR DQ mode functional test with"
1941*2d9fd380Sjfb8856606 " ext bkt\n");
1942*2d9fd380Sjfb8856606 else
1943*2d9fd380Sjfb8856606 printf("\n# Running RCU QSBR DQ mode functional test\n");
1944*2d9fd380Sjfb8856606
1945*2d9fd380Sjfb8856606 g_handle = rte_hash_create(¶ms_pseudo_hash);
1946*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
1947*2d9fd380Sjfb8856606
1948*2d9fd380Sjfb8856606 /* Create RCU QSBR variable */
1949*2d9fd380Sjfb8856606 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
1950*2d9fd380Sjfb8856606 g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
1951*2d9fd380Sjfb8856606 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1952*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
1953*2d9fd380Sjfb8856606 "RCU QSBR variable creation failed");
1954*2d9fd380Sjfb8856606
1955*2d9fd380Sjfb8856606 status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
1956*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status != 0,
1957*2d9fd380Sjfb8856606 "RCU QSBR variable initialization failed");
1958*2d9fd380Sjfb8856606
1959*2d9fd380Sjfb8856606 rcu_cfg.v = g_qsv;
1960*2d9fd380Sjfb8856606 rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
1961*2d9fd380Sjfb8856606 /* Attach RCU QSBR to hash table */
1962*2d9fd380Sjfb8856606 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1963*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status != 0,
1964*2d9fd380Sjfb8856606 "Attach RCU QSBR to hash table failed");
1965*2d9fd380Sjfb8856606
1966*2d9fd380Sjfb8856606 /* Fill bucket */
1967*2d9fd380Sjfb8856606 for (i = 0; i < total_entries; i++) {
1968*2d9fd380Sjfb8856606 pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
1969*2d9fd380Sjfb8856606 print_key_info("Add", &g_rand_keys[i], pos[i]);
1970*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
1971*2d9fd380Sjfb8856606 "failed to add key (pos[%u]=%d)", i,
1972*2d9fd380Sjfb8856606 pos[i]);
1973*2d9fd380Sjfb8856606 expected_pos[i] = pos[i];
1974*2d9fd380Sjfb8856606 }
1975*2d9fd380Sjfb8856606
1976*2d9fd380Sjfb8856606 /* Register pseudo reader */
1977*2d9fd380Sjfb8856606 status = rte_rcu_qsbr_thread_register(g_qsv, 0);
1978*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status != 0,
1979*2d9fd380Sjfb8856606 "RCU QSBR thread registration failed");
1980*2d9fd380Sjfb8856606 rte_rcu_qsbr_thread_online(g_qsv, 0);
1981*2d9fd380Sjfb8856606
1982*2d9fd380Sjfb8856606 /* Lookup */
1983*2d9fd380Sjfb8856606 pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
1984*2d9fd380Sjfb8856606 print_key_info("Lkp", &g_rand_keys[0], pos[0]);
1985*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
1986*2d9fd380Sjfb8856606 "failed to find correct key (pos[%u]=%d)", 0,
1987*2d9fd380Sjfb8856606 pos[0]);
1988*2d9fd380Sjfb8856606
1989*2d9fd380Sjfb8856606 /* Writer update */
1990*2d9fd380Sjfb8856606 pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
1991*2d9fd380Sjfb8856606 print_key_info("Del", &g_rand_keys[0], pos[0]);
1992*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
1993*2d9fd380Sjfb8856606 "failed to del correct key (pos[%u]=%d)", 0,
1994*2d9fd380Sjfb8856606 pos[0]);
1995*2d9fd380Sjfb8856606
1996*2d9fd380Sjfb8856606 /* Lookup */
1997*2d9fd380Sjfb8856606 pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
1998*2d9fd380Sjfb8856606 print_key_info("Lkp", &g_rand_keys[0], pos[0]);
1999*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOENT,
2000*2d9fd380Sjfb8856606 "found deleted key (pos[%u]=%d)", 0, pos[0]);
2001*2d9fd380Sjfb8856606
2002*2d9fd380Sjfb8856606 /* Fill bucket */
2003*2d9fd380Sjfb8856606 pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2004*2d9fd380Sjfb8856606 print_key_info("Add", &g_rand_keys[0], pos[0]);
2005*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOSPC,
2006*2d9fd380Sjfb8856606 "Added key successfully (pos[%u]=%d)", 0, pos[0]);
2007*2d9fd380Sjfb8856606
2008*2d9fd380Sjfb8856606 /* Reader quiescent */
2009*2d9fd380Sjfb8856606 rte_rcu_qsbr_quiescent(g_qsv, 0);
2010*2d9fd380Sjfb8856606
2011*2d9fd380Sjfb8856606 /* Fill bucket */
2012*2d9fd380Sjfb8856606 pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2013*2d9fd380Sjfb8856606 print_key_info("Add", &g_rand_keys[0], pos[0]);
2014*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2015*2d9fd380Sjfb8856606 "failed to add key (pos[%u]=%d)", 0, pos[0]);
2016*2d9fd380Sjfb8856606 expected_pos[0] = pos[0];
2017*2d9fd380Sjfb8856606
2018*2d9fd380Sjfb8856606 rte_rcu_qsbr_thread_offline(g_qsv, 0);
2019*2d9fd380Sjfb8856606 (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2020*2d9fd380Sjfb8856606
2021*2d9fd380Sjfb8856606 /* Lookup */
2022*2d9fd380Sjfb8856606 pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2023*2d9fd380Sjfb8856606 print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2024*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2025*2d9fd380Sjfb8856606 "failed to find correct key (pos[%u]=%d)", 0,
2026*2d9fd380Sjfb8856606 pos[0]);
2027*2d9fd380Sjfb8856606
2028*2d9fd380Sjfb8856606 rte_hash_free(g_handle);
2029*2d9fd380Sjfb8856606 rte_free(g_qsv);
2030*2d9fd380Sjfb8856606 return 0;
2031*2d9fd380Sjfb8856606
2032*2d9fd380Sjfb8856606 }
2033*2d9fd380Sjfb8856606
2034*2d9fd380Sjfb8856606 /* Report quiescent state interval every 1024 lookups. Larger critical
2035*2d9fd380Sjfb8856606 * sections in reader will result in writer polling multiple times.
2036*2d9fd380Sjfb8856606 */
2037*2d9fd380Sjfb8856606 #define QSBR_REPORTING_INTERVAL 1024
2038*2d9fd380Sjfb8856606 #define WRITER_ITERATIONS 512
2039*2d9fd380Sjfb8856606
2040*2d9fd380Sjfb8856606 /*
2041*2d9fd380Sjfb8856606 * Reader thread using rte_hash data structure with RCU.
2042*2d9fd380Sjfb8856606 */
2043*2d9fd380Sjfb8856606 static int
test_hash_rcu_qsbr_reader(void * arg)2044*2d9fd380Sjfb8856606 test_hash_rcu_qsbr_reader(void *arg)
2045*2d9fd380Sjfb8856606 {
2046*2d9fd380Sjfb8856606 int i;
2047*2d9fd380Sjfb8856606
2048*2d9fd380Sjfb8856606 RTE_SET_USED(arg);
2049*2d9fd380Sjfb8856606 /* Register this thread to report quiescent state */
2050*2d9fd380Sjfb8856606 (void)rte_rcu_qsbr_thread_register(g_qsv, 0);
2051*2d9fd380Sjfb8856606 rte_rcu_qsbr_thread_online(g_qsv, 0);
2052*2d9fd380Sjfb8856606
2053*2d9fd380Sjfb8856606 do {
2054*2d9fd380Sjfb8856606 for (i = 0; i < QSBR_REPORTING_INTERVAL; i++)
2055*2d9fd380Sjfb8856606 rte_hash_lookup(g_handle, &g_rand_keys[0]);
2056*2d9fd380Sjfb8856606
2057*2d9fd380Sjfb8856606 /* Update quiescent state */
2058*2d9fd380Sjfb8856606 rte_rcu_qsbr_quiescent(g_qsv, 0);
2059*2d9fd380Sjfb8856606 } while (!writer_done);
2060*2d9fd380Sjfb8856606
2061*2d9fd380Sjfb8856606 rte_rcu_qsbr_thread_offline(g_qsv, 0);
2062*2d9fd380Sjfb8856606 (void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2063*2d9fd380Sjfb8856606
2064*2d9fd380Sjfb8856606 return 0;
2065*2d9fd380Sjfb8856606 }
2066*2d9fd380Sjfb8856606
2067*2d9fd380Sjfb8856606 /*
2068*2d9fd380Sjfb8856606 * rte_hash_rcu_qsbr_add sync mode functional test.
2069*2d9fd380Sjfb8856606 * 1 Reader and 1 writer. They cannot be in the same thread in this test.
2070*2d9fd380Sjfb8856606 * - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
2071*2d9fd380Sjfb8856606 * - Add RCU QSBR variable to hash
2072*2d9fd380Sjfb8856606 * - Register a reader thread. Reader keeps looking up a specific key.
2073*2d9fd380Sjfb8856606 * - Writer keeps adding and deleting a specific key.
2074*2d9fd380Sjfb8856606 */
2075*2d9fd380Sjfb8856606 static int
test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt)2076*2d9fd380Sjfb8856606 test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt)
2077*2d9fd380Sjfb8856606 {
2078*2d9fd380Sjfb8856606 uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
2079*2d9fd380Sjfb8856606
2080*2d9fd380Sjfb8856606 uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2081*2d9fd380Sjfb8856606
2082*2d9fd380Sjfb8856606 if (ext_bkt)
2083*2d9fd380Sjfb8856606 hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
2084*2d9fd380Sjfb8856606
2085*2d9fd380Sjfb8856606 struct rte_hash_parameters params_pseudo_hash = {
2086*2d9fd380Sjfb8856606 .name = "test_hash_rcu_qsbr_sync_mode",
2087*2d9fd380Sjfb8856606 .entries = total_entries,
2088*2d9fd380Sjfb8856606 .key_len = sizeof(struct flow_key), /* 13 */
2089*2d9fd380Sjfb8856606 .hash_func = pseudo_hash,
2090*2d9fd380Sjfb8856606 .hash_func_init_val = 0,
2091*2d9fd380Sjfb8856606 .socket_id = 0,
2092*2d9fd380Sjfb8856606 .extra_flag = hash_extra_flag,
2093*2d9fd380Sjfb8856606 };
2094*2d9fd380Sjfb8856606 int pos[total_entries];
2095*2d9fd380Sjfb8856606 int expected_pos[total_entries];
2096*2d9fd380Sjfb8856606 unsigned int i;
2097*2d9fd380Sjfb8856606 size_t sz;
2098*2d9fd380Sjfb8856606 int32_t status;
2099*2d9fd380Sjfb8856606 struct rte_hash_rcu_config rcu_cfg = {0};
2100*2d9fd380Sjfb8856606
2101*2d9fd380Sjfb8856606 g_qsv = NULL;
2102*2d9fd380Sjfb8856606 g_handle = NULL;
2103*2d9fd380Sjfb8856606
2104*2d9fd380Sjfb8856606 for (i = 0; i < total_entries; i++) {
2105*2d9fd380Sjfb8856606 g_rand_keys[i].port_dst = i;
2106*2d9fd380Sjfb8856606 g_rand_keys[i].port_src = i+1;
2107*2d9fd380Sjfb8856606 }
2108*2d9fd380Sjfb8856606
2109*2d9fd380Sjfb8856606 if (ext_bkt)
2110*2d9fd380Sjfb8856606 printf("\n# Running RCU QSBR sync mode functional test with"
2111*2d9fd380Sjfb8856606 " ext bkt\n");
2112*2d9fd380Sjfb8856606 else
2113*2d9fd380Sjfb8856606 printf("\n# Running RCU QSBR sync mode functional test\n");
2114*2d9fd380Sjfb8856606
2115*2d9fd380Sjfb8856606 g_handle = rte_hash_create(¶ms_pseudo_hash);
2116*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2117*2d9fd380Sjfb8856606
2118*2d9fd380Sjfb8856606 /* Create RCU QSBR variable */
2119*2d9fd380Sjfb8856606 sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2120*2d9fd380Sjfb8856606 g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2121*2d9fd380Sjfb8856606 RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2122*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2123*2d9fd380Sjfb8856606 "RCU QSBR variable creation failed");
2124*2d9fd380Sjfb8856606
2125*2d9fd380Sjfb8856606 status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2126*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status != 0,
2127*2d9fd380Sjfb8856606 "RCU QSBR variable initialization failed");
2128*2d9fd380Sjfb8856606
2129*2d9fd380Sjfb8856606 rcu_cfg.v = g_qsv;
2130*2d9fd380Sjfb8856606 rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
2131*2d9fd380Sjfb8856606 /* Attach RCU QSBR to hash table */
2132*2d9fd380Sjfb8856606 status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2133*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(status != 0,
2134*2d9fd380Sjfb8856606 "Attach RCU QSBR to hash table failed");
2135*2d9fd380Sjfb8856606
2136*2d9fd380Sjfb8856606 /* Launch reader thread */
2137*2d9fd380Sjfb8856606 rte_eal_remote_launch(test_hash_rcu_qsbr_reader, NULL,
2138*2d9fd380Sjfb8856606 rte_get_next_lcore(-1, 1, 0));
2139*2d9fd380Sjfb8856606
2140*2d9fd380Sjfb8856606 /* Fill bucket */
2141*2d9fd380Sjfb8856606 for (i = 0; i < total_entries; i++) {
2142*2d9fd380Sjfb8856606 pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
2143*2d9fd380Sjfb8856606 print_key_info("Add", &g_rand_keys[i], pos[i]);
2144*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
2145*2d9fd380Sjfb8856606 "failed to add key (pos[%u]=%d)", i, pos[i]);
2146*2d9fd380Sjfb8856606 expected_pos[i] = pos[i];
2147*2d9fd380Sjfb8856606 }
2148*2d9fd380Sjfb8856606 writer_done = 0;
2149*2d9fd380Sjfb8856606
2150*2d9fd380Sjfb8856606 /* Writer Update */
2151*2d9fd380Sjfb8856606 for (i = 0; i < WRITER_ITERATIONS; i++) {
2152*2d9fd380Sjfb8856606 expected_pos[0] = pos[0];
2153*2d9fd380Sjfb8856606 pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
2154*2d9fd380Sjfb8856606 print_key_info("Del", &g_rand_keys[0], status);
2155*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2156*2d9fd380Sjfb8856606 "failed to del correct key (pos[%u]=%d)"
2157*2d9fd380Sjfb8856606 , 0, pos[0]);
2158*2d9fd380Sjfb8856606
2159*2d9fd380Sjfb8856606 pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2160*2d9fd380Sjfb8856606 print_key_info("Add", &g_rand_keys[0], pos[0]);
2161*2d9fd380Sjfb8856606 RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2162*2d9fd380Sjfb8856606 "failed to add key (pos[%u]=%d)", 0,
2163*2d9fd380Sjfb8856606 pos[0]);
2164*2d9fd380Sjfb8856606 }
2165*2d9fd380Sjfb8856606
2166*2d9fd380Sjfb8856606 writer_done = 1;
2167*2d9fd380Sjfb8856606 /* Wait until reader exited. */
2168*2d9fd380Sjfb8856606 rte_eal_mp_wait_lcore();
2169*2d9fd380Sjfb8856606
2170*2d9fd380Sjfb8856606 rte_hash_free(g_handle);
2171*2d9fd380Sjfb8856606 rte_free(g_qsv);
2172*2d9fd380Sjfb8856606
2173*2d9fd380Sjfb8856606 return 0;
2174*2d9fd380Sjfb8856606
2175*2d9fd380Sjfb8856606 }
2176*2d9fd380Sjfb8856606
21774418919fSjohnjiang /*
21784418919fSjohnjiang * Do all unit and performance tests.
21794418919fSjohnjiang */
21804418919fSjohnjiang static int
test_hash(void)21814418919fSjohnjiang test_hash(void)
21824418919fSjohnjiang {
21834418919fSjohnjiang if (test_add_delete() < 0)
21844418919fSjohnjiang return -1;
21854418919fSjohnjiang if (test_hash_add_delete_jhash2() < 0)
21864418919fSjohnjiang return -1;
21874418919fSjohnjiang if (test_hash_add_delete_2_jhash2() < 0)
21884418919fSjohnjiang return -1;
21894418919fSjohnjiang if (test_hash_add_delete_jhash_1word() < 0)
21904418919fSjohnjiang return -1;
21914418919fSjohnjiang if (test_hash_add_delete_jhash_2word() < 0)
21924418919fSjohnjiang return -1;
21934418919fSjohnjiang if (test_hash_add_delete_jhash_3word() < 0)
21944418919fSjohnjiang return -1;
21954418919fSjohnjiang if (test_hash_get_key_with_position() < 0)
21964418919fSjohnjiang return -1;
21974418919fSjohnjiang if (test_hash_find_existing() < 0)
21984418919fSjohnjiang return -1;
21994418919fSjohnjiang if (test_add_update_delete() < 0)
22004418919fSjohnjiang return -1;
22014418919fSjohnjiang if (test_add_update_delete_free() < 0)
22024418919fSjohnjiang return -1;
22034418919fSjohnjiang if (test_add_delete_free_lf() < 0)
22044418919fSjohnjiang return -1;
22054418919fSjohnjiang if (test_five_keys() < 0)
22064418919fSjohnjiang return -1;
22074418919fSjohnjiang if (test_full_bucket() < 0)
22084418919fSjohnjiang return -1;
22094418919fSjohnjiang if (test_extendable_bucket() < 0)
22104418919fSjohnjiang return -1;
22114418919fSjohnjiang
22124418919fSjohnjiang if (test_fbk_hash_find_existing() < 0)
22134418919fSjohnjiang return -1;
22144418919fSjohnjiang if (fbk_hash_unit_test() < 0)
22154418919fSjohnjiang return -1;
22164418919fSjohnjiang if (test_hash_creation_with_bad_parameters() < 0)
22174418919fSjohnjiang return -1;
22184418919fSjohnjiang if (test_hash_creation_with_good_parameters() < 0)
22194418919fSjohnjiang return -1;
22204418919fSjohnjiang
22214418919fSjohnjiang /* ext table disabled */
22224418919fSjohnjiang if (test_average_table_utilization(0) < 0)
22234418919fSjohnjiang return -1;
22244418919fSjohnjiang if (test_hash_iteration(0) < 0)
22254418919fSjohnjiang return -1;
22264418919fSjohnjiang
22274418919fSjohnjiang /* ext table enabled */
22284418919fSjohnjiang if (test_average_table_utilization(1) < 0)
22294418919fSjohnjiang return -1;
22304418919fSjohnjiang if (test_hash_iteration(1) < 0)
22314418919fSjohnjiang return -1;
22324418919fSjohnjiang
22334418919fSjohnjiang run_hash_func_tests();
22344418919fSjohnjiang
22354418919fSjohnjiang if (test_crc32_hash_alg_equiv() < 0)
22364418919fSjohnjiang return -1;
22374418919fSjohnjiang
2238*2d9fd380Sjfb8856606 if (test_hash_rcu_qsbr_add() < 0)
2239*2d9fd380Sjfb8856606 return -1;
2240*2d9fd380Sjfb8856606
2241*2d9fd380Sjfb8856606 if (test_hash_rcu_qsbr_dq_mode(0) < 0)
2242*2d9fd380Sjfb8856606 return -1;
2243*2d9fd380Sjfb8856606
2244*2d9fd380Sjfb8856606 if (test_hash_rcu_qsbr_dq_mode(1) < 0)
2245*2d9fd380Sjfb8856606 return -1;
2246*2d9fd380Sjfb8856606
2247*2d9fd380Sjfb8856606 if (test_hash_rcu_qsbr_sync_mode(0) < 0)
2248*2d9fd380Sjfb8856606 return -1;
2249*2d9fd380Sjfb8856606
2250*2d9fd380Sjfb8856606 if (test_hash_rcu_qsbr_sync_mode(1) < 0)
2251*2d9fd380Sjfb8856606 return -1;
2252*2d9fd380Sjfb8856606
22534418919fSjohnjiang return 0;
22544418919fSjohnjiang }
22554418919fSjohnjiang
22564418919fSjohnjiang REGISTER_TEST_COMMAND(hash_autotest, test_hash);
2257