197f17497SC.J. Collier/*-
297f17497SC.J. Collier *   BSD LICENSE
397f17497SC.J. Collier *
497f17497SC.J. Collier *   Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
597f17497SC.J. Collier *   All rights reserved.
697f17497SC.J. Collier *
797f17497SC.J. Collier *   Redistribution and use in source and binary forms, with or without
897f17497SC.J. Collier *   modification, are permitted provided that the following conditions
997f17497SC.J. Collier *   are met:
1097f17497SC.J. Collier *
1197f17497SC.J. Collier *     * Redistributions of source code must retain the above copyright
1297f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer.
1397f17497SC.J. Collier *     * Redistributions in binary form must reproduce the above copyright
1497f17497SC.J. Collier *       notice, this list of conditions and the following disclaimer in
1597f17497SC.J. Collier *       the documentation and/or other materials provided with the
1697f17497SC.J. Collier *       distribution.
1797f17497SC.J. Collier *     * Neither the name of Intel Corporation nor the names of its
1897f17497SC.J. Collier *       contributors may be used to endorse or promote products derived
1997f17497SC.J. Collier *       from this software without specific prior written permission.
2097f17497SC.J. Collier *
2197f17497SC.J. Collier *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2297f17497SC.J. Collier *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2397f17497SC.J. Collier *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2497f17497SC.J. Collier *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2597f17497SC.J. Collier *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2697f17497SC.J. Collier *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2797f17497SC.J. Collier *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2897f17497SC.J. Collier *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2997f17497SC.J. Collier *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3097f17497SC.J. Collier *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3197f17497SC.J. Collier *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3297f17497SC.J. Collier */
3397f17497SC.J. Collier
3497f17497SC.J. Collier#include <stdio.h>
3597f17497SC.J. Collier#include <stdint.h>
3697f17497SC.J. Collier#include <string.h>
3797f17497SC.J. Collier#include <stdlib.h>
3897f17497SC.J. Collier#include <stdarg.h>
3997f17497SC.J. Collier#include <errno.h>
4097f17497SC.J. Collier#include <sys/queue.h>
4197f17497SC.J. Collier
4297f17497SC.J. Collier#include <rte_common.h>
4397f17497SC.J. Collier#include <rte_malloc.h>
4497f17497SC.J. Collier#include <rte_cycles.h>
4597f17497SC.J. Collier#include <rte_random.h>
4697f17497SC.J. Collier#include <rte_memory.h>
4797f17497SC.J. Collier#include <rte_memzone.h>
4897f17497SC.J. Collier#include <rte_eal.h>
4997f17497SC.J. Collier#include <rte_ip.h>
5097f17497SC.J. Collier#include <rte_string_fns.h>
5197f17497SC.J. Collier
5297f17497SC.J. Collier#include "test.h"
5397f17497SC.J. Collier
5497f17497SC.J. Collier#include <rte_hash.h>
5597f17497SC.J. Collier#include <rte_fbk_hash.h>
5697f17497SC.J. Collier#include <rte_jhash.h>
5797f17497SC.J. Collier#include <rte_hash_crc.h>
5897f17497SC.J. Collier
5997f17497SC.J. Collier/*******************************************************************************
6097f17497SC.J. Collier * Hash function performance test configuration section. Each performance test
6197f17497SC.J. Collier * will be performed HASHTEST_ITERATIONS times.
6297f17497SC.J. Collier *
6397f17497SC.J. Collier * The five arrays below control what tests are performed. Every combination
6497f17497SC.J. Collier * from the array entries is tested.
6597f17497SC.J. Collier */
6697f17497SC.J. Collierstatic rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
6797f17497SC.J. Collierstatic uint32_t hashtest_initvals[] = {0};
6897f17497SC.J. Collierstatic uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64};
6997f17497SC.J. Collier#define MAX_KEYSIZE 64
7097f17497SC.J. Collier/******************************************************************************/
7197f17497SC.J. Collier#define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
7297f17497SC.J. Collier
7397f17497SC.J. Collier/*
7497f17497SC.J. Collier * Check condition and return an error if true. Assumes that "handle" is the
7597f17497SC.J. Collier * name of the hash structure pointer to be freed.
7697f17497SC.J. Collier */
7797f17497SC.J. Collier#define RETURN_IF_ERROR(cond, str, ...) do {				\
7897f17497SC.J. Collier	if (cond) {							\
7997f17497SC.J. Collier		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
8097f17497SC.J. Collier		if (handle) rte_hash_free(handle);			\
8197f17497SC.J. Collier		return -1;						\
8297f17497SC.J. Collier	}								\
8397f17497SC.J. Collier} while(0)
8497f17497SC.J. Collier
8597f17497SC.J. Collier#define RETURN_IF_ERROR_FBK(cond, str, ...) do {				\
8697f17497SC.J. Collier	if (cond) {							\
8797f17497SC.J. Collier		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
8897f17497SC.J. Collier		if (handle) rte_fbk_hash_free(handle);			\
8997f17497SC.J. Collier		return -1;						\
9097f17497SC.J. Collier	}								\
9197f17497SC.J. Collier} while(0)
9297f17497SC.J. Collier
9397f17497SC.J. Collier/* 5-tuple key type */
9497f17497SC.J. Collierstruct flow_key {
9597f17497SC.J. Collier	uint32_t ip_src;
9697f17497SC.J. Collier	uint32_t ip_dst;
9797f17497SC.J. Collier	uint16_t port_src;
9897f17497SC.J. Collier	uint16_t port_dst;
9997f17497SC.J. Collier	uint8_t proto;
10097f17497SC.J. Collier} __attribute__((packed));
10197f17497SC.J. Collier
10297f17497SC.J. Collier/*
10397f17497SC.J. Collier * Hash function that always returns the same value, to easily test what
10497f17497SC.J. Collier * happens when a bucket is full.
10597f17497SC.J. Collier */
10697f17497SC.J. Collierstatic uint32_t pseudo_hash(__attribute__((unused)) const void *keys,
10797f17497SC.J. Collier			    __attribute__((unused)) uint32_t key_len,
10897f17497SC.J. Collier			    __attribute__((unused)) uint32_t init_val)
10997f17497SC.J. Collier{
11097f17497SC.J. Collier	return 3;
11197f17497SC.J. Collier}
11297f17497SC.J. Collier
113f7a9461eSLuca Boccassi#define UNIT_TEST_HASH_VERBOSE	0
11497f17497SC.J. Collier/*
11597f17497SC.J. Collier * Print out result of unit test hash operation.
11697f17497SC.J. Collier */
11797f17497SC.J. Collierstatic void print_key_info(const char *msg, const struct flow_key *key,
11897f17497SC.J. Collier								int32_t pos)
11997f17497SC.J. Collier{
120f7a9461eSLuca Boccassi	if (UNIT_TEST_HASH_VERBOSE) {
121f7a9461eSLuca Boccassi		const uint8_t *p = (const uint8_t *)key;
122f7a9461eSLuca Boccassi		unsigned int i;
12397f17497SC.J. Collier
124f7a9461eSLuca Boccassi		printf("%s key:0x", msg);
125f7a9461eSLuca Boccassi		for (i = 0; i < sizeof(struct flow_key); i++)
126f7a9461eSLuca Boccassi			printf("%02X", p[i]);
127f7a9461eSLuca Boccassi		printf(" @ pos %d\n", pos);
12897f17497SC.J. Collier	}
12997f17497SC.J. Collier}
13097f17497SC.J. Collier
13197f17497SC.J. Collier/* Keys used by unit test functions */
13297f17497SC.J. Collierstatic struct flow_key keys[5] = { {
13397f17497SC.J. Collier	.ip_src = IPv4(0x03, 0x02, 0x01, 0x00),
13497f17497SC.J. Collier	.ip_dst = IPv4(0x07, 0x06, 0x05, 0x04),
13597f17497SC.J. Collier	.port_src = 0x0908,
13697f17497SC.J. Collier	.port_dst = 0x0b0a,
13797f17497SC.J. Collier	.proto = 0x0c,
13897f17497SC.J. Collier}, {
13997f17497SC.J. Collier	.ip_src = IPv4(0x13, 0x12, 0x11, 0x10),
14097f17497SC.J. Collier	.ip_dst = IPv4(0x17, 0x16, 0x15, 0x14),
14197f17497SC.J. Collier	.port_src = 0x1918,
14297f17497SC.J. Collier	.port_dst = 0x1b1a,
14397f17497SC.J. Collier	.proto = 0x1c,
14497f17497SC.J. Collier}, {
14597f17497SC.J. Collier	.ip_src = IPv4(0x23, 0x22, 0x21, 0x20),
14697f17497SC.J. Collier	.ip_dst = IPv4(0x27, 0x26, 0x25, 0x24),
14797f17497SC.J. Collier	.port_src = 0x2928,
14897f17497SC.J. Collier	.port_dst = 0x2b2a,
14997f17497SC.J. Collier	.proto = 0x2c,
15097f17497SC.J. Collier}, {
15197f17497SC.J. Collier	.ip_src = IPv4(0x33, 0x32, 0x31, 0x30),
15297f17497SC.J. Collier	.ip_dst = IPv4(0x37, 0x36, 0x35, 0x34),
15397f17497SC.J. Collier	.port_src = 0x3938,
15497f17497SC.J. Collier	.port_dst = 0x3b3a,
15597f17497SC.J. Collier	.proto = 0x3c,
15697f17497SC.J. Collier}, {
15797f17497SC.J. Collier	.ip_src = IPv4(0x43, 0x42, 0x41, 0x40),
15897f17497SC.J. Collier	.ip_dst = IPv4(0x47, 0x46, 0x45, 0x44),
15997f17497SC.J. Collier	.port_src = 0x4948,
16097f17497SC.J. Collier	.port_dst = 0x4b4a,
16197f17497SC.J. Collier	.proto = 0x4c,
16297f17497SC.J. Collier} };
16397f17497SC.J. Collier
16497f17497SC.J. Collier/* Parameters used for hash table in unit test functions. Name set later. */
16597f17497SC.J. Collierstatic struct rte_hash_parameters ut_params = {
16697f17497SC.J. Collier	.entries = 64,
16797f17497SC.J. Collier	.key_len = sizeof(struct flow_key), /* 13 */
16897f17497SC.J. Collier	.hash_func = rte_jhash,
16997f17497SC.J. Collier	.hash_func_init_val = 0,
17097f17497SC.J. Collier	.socket_id = 0,
17197f17497SC.J. Collier};
17297f17497SC.J. Collier
1738b25d1adSChristian Ehrhardt#define CRC32_ITERATIONS (1U << 10)
17497f17497SC.J. Collier#define CRC32_DWORDS (1U << 6)
17597f17497SC.J. Collier/*
17697f17497SC.J. Collier * Test if all CRC32 implementations yield the same hash value
17797f17497SC.J. Collier */
17897f17497SC.J. Collierstatic int
17997f17497SC.J. Colliertest_crc32_hash_alg_equiv(void)
18097f17497SC.J. Collier{
18197f17497SC.J. Collier	uint32_t hash_val;
18297f17497SC.J. Collier	uint32_t init_val;
18397f17497SC.J. Collier	uint64_t data64[CRC32_DWORDS];
18497f17497SC.J. Collier	unsigned i, j;
18597f17497SC.J. Collier	size_t data_len;
18697f17497SC.J. Collier
18797f17497SC.J. Collier	printf("\n# CRC32 implementations equivalence test\n");
18897f17497SC.J. Collier	for (i = 0; i < CRC32_ITERATIONS; i++) {
18997f17497SC.J. Collier		/* Randomizing data_len of data set */
19097f17497SC.J. Collier		data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
19197f17497SC.J. Collier		init_val = (uint32_t) rte_rand();
19297f17497SC.J. Collier
19397f17497SC.J. Collier		/* Fill the data set */
19497f17497SC.J. Collier		for (j = 0; j < CRC32_DWORDS; j++)
19597f17497SC.J. Collier			data64[j] = rte_rand();
19697f17497SC.J. Collier
19797f17497SC.J. Collier		/* Calculate software CRC32 */
19897f17497SC.J. Collier		rte_hash_crc_set_alg(CRC32_SW);
19997f17497SC.J. Collier		hash_val = rte_hash_crc(data64, data_len, init_val);
20097f17497SC.J. Collier
20197f17497SC.J. Collier		/* Check against 4-byte-operand sse4.2 CRC32 if available */
20297f17497SC.J. Collier		rte_hash_crc_set_alg(CRC32_SSE42);
20397f17497SC.J. Collier		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
20497f17497SC.J. Collier			printf("Failed checking CRC32_SW against CRC32_SSE42\n");
20597f17497SC.J. Collier			break;
20697f17497SC.J. Collier		}
20797f17497SC.J. Collier
20897f17497SC.J. Collier		/* Check against 8-byte-operand sse4.2 CRC32 if available */
20997f17497SC.J. Collier		rte_hash_crc_set_alg(CRC32_SSE42_x64);
21097f17497SC.J. Collier		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
21197f17497SC.J. Collier			printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
21297f17497SC.J. Collier			break;
21397f17497SC.J. Collier		}
21497f17497SC.J. Collier
21597f17497SC.J. Collier		/* Check against 8-byte-operand ARM64 CRC32 if available */
21697f17497SC.J. Collier		rte_hash_crc_set_alg(CRC32_ARM64);
21797f17497SC.J. Collier		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
21897f17497SC.J. Collier			printf("Failed checking CRC32_SW against CRC32_ARM64\n");
21997f17497SC.J. Collier			break;
22097f17497SC.J. Collier		}
22197f17497SC.J. Collier	}
22297f17497SC.J. Collier
22397f17497SC.J. Collier	/* Resetting to best available algorithm */
22497f17497SC.J. Collier	rte_hash_crc_set_alg(CRC32_SSE42_x64);
22597f17497SC.J. Collier
22697f17497SC.J. Collier	if (i == CRC32_ITERATIONS)
22797f17497SC.J. Collier		return 0;
22897f17497SC.J. Collier
22997f17497SC.J. Collier	printf("Failed test data (hex, %zu bytes total):\n", data_len);
23097f17497SC.J. Collier	for (j = 0; j < data_len; j++)
23197f17497SC.J. Collier		printf("%02X%c", ((uint8_t *)data64)[j],
23297f17497SC.J. Collier				((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
23397f17497SC.J. Collier
23497f17497SC.J. Collier	return -1;
23597f17497SC.J. Collier}
23697f17497SC.J. Collier
23797f17497SC.J. Collier/*
23897f17497SC.J. Collier * Test a hash function.
23997f17497SC.J. Collier */
24097f17497SC.J. Collierstatic void run_hash_func_test(rte_hash_function f, uint32_t init_val,
24197f17497SC.J. Collier		uint32_t key_len)
24297f17497SC.J. Collier{
24397f17497SC.J. Collier	static uint8_t key[MAX_KEYSIZE];
24497f17497SC.J. Collier	unsigned i;
24597f17497SC.J. Collier
24697f17497SC.J. Collier
24797f17497SC.J. Collier	for (i = 0; i < key_len; i++)
24897f17497SC.J. Collier		key[i] = (uint8_t) rte_rand();
24997f17497SC.J. Collier
25097f17497SC.J. Collier	/* just to be on the safe side */
25197f17497SC.J. Collier	if (!f)
25297f17497SC.J. Collier		return;
25397f17497SC.J. Collier
25497f17497SC.J. Collier	f(key, key_len, init_val);
25597f17497SC.J. Collier}
25697f17497SC.J. Collier
25797f17497SC.J. Collier/*
25897f17497SC.J. Collier * Test all hash functions.
25997f17497SC.J. Collier */
26097f17497SC.J. Collierstatic void run_hash_func_tests(void)
26197f17497SC.J. Collier{
26297f17497SC.J. Collier	unsigned i, j, k;
26397f17497SC.J. Collier
26497f17497SC.J. Collier	for (i = 0;
26597f17497SC.J. Collier	     i < sizeof(hashtest_funcs) / sizeof(rte_hash_function);
26697f17497SC.J. Collier	     i++) {
26797f17497SC.J. Collier		for (j = 0;
26897f17497SC.J. Collier		     j < sizeof(hashtest_initvals) / sizeof(uint32_t);
26997f17497SC.J. Collier		     j++) {
27097f17497SC.J. Collier			for (k = 0;
27197f17497SC.J. Collier			     k < sizeof(hashtest_key_lens) / sizeof(uint32_t);
27297f17497SC.J. Collier			     k++) {
27397f17497SC.J. Collier				run_hash_func_test(hashtest_funcs[i],
27497f17497SC.J. Collier						hashtest_initvals[j],
27597f17497SC.J. Collier						hashtest_key_lens[k]);
27697f17497SC.J. Collier			}
27797f17497SC.J. Collier		}
27897f17497SC.J. Collier	}
27997f17497SC.J. Collier}
28097f17497SC.J. Collier
28197f17497SC.J. Collier/*
28297f17497SC.J. Collier * Basic sequence of operations for a single key:
28397f17497SC.J. Collier *	- add
28497f17497SC.J. Collier *	- lookup (hit)
28597f17497SC.J. Collier *	- delete
28697f17497SC.J. Collier *	- lookup (miss)
28797f17497SC.J. Collier */
28897f17497SC.J. Collierstatic int test_add_delete(void)
28997f17497SC.J. Collier{
29097f17497SC.J. Collier	struct rte_hash *handle;
29197f17497SC.J. Collier	/* test with standard add/lookup/delete functions */
29297f17497SC.J. Collier	int pos0, expectedPos0;
29397f17497SC.J. Collier
29497f17497SC.J. Collier	ut_params.name = "test1";
29597f17497SC.J. Collier	handle = rte_hash_create(&ut_params);
29697f17497SC.J. Collier	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
29797f17497SC.J. Collier
29897f17497SC.J. Collier	pos0 = rte_hash_add_key(handle, &keys[0]);
29997f17497SC.J. Collier	print_key_info("Add", &keys[0], pos0);
30097f17497SC.J. Collier	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
30197f17497SC.J. Collier	expectedPos0 = pos0;
30297f17497SC.J. Collier
30397f17497SC.J. Collier	pos0 = rte_hash_lookup(handle, &keys[0]);
30497f17497SC.J. Collier	print_key_info("Lkp", &keys[0], pos0);
30597f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != expectedPos0,
30697f17497SC.J. Collier			"failed to find key (pos0=%d)", pos0);
30797f17497SC.J. Collier
30897f17497SC.J. Collier	pos0 = rte_hash_del_key(handle, &keys[0]);
30997f17497SC.J. Collier	print_key_info("Del", &keys[0], pos0);
31097f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != expectedPos0,
31197f17497SC.J. Collier			"failed to delete key (pos0=%d)", pos0);
31297f17497SC.J. Collier
31397f17497SC.J. Collier	pos0 = rte_hash_lookup(handle, &keys[0]);
31497f17497SC.J. Collier	print_key_info("Lkp", &keys[0], pos0);
31597f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != -ENOENT,
31697f17497SC.J. Collier			"fail: found key after deleting! (pos0=%d)", pos0);
31797f17497SC.J. Collier
31897f17497SC.J. Collier	rte_hash_free(handle);
31997f17497SC.J. Collier
32097f17497SC.J. Collier	/* repeat test with precomputed hash functions */
32197f17497SC.J. Collier	hash_sig_t hash_value;
32297f17497SC.J. Collier	int pos1, expectedPos1;
32397f17497SC.J. Collier
32497f17497SC.J. Collier	handle = rte_hash_create(&ut_params);
32597f17497SC.J. Collier	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
32697f17497SC.J. Collier
32797f17497SC.J. Collier	hash_value = rte_hash_hash(handle, &keys[0]);
32897f17497SC.J. Collier	pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
32997f17497SC.J. Collier	print_key_info("Add", &keys[0], pos1);
33097f17497SC.J. Collier	RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
33197f17497SC.J. Collier	expectedPos1 = pos1;
33297f17497SC.J. Collier
33397f17497SC.J. Collier	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
33497f17497SC.J. Collier	print_key_info("Lkp", &keys[0], pos1);
33597f17497SC.J. Collier	RETURN_IF_ERROR(pos1 != expectedPos1,
33697f17497SC.J. Collier			"failed to find key (pos1=%d)", pos1);
33797f17497SC.J. Collier
33897f17497SC.J. Collier	pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
33997f17497SC.J. Collier	print_key_info("Del", &keys[0], pos1);
34097f17497SC.J. Collier	RETURN_IF_ERROR(pos1 != expectedPos1,
34197f17497SC.J. Collier			"failed to delete key (pos1=%d)", pos1);
34297f17497SC.J. Collier
34397f17497SC.J. Collier	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
34497f17497SC.J. Collier	print_key_info("Lkp", &keys[0], pos1);
34597f17497SC.J. Collier	RETURN_IF_ERROR(pos1 != -ENOENT,
34697f17497SC.J. Collier			"fail: found key after deleting! (pos1=%d)", pos1);
34797f17497SC.J. Collier
34897f17497SC.J. Collier	rte_hash_free(handle);
34997f17497SC.J. Collier
35097f17497SC.J. Collier	return 0;
35197f17497SC.J. Collier}
35297f17497SC.J. Collier
35397f17497SC.J. Collier/*
35497f17497SC.J. Collier * Sequence of operations for a single key:
35597f17497SC.J. Collier *	- delete: miss
35697f17497SC.J. Collier *	- add
35797f17497SC.J. Collier *	- lookup: hit
35897f17497SC.J. Collier *	- add: update
35997f17497SC.J. Collier *	- lookup: hit (updated data)
36097f17497SC.J. Collier *	- delete: hit
36197f17497SC.J. Collier *	- delete: miss
36297f17497SC.J. Collier *	- lookup: miss
36397f17497SC.J. Collier */
36497f17497SC.J. Collierstatic int test_add_update_delete(void)
36597f17497SC.J. Collier{
36697f17497SC.J. Collier	struct rte_hash *handle;
36797f17497SC.J. Collier	int pos0, expectedPos0;
36897f17497SC.J. Collier
36997f17497SC.J. Collier	ut_params.name = "test2";
37097f17497SC.J. Collier	handle = rte_hash_create(&ut_params);
37197f17497SC.J. Collier	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
37297f17497SC.J. Collier
37397f17497SC.J. Collier	pos0 = rte_hash_del_key(handle, &keys[0]);
37497f17497SC.J. Collier	print_key_info("Del", &keys[0], pos0);
37597f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != -ENOENT,
37697f17497SC.J. Collier			"fail: found non-existent key (pos0=%d)", pos0);
37797f17497SC.J. Collier
37897f17497SC.J. Collier	pos0 = rte_hash_add_key(handle, &keys[0]);
37997f17497SC.J. Collier	print_key_info("Add", &keys[0], pos0);
38097f17497SC.J. Collier	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
38197f17497SC.J. Collier	expectedPos0 = pos0;
38297f17497SC.J. Collier
38397f17497SC.J. Collier	pos0 = rte_hash_lookup(handle, &keys[0]);
38497f17497SC.J. Collier	print_key_info("Lkp", &keys[0], pos0);
38597f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != expectedPos0,
38697f17497SC.J. Collier			"failed to find key (pos0=%d)", pos0);
38797f17497SC.J. Collier
38897f17497SC.J. Collier	pos0 = rte_hash_add_key(handle, &keys[0]);
38997f17497SC.J. Collier	print_key_info("Add", &keys[0], pos0);
39097f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != expectedPos0,
39197f17497SC.J. Collier			"failed to re-add key (pos0=%d)", pos0);
39297f17497SC.J. Collier
39397f17497SC.J. Collier	pos0 = rte_hash_lookup(handle, &keys[0]);
39497f17497SC.J. Collier	print_key_info("Lkp", &keys[0], pos0);
39597f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != expectedPos0,
39697f17497SC.J. Collier			"failed to find key (pos0=%d)", pos0);
39797f17497SC.J. Collier
39897f17497SC.J. Collier	pos0 = rte_hash_del_key(handle, &keys[0]);
39997f17497SC.J. Collier	print_key_info("Del", &keys[0], pos0);
40097f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != expectedPos0,
40197f17497SC.J. Collier			"failed to delete key (pos0=%d)", pos0);
40297f17497SC.J. Collier
40397f17497SC.J. Collier	pos0 = rte_hash_del_key(handle, &keys[0]);
40497f17497SC.J. Collier	print_key_info("Del", &keys[0], pos0);
40597f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != -ENOENT,
40697f17497SC.J. Collier			"fail: deleted already deleted key (pos0=%d)", pos0);
40797f17497SC.J. Collier
40897f17497SC.J. Collier	pos0 = rte_hash_lookup(handle, &keys[0]);
40997f17497SC.J. Collier	print_key_info("Lkp", &keys[0], pos0);
41097f17497SC.J. Collier	RETURN_IF_ERROR(pos0 != -ENOENT,
41197f17497SC.J. Collier			"fail: found key after deleting! (pos0=%d)", pos0);
41297f17497SC.J. Collier
41397f17497SC.J. Collier	rte_hash_free(handle);
41497f17497SC.J. Collier	return 0;
41597f17497SC.J. Collier}
41697f17497SC.J. Collier
417a41e6ff1SRicardo Salveti/*
418a41e6ff1SRicardo Salveti * Sequence of operations for retrieving a key with its position
419a41e6ff1SRicardo Salveti *
420a41e6ff1SRicardo Salveti *  - create table
421a41e6ff1SRicardo Salveti *  - add key
422a41e6ff1SRicardo Salveti *  - get the key with its position: hit
423a41e6ff1SRicardo Salveti *  - delete key
424a41e6ff1SRicardo Salveti *  - try to get the deleted key: miss
425a41e6ff1SRicardo Salveti *
426a41e6ff1SRicardo Salveti */
427a41e6ff1SRicardo Salvetistatic int test_hash_get_key_with_position(void)
428a41e6ff1SRicardo Salveti{
429a41e6ff1SRicardo Salveti	struct rte_hash *handle = NULL;
430a41e6ff1SRicardo Salveti	int pos, expectedPos, result;
431a41e6ff1SRicardo Salveti	void *key;
432a41e6ff1SRicardo Salveti
433a41e6ff1SRicardo Salveti	ut_params.name = "hash_get_key_w_pos";
434a41e6ff1SRicardo Salveti	handle = rte_hash_create(&ut_params);
435a41e6ff1SRicardo Salveti	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
436a41e6ff1SRicardo Salveti
437a41e6ff1SRicardo Salveti	pos = rte_hash_add_key(handle, &keys[0]);
438a41e6ff1SRicardo Salveti	print_key_info("Add", &keys[0], pos);
439a41e6ff1SRicardo Salveti	RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
440a41e6ff1SRicardo Salveti	expectedPos = pos;
441a41e6ff1SRicardo Salveti
442a41e6ff1SRicardo Salveti	result = rte_hash_get_key_with_position(handle, pos, &key);
443a41e6ff1SRicardo Salveti	RETURN_IF_ERROR(result != 0, "error retrieving a key");
444a41e6ff1SRicardo Salveti
445a41e6ff1SRicardo Salveti	pos = rte_hash_del_key(handle, &keys[0]);
446a41e6ff1SRicardo Salveti	print_key_info("Del", &keys[0], pos);
447a41e6ff1SRicardo Salveti	RETURN_IF_ERROR(pos != expectedPos,
448a41e6ff1SRicardo Salveti			"failed to delete key (pos0=%d)", pos);
449a41e6ff1SRicardo Salveti
450a41e6ff1SRicardo Salveti	result = rte_hash_get_key_with_position(handle, pos, &key);
451a41e6ff1SRicardo Salveti	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
452a41e6ff1SRicardo Salveti
453a41e6ff1SRicardo Salveti	rte_hash_free(handle);
454a41e6ff1SRicardo Salveti	return 0;
455a41e6ff1SRicardo Salveti}
456a41e6ff1SRicardo Salveti
45797f17497SC.J. Collier/*
45897f17497SC.J. Collier * Sequence of operations for find existing hash table
45997f17497SC.J. Collier *
46097f17497SC.J. Collier *  - create table
46197f17497SC.J. Collier *  - find existing table: hit
46297f17497SC.J. Collier *  - find non-existing table: miss
46397f17497SC.J. Collier *
46497f17497SC.J. Collier */
46597f17497SC.J. Collierstatic int test_hash_find_existing(void)
46697f17497SC.J. Collier{
46797f17497SC.J. Collier	struct rte_hash *handle = NULL, *result = NULL;
46897f17497SC.J. Collier
46997f17497SC.J. Collier	/* Create hash table. */
47097f17497SC.J. Collier	ut_params.name = "hash_find_existing";
47197f17497SC.J. Collier	handle = rte_hash_create(&ut_params);
47297f17497SC.J. Collier	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
47397f17497SC.J. Collier
47497f17497SC.J. Collier	/* Try to find existing hash table */
47597f17497SC.J. Collier	result = rte_hash_find_existing("hash_find_existing");
47697f17497SC.J. Collier	RETURN_IF_ERROR(result != handle, "could not find existing hash table");
47797f17497SC.J. Collier
47897f17497SC.J. Collier	/* Try to find non-existing hash table */
47997f17497SC.J. Collier	result = rte_hash_find_existing("hash_find_non_existing");
48097f17497SC.J. Collier	RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
48197f17497SC.J. Collier
48297f17497SC.J. Collier	/* Cleanup. */
48397f17497SC.J. Collier	rte_hash_free(handle);
48497f17497SC.J. Collier
48597f17497SC.J. Collier	return 0;
48697f17497SC.J. Collier}
48797f17497SC.J. Collier
48897f17497SC.J. Collier/*
48997f17497SC.J. Collier * Sequence of operations for 5 keys
49097f17497SC.J. Collier *	- add keys
49197f17497SC.J. Collier *	- lookup keys: hit
49297f17497SC.J. Collier *	- add keys (update)
49397f17497SC.J. Collier *	- lookup keys: hit (updated data)
49497f17497SC.J. Collier *	- delete keys : hit
49597f17497SC.J. Collier *	- lookup keys: miss
49697f17497SC.J. Collier */
49797f17497SC.J. Collierstatic int test_five_keys(void)
49897f17497SC.J. Collier{
49997f17497SC.J. Collier	struct rte_hash *handle;
50097f17497SC.J. Collier	const void *key_array[5] = {0};
50197f17497SC.J. Collier	int pos[5];
50297f17497SC.J. Collier	int expected_pos[5];
50397f17497SC.J. Collier	unsigned i;
50497f17497SC.J. Collier	int ret;
50597f17497SC.J. Collier
50697f17497SC.J. Collier	ut_params.name = "test3";
50797f17497SC.J. Collier	handle = rte_hash_create(&ut_params);
50897f17497SC.J. Collier	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
50997f17497SC.J. Collier
51097f17497SC.J. Collier	/* Add */
51197f17497SC.J. Collier	for (i = 0; i < 5; i++) {
51297f17497SC.J. Collier		pos[i] = rte_hash_add_key(handle, &keys[i]);
51397f17497SC.J. Collier		print_key_info("Add", &keys[i], pos[i]);
51497f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] < 0,
51597f17497SC.J. Collier				"failed to add key (pos[%u]=%d)", i, pos[i]);
51697f17497SC.J. Collier		expected_pos[i] = pos[i];
51797f17497SC.J. Collier	}
51897f17497SC.J. Collier
51997f17497SC.J. Collier	/* Lookup */
52097f17497SC.J. Collier	for(i = 0; i < 5; i++)
52197f17497SC.J. Collier		key_array[i] = &keys[i];
52297f17497SC.J. Collier
5238b25d1adSChristian Ehrhardt	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
52497f17497SC.J. Collier	if(ret == 0)
52597f17497SC.J. Collier		for(i = 0; i < 5; i++) {
52697f17497SC.J. Collier			print_key_info("Lkp", key_array[i], pos[i]);
52797f17497SC.J. Collier			RETURN_IF_ERROR(pos[i] != expected_pos[i],
52897f17497SC.J. Collier					"failed to find key (pos[%u]=%d)", i, pos[i]);
52997f17497SC.J. Collier		}
53097f17497SC.J. Collier
53197f17497SC.J. Collier	/* Add - update */
53297f17497SC.J. Collier	for (i = 0; i < 5; i++) {
53397f17497SC.J. Collier		pos[i] = rte_hash_add_key(handle, &keys[i]);
53497f17497SC.J. Collier		print_key_info("Add", &keys[i], pos[i]);
53597f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != expected_pos[i],
53697f17497SC.J. Collier				"failed to add key (pos[%u]=%d)", i, pos[i]);
53797f17497SC.J. Collier	}
53897f17497SC.J. Collier
53997f17497SC.J. Collier	/* Lookup */
54097f17497SC.J. Collier	for (i = 0; i < 5; i++) {
54197f17497SC.J. Collier		pos[i] = rte_hash_lookup(handle, &keys[i]);
54297f17497SC.J. Collier		print_key_info("Lkp", &keys[i], pos[i]);
54397f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != expected_pos[i],
54497f17497SC.J. Collier				"failed to find key (pos[%u]=%d)", i, pos[i]);
54597f17497SC.J. Collier	}
54697f17497SC.J. Collier
54797f17497SC.J. Collier	/* Delete */
54897f17497SC.J. Collier	for (i = 0; i < 5; i++) {
54997f17497SC.J. Collier		pos[i] = rte_hash_del_key(handle, &keys[i]);
55097f17497SC.J. Collier		print_key_info("Del", &keys[i], pos[i]);
55197f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != expected_pos[i],
55297f17497SC.J. Collier				"failed to delete key (pos[%u]=%d)", i, pos[i]);
55397f17497SC.J. Collier	}
55497f17497SC.J. Collier
55597f17497SC.J. Collier	/* Lookup */
55697f17497SC.J. Collier	for (i = 0; i < 5; i++) {
55797f17497SC.J. Collier		pos[i] = rte_hash_lookup(handle, &keys[i]);
55897f17497SC.J. Collier		print_key_info("Lkp", &keys[i], pos[i]);
55997f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != -ENOENT,
56097f17497SC.J. Collier				"found non-existent key (pos[%u]=%d)", i, pos[i]);
56197f17497SC.J. Collier	}
56297f17497SC.J. Collier
56397f17497SC.J. Collier	/* Lookup multi */
5648b25d1adSChristian Ehrhardt	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
56597f17497SC.J. Collier	if (ret == 0)
56697f17497SC.J. Collier		for (i = 0; i < 5; i++) {
56797f17497SC.J. Collier			print_key_info("Lkp", key_array[i], pos[i]);
56897f17497SC.J. Collier			RETURN_IF_ERROR(pos[i] != -ENOENT,
56997f17497SC.J. Collier					"found not-existent key (pos[%u]=%d)", i, pos[i]);
57097f17497SC.J. Collier		}
57197f17497SC.J. Collier
57297f17497SC.J. Collier	rte_hash_free(handle);
57397f17497SC.J. Collier
57497f17497SC.J. Collier	return 0;
57597f17497SC.J. Collier}
57697f17497SC.J. Collier
57797f17497SC.J. Collier/*
57897f17497SC.J. Collier * Add keys to the same bucket until bucket full.
57997f17497SC.J. Collier *	- add 5 keys to the same bucket (hash created with 4 keys per bucket):
58097f17497SC.J. Collier *	  first 4 successful, 5th successful, pushing existing item in bucket
58197f17497SC.J. Collier *	- lookup the 5 keys: 5 hits
58297f17497SC.J. Collier *	- add the 5 keys again: 5 OK
58397f17497SC.J. Collier *	- lookup the 5 keys: 5 hits (updated data)
58497f17497SC.J. Collier *	- delete the 5 keys: 5 OK
58597f17497SC.J. Collier *	- lookup the 5 keys: 5 misses
58697f17497SC.J. Collier */
58797f17497SC.J. Collierstatic int test_full_bucket(void)
58897f17497SC.J. Collier{
58997f17497SC.J. Collier	struct rte_hash_parameters params_pseudo_hash = {
59097f17497SC.J. Collier		.name = "test4",
59197f17497SC.J. Collier		.entries = 64,
59297f17497SC.J. Collier		.key_len = sizeof(struct flow_key), /* 13 */
59397f17497SC.J. Collier		.hash_func = pseudo_hash,
59497f17497SC.J. Collier		.hash_func_init_val = 0,
59597f17497SC.J. Collier		.socket_id = 0,
59697f17497SC.J. Collier	};
59797f17497SC.J. Collier	struct rte_hash *handle;
59897f17497SC.J. Collier	int pos[5];
59997f17497SC.J. Collier	int expected_pos[5];
60097f17497SC.J. Collier	unsigned i;
60197f17497SC.J. Collier
60297f17497SC.J. Collier	handle = rte_hash_create(&params_pseudo_hash);
60397f17497SC.J. Collier	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
60497f17497SC.J. Collier
60597f17497SC.J. Collier	/* Fill bucket */
60697f17497SC.J. Collier	for (i = 0; i < 4; i++) {
60797f17497SC.J. Collier		pos[i] = rte_hash_add_key(handle, &keys[i]);
60897f17497SC.J. Collier		print_key_info("Add", &keys[i], pos[i]);
60997f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] < 0,
61097f17497SC.J. Collier			"failed to add key (pos[%u]=%d)", i, pos[i]);
61197f17497SC.J. Collier		expected_pos[i] = pos[i];
61297f17497SC.J. Collier	}
61397f17497SC.J. Collier	/*
61497f17497SC.J. Collier	 * This should work and will push one of the items
61597f17497SC.J. Collier	 * in the bucket because it is full
61697f17497SC.J. Collier	 */
61797f17497SC.J. Collier	pos[4] = rte_hash_add_key(handle, &keys[4]);
61897f17497SC.J. Collier	print_key_info("Add", &keys[4], pos[4]);
61997f17497SC.J. Collier	RETURN_IF_ERROR(pos[4] < 0,
62097f17497SC.J. Collier			"failed to add key (pos[4]=%d)", pos[4]);
62197f17497SC.J. Collier	expected_pos[4] = pos[4];
62297f17497SC.J. Collier
62397f17497SC.J. Collier	/* Lookup */
62497f17497SC.J. Collier	for (i = 0; i < 5; i++) {
62597f17497SC.J. Collier		pos[i] = rte_hash_lookup(handle, &keys[i]);
62697f17497SC.J. Collier		print_key_info("Lkp", &keys[i], pos[i]);
62797f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != expected_pos[i],
62897f17497SC.J. Collier			"failed to find key (pos[%u]=%d)", i, pos[i]);
62997f17497SC.J. Collier	}
63097f17497SC.J. Collier
63197f17497SC.J. Collier	/* Add - update */
63297f17497SC.J. Collier	for (i = 0; i < 5; i++) {
63397f17497SC.J. Collier		pos[i] = rte_hash_add_key(handle, &keys[i]);
63497f17497SC.J. Collier		print_key_info("Add", &keys[i], pos[i]);
63597f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != expected_pos[i],
63697f17497SC.J. Collier			"failed to add key (pos[%u]=%d)", i, pos[i]);
63797f17497SC.J. Collier	}
63897f17497SC.J. Collier
63997f17497SC.J. Collier	/* Lookup */
64097f17497SC.J. Collier	for (i = 0; i < 5; i++) {
64197f17497SC.J. Collier		pos[i] = rte_hash_lookup(handle, &keys[i]);
64297f17497SC.J. Collier		print_key_info("Lkp", &keys[i], pos[i]);
64397f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != expected_pos[i],
64497f17497SC.J. Collier			"failed to find key (pos[%u]=%d)", i, pos[i]);
64597f17497SC.J. Collier	}
64697f17497SC.J. Collier
64797f17497SC.J. Collier	/* Delete 1 key, check other keys are still found */
64897f17497SC.J. Collier	pos[1] = rte_hash_del_key(handle, &keys[1]);
64997f17497SC.J. Collier	print_key_info("Del", &keys[1], pos[1]);
65097f17497SC.J. Collier	RETURN_IF_ERROR(pos[1] != expected_pos[1],
65197f17497SC.J. Collier			"failed to delete key (pos[1]=%d)", pos[1]);
65297f17497SC.J. Collier	pos[3] = rte_hash_lookup(handle, &keys[3]);
65397f17497SC.J. Collier	print_key_info("Lkp", &keys[3], pos[3]);
65497f17497SC.J. Collier	RETURN_IF_ERROR(pos[3] != expected_pos[3],
65597f17497SC.J. Collier			"failed lookup after deleting key from same bucket "
65697f17497SC.J. Collier			"(pos[3]=%d)", pos[3]);
65797f17497SC.J. Collier
65897f17497SC.J. Collier	/* Go back to previous state */
65997f17497SC.J. Collier	pos[1] = rte_hash_add_key(handle, &keys[1]);
66097f17497SC.J. Collier	print_key_info("Add", &keys[1], pos[1]);
66197f17497SC.J. Collier	expected_pos[1] = pos[1];
66297f17497SC.J. Collier	RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
66397f17497SC.J. Collier
66497f17497SC.J. Collier	/* Delete */
66597f17497SC.J. Collier	for (i = 0; i < 5; i++) {
66697f17497SC.J. Collier		pos[i] = rte_hash_del_key(handle, &keys[i]);
66797f17497SC.J. Collier		print_key_info("Del", &keys[i], pos[i]);
66897f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != expected_pos[i],
66997f17497SC.J. Collier			"failed to delete key (pos[%u]=%d)", i, pos[i]);
67097f17497SC.J. Collier	}
67197f17497SC.J. Collier
67297f17497SC.J. Collier	/* Lookup */
67397f17497SC.J. Collier	for (i = 0; i < 5; i++) {
67497f17497SC.J. Collier		pos[i] = rte_hash_lookup(handle, &keys[i]);
67597f17497SC.J. Collier		print_key_info("Lkp", &keys[i], pos[i]);
67697f17497SC.J. Collier		RETURN_IF_ERROR(pos[i] != -ENOENT,
67797f17497SC.J. Collier			"fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
67897f17497SC.J. Collier	}
67997f17497SC.J. Collier
68097f17497SC.J. Collier	rte_hash_free(handle);
68197f17497SC.J. Collier
68297f17497SC.J. Collier	/* Cover the NULL case. */
68397f17497SC.J. Collier	rte_hash_free(0);
68497f17497SC.J. Collier	return 0;
68597f17497SC.J. Collier}
68697f17497SC.J. Collier
68797f17497SC.J. Collier/******************************************************************************/
68897f17497SC.J. Collierstatic int
68997f17497SC.J. Collierfbk_hash_unit_test(void)
69097f17497SC.J. Collier{
69197f17497SC.J. Collier	struct rte_fbk_hash_params params = {
69297f17497SC.J. Collier		.name = "fbk_hash_test",
69397f17497SC.J. Collier		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
69497f17497SC.J. Collier		.entries_per_bucket = 4,
69597f17497SC.J. Collier		.socket_id = 0,
69697f17497SC.J. Collier	};
69797f17497SC.J. Collier
69897f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_1 = {
69997f17497SC.J. Collier		.name = "invalid_1",
70097f17497SC.J. Collier		.entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
70197f17497SC.J. Collier		.entries_per_bucket = 4,
70297f17497SC.J. Collier		.socket_id = 0,
70397f17497SC.J. Collier	};
70497f17497SC.J. Collier
70597f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_2 = {
70697f17497SC.J. Collier		.name = "invalid_2",
70797f17497SC.J. Collier		.entries = 4,
70897f17497SC.J. Collier		.entries_per_bucket = 3,         /* Not power of 2 */
70997f17497SC.J. Collier		.socket_id = 0,
71097f17497SC.J. Collier	};
71197f17497SC.J. Collier
71297f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_3 = {
71397f17497SC.J. Collier		.name = "invalid_3",
71497f17497SC.J. Collier		.entries = 0,                    /* Entries is 0 */
71597f17497SC.J. Collier		.entries_per_bucket = 4,
71697f17497SC.J. Collier		.socket_id = 0,
71797f17497SC.J. Collier	};
71897f17497SC.J. Collier
71997f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_4 = {
72097f17497SC.J. Collier		.name = "invalid_4",
72197f17497SC.J. Collier		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
72297f17497SC.J. Collier		.entries_per_bucket = 0,         /* Entries per bucket is 0 */
72397f17497SC.J. Collier		.socket_id = 0,
72497f17497SC.J. Collier	};
72597f17497SC.J. Collier
72697f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_5 = {
72797f17497SC.J. Collier		.name = "invalid_5",
72897f17497SC.J. Collier		.entries = 4,
72997f17497SC.J. Collier		.entries_per_bucket = 8,         /* Entries per bucket > entries */
73097f17497SC.J. Collier		.socket_id = 0,
73197f17497SC.J. Collier	};
73297f17497SC.J. Collier
73397f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_6 = {
73497f17497SC.J. Collier		.name = "invalid_6",
73597f17497SC.J. Collier		.entries = RTE_FBK_HASH_ENTRIES_MAX * 2,   /* Entries > max allowed */
73697f17497SC.J. Collier		.entries_per_bucket = 4,
73797f17497SC.J. Collier		.socket_id = 0,
73897f17497SC.J. Collier	};
73997f17497SC.J. Collier
74097f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_7 = {
74197f17497SC.J. Collier		.name = "invalid_7",
74297f17497SC.J. Collier		.entries = RTE_FBK_HASH_ENTRIES_MAX,
74397f17497SC.J. Collier		.entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2,	/* Entries > max allowed */
74497f17497SC.J. Collier		.socket_id = 0,
74597f17497SC.J. Collier	};
74697f17497SC.J. Collier
74797f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_8 = {
74897f17497SC.J. Collier		.name = "invalid_7",
74997f17497SC.J. Collier		.entries = RTE_FBK_HASH_ENTRIES_MAX,
75097f17497SC.J. Collier		.entries_per_bucket = 4,
75197f17497SC.J. Collier		.socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
75297f17497SC.J. Collier	};
75397f17497SC.J. Collier
75497f17497SC.J. Collier	/* try to create two hashes with identical names
75597f17497SC.J. Collier	 * in this case, trying to create a second one will not
75697f17497SC.J. Collier	 * fail but will simply return pointer to the existing
75797f17497SC.J. Collier	 * hash with that name. sort of like a "find hash by name" :-)
75897f17497SC.J. Collier	 */
75997f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_same_name_1 = {
76097f17497SC.J. Collier		.name = "same_name",				/* hash with identical name */
76197f17497SC.J. Collier		.entries = 4,
76297f17497SC.J. Collier		.entries_per_bucket = 2,
76397f17497SC.J. Collier		.socket_id = 0,
76497f17497SC.J. Collier	};
76597f17497SC.J. Collier
76697f17497SC.J. Collier	/* trying to create this hash should return a pointer to an existing hash */
76797f17497SC.J. Collier	struct rte_fbk_hash_params invalid_params_same_name_2 = {
76897f17497SC.J. Collier		.name = "same_name",				/* hash with identical name */
76997f17497SC.J. Collier		.entries = RTE_FBK_HASH_ENTRIES_MAX,
77097f17497SC.J. Collier		.entries_per_bucket = 4,
77197f17497SC.J. Collier		.socket_id = 0,
77297f17497SC.J. Collier	};
77397f17497SC.J. Collier
77497f17497SC.J. Collier	/* this is a sanity check for "same name" test
77597f17497SC.J. Collier	 * creating this hash will check if we are actually able to create
77697f17497SC.J. Collier	 * multiple hashes with different names (instead of having just one).
77797f17497SC.J. Collier	 */
77897f17497SC.J. Collier	struct rte_fbk_hash_params different_name = {
77997f17497SC.J. Collier		.name = "different_name",			/* different name */
7806b3e017eSChristian Ehrhardt		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
78197f17497SC.J. Collier		.entries_per_bucket = 4,
78297f17497SC.J. Collier		.socket_id = 0,
78397f17497SC.J. Collier	};
78497f17497SC.J. Collier
78597f17497SC.J. Collier	struct rte_fbk_hash_params params_jhash = {
78697f17497SC.J. Collier		.name = "valid",
78797f17497SC.J. Collier		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
78897f17497SC.J. Collier		.entries_per_bucket = 4,
78997f17497SC.J. Collier		.socket_id = 0,
79097f17497SC.J. Collier		.hash_func = rte_jhash_1word,              /* Tests for different hash_func */
79197f17497SC.J. Collier		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
79297f17497SC.J. Collier	};
79397f17497SC.J. Collier
79497f17497SC.J. Collier	struct rte_fbk_hash_params params_nohash = {
79597f17497SC.J. Collier		.name = "valid nohash",
79697f17497SC.J. Collier		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
79797f17497SC.J. Collier		.entries_per_bucket = 4,
79897f17497SC.J. Collier		.socket_id = 0,
79997f17497SC.J. Collier		.hash_func = NULL,                            /* Tests for null hash_func */
80097f17497SC.J. Collier		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
80197f17497SC.J. Collier	};
80297f17497SC.J. Collier
80397f17497SC.J. Collier	struct rte_fbk_hash_table *handle, *tmp;
80497f17497SC.J. Collier	uint32_t keys[5] =
80597f17497SC.J. Collier		{0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
80697f17497SC.J. Collier	uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
80797f17497SC.J. Collier	int status;
80897f17497SC.J. Collier	unsigned i;
80997f17497SC.J. Collier	double used_entries;
81097f17497SC.J. Collier
81197f17497SC.J. Collier	/* Try creating hashes with invalid parameters */
81297f17497SC.J. Collier	printf("# Testing hash creation with invalid parameters "
81397f17497SC.J. Collier			"- expect error msgs\n");
81497f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_1);
81597f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
81697f17497SC.J. Collier
81797f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_2);
81897f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
81997f17497SC.J. Collier
82097f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_3);
82197f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
82297f17497SC.J. Collier
82397f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_4);
82497f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
82597f17497SC.J. Collier
82697f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_5);
82797f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
82897f17497SC.J. Collier
82997f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_6);
83097f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
83197f17497SC.J. Collier
83297f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_7);
83397f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
83497f17497SC.J. Collier
83597f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_8);
83697f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
83797f17497SC.J. Collier
83897f17497SC.J. Collier	handle = rte_fbk_hash_create(&invalid_params_same_name_1);
83997f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
84097f17497SC.J. Collier
84197f17497SC.J. Collier	tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
84297f17497SC.J. Collier	if (tmp != NULL)
84397f17497SC.J. Collier		rte_fbk_hash_free(tmp);
84497f17497SC.J. Collier	RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
84597f17497SC.J. Collier
84697f17497SC.J. Collier	/* we are not freeing  handle here because we need a hash list
84797f17497SC.J. Collier	 * to be not empty for the next test */
84897f17497SC.J. Collier
84997f17497SC.J. Collier	/* create a hash in non-empty list - good for coverage */
85097f17497SC.J. Collier	tmp = rte_fbk_hash_create(&different_name);
85197f17497SC.J. Collier	RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
85297f17497SC.J. Collier
85397f17497SC.J. Collier	/* free both hashes */
85497f17497SC.J. Collier	rte_fbk_hash_free(handle);
85597f17497SC.J. Collier	rte_fbk_hash_free(tmp);
85697f17497SC.J. Collier
85797f17497SC.J. Collier	/* Create empty jhash hash. */
85897f17497SC.J. Collier	handle = rte_fbk_hash_create(&params_jhash);
85997f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
86097f17497SC.J. Collier
86197f17497SC.J. Collier	/* Cleanup. */
86297f17497SC.J. Collier	rte_fbk_hash_free(handle);
86397f17497SC.J. Collier
86497f17497SC.J. Collier	/* Create empty jhash hash. */
86597f17497SC.J. Collier	handle = rte_fbk_hash_create(&params_nohash);
86697f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
86797f17497SC.J. Collier
86897f17497SC.J. Collier	/* Cleanup. */
86997f17497SC.J. Collier	rte_fbk_hash_free(handle);
87097f17497SC.J. Collier
87197f17497SC.J. Collier	/* Create empty hash. */
87297f17497SC.J. Collier	handle = rte_fbk_hash_create(&params);
87397f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
87497f17497SC.J. Collier
87597f17497SC.J. Collier	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
87697f17497SC.J. Collier	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
87797f17497SC.J. Collier				"load factor right after creation is not zero but it should be");
87897f17497SC.J. Collier	/* Add keys. */
87997f17497SC.J. Collier	for (i = 0; i < 5; i++) {
88097f17497SC.J. Collier		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
88197f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
88297f17497SC.J. Collier	}
88397f17497SC.J. Collier
88497f17497SC.J. Collier	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
88597f17497SC.J. Collier	RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
88697f17497SC.J. Collier				"load factor now is not as expected");
88797f17497SC.J. Collier	/* Find value of added keys. */
88897f17497SC.J. Collier	for (i = 0; i < 5; i++) {
88997f17497SC.J. Collier		status = rte_fbk_hash_lookup(handle, keys[i]);
89097f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status != vals[i],
89197f17497SC.J. Collier				"fbk hash lookup failed");
89297f17497SC.J. Collier	}
89397f17497SC.J. Collier
89497f17497SC.J. Collier	/* Change value of added keys. */
89597f17497SC.J. Collier	for (i = 0; i < 5; i++) {
89697f17497SC.J. Collier		status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
89797f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
89897f17497SC.J. Collier	}
89997f17497SC.J. Collier
90097f17497SC.J. Collier	/* Find new values. */
90197f17497SC.J. Collier	for (i = 0; i < 5; i++) {
90297f17497SC.J. Collier		status = rte_fbk_hash_lookup(handle, keys[i]);
90397f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status != vals[4-i],
90497f17497SC.J. Collier				"fbk hash lookup failed");
90597f17497SC.J. Collier	}
90697f17497SC.J. Collier
90797f17497SC.J. Collier	/* Delete keys individually. */
90897f17497SC.J. Collier	for (i = 0; i < 5; i++) {
90997f17497SC.J. Collier		status = rte_fbk_hash_delete_key(handle, keys[i]);
91097f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
91197f17497SC.J. Collier	}
91297f17497SC.J. Collier
91397f17497SC.J. Collier	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
91497f17497SC.J. Collier	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
91597f17497SC.J. Collier				"load factor right after deletion is not zero but it should be");
91697f17497SC.J. Collier	/* Lookup should now fail. */
91797f17497SC.J. Collier	for (i = 0; i < 5; i++) {
91897f17497SC.J. Collier		status = rte_fbk_hash_lookup(handle, keys[i]);
91997f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status == 0,
92097f17497SC.J. Collier				"fbk hash lookup should have failed");
92197f17497SC.J. Collier	}
92297f17497SC.J. Collier
92397f17497SC.J. Collier	/* Add keys again. */
92497f17497SC.J. Collier	for (i = 0; i < 5; i++) {
92597f17497SC.J. Collier		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
92697f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
92797f17497SC.J. Collier	}
92897f17497SC.J. Collier
92997f17497SC.J. Collier	/* Make sure they were added. */
93097f17497SC.J. Collier	for (i = 0; i < 5; i++) {
93197f17497SC.J. Collier		status = rte_fbk_hash_lookup(handle, keys[i]);
93297f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status != vals[i],
93397f17497SC.J. Collier				"fbk hash lookup failed");
93497f17497SC.J. Collier	}
93597f17497SC.J. Collier
93697f17497SC.J. Collier	/* Clear all entries. */
93797f17497SC.J. Collier	rte_fbk_hash_clear_all(handle);
93897f17497SC.J. Collier
93997f17497SC.J. Collier	/* Lookup should fail. */
94097f17497SC.J. Collier	for (i = 0; i < 5; i++) {
94197f17497SC.J. Collier		status = rte_fbk_hash_lookup(handle, keys[i]);
94297f17497SC.J. Collier		RETURN_IF_ERROR_FBK(status == 0,
94397f17497SC.J. Collier				"fbk hash lookup should have failed");
94497f17497SC.J. Collier	}
94597f17497SC.J. Collier
94697f17497SC.J. Collier	/* coverage */
94797f17497SC.J. Collier
94897f17497SC.J. Collier	/* fill up the hash_table */
94997f17497SC.J. Collier	for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
95097f17497SC.J. Collier		rte_fbk_hash_add_key(handle, i, (uint16_t) i);
95197f17497SC.J. Collier
95297f17497SC.J. Collier	/* Find non-existent key in a full hashtable */
95397f17497SC.J. Collier	status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
95497f17497SC.J. Collier	RETURN_IF_ERROR_FBK(status != -ENOENT,
95597f17497SC.J. Collier			"fbk hash lookup succeeded");
95697f17497SC.J. Collier
95797f17497SC.J. Collier	/* Delete non-existent key in a full hashtable */
95897f17497SC.J. Collier	status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
95997f17497SC.J. Collier	RETURN_IF_ERROR_FBK(status != -ENOENT,
96097f17497SC.J. Collier			"fbk hash delete succeeded");
96197f17497SC.J. Collier
96297f17497SC.J. Collier	/* Delete one key from a full hashtable */
96397f17497SC.J. Collier	status = rte_fbk_hash_delete_key(handle, 1);
96497f17497SC.J. Collier	RETURN_IF_ERROR_FBK(status != 0,
96597f17497SC.J. Collier			"fbk hash delete failed");
96697f17497SC.J. Collier
96797f17497SC.J. Collier	/* Clear all entries. */
96897f17497SC.J. Collier	rte_fbk_hash_clear_all(handle);
96997f17497SC.J. Collier
97097f17497SC.J. Collier	/* Cleanup. */
97197f17497SC.J. Collier	rte_fbk_hash_free(handle);
97297f17497SC.J. Collier
97397f17497SC.J. Collier	/* Cover the NULL case. */
97497f17497SC.J. Collier	rte_fbk_hash_free(0);
97597f17497SC.J. Collier
97697f17497SC.J. Collier	return 0;
97797f17497SC.J. Collier}
97897f17497SC.J. Collier
97997f17497SC.J. Collier/*
98097f17497SC.J. Collier * Sequence of operations for find existing fbk hash table
98197f17497SC.J. Collier *
98297f17497SC.J. Collier *  - create table
98397f17497SC.J. Collier *  - find existing table: hit
98497f17497SC.J. Collier *  - find non-existing table: miss
98597f17497SC.J. Collier *
98697f17497SC.J. Collier */
98797f17497SC.J. Collierstatic int test_fbk_hash_find_existing(void)
98897f17497SC.J. Collier{
98997f17497SC.J. Collier	struct rte_fbk_hash_params params = {
99097f17497SC.J. Collier			.name = "fbk_hash_find_existing",
99197f17497SC.J. Collier			.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
99297f17497SC.J. Collier			.entries_per_bucket = 4,
99397f17497SC.J. Collier			.socket_id = 0,
99497f17497SC.J. Collier	};
99597f17497SC.J. Collier	struct rte_fbk_hash_table *handle = NULL, *result = NULL;
99697f17497SC.J. Collier
99797f17497SC.J. Collier	/* Create hash table. */
99897f17497SC.J. Collier	handle = rte_fbk_hash_create(&params);
99997f17497SC.J. Collier	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
100097f17497SC.J. Collier
100197f17497SC.J. Collier	/* Try to find existing fbk hash table */
100297f17497SC.J. Collier	result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
100397f17497SC.J. Collier	RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
100497f17497SC.J. Collier
100597f17497SC.J. Collier	/* Try to find non-existing fbk hash table */
100697f17497SC.J. Collier	result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
100797f17497SC.J. Collier	RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
100897f17497SC.J. Collier
100997f17497SC.J. Collier	/* Cleanup. */
101097f17497SC.J. Collier	rte_fbk_hash_free(handle);
101197f17497SC.J. Collier
101297f17497SC.J. Collier	return 0;
101397f17497SC.J. Collier}
101497f17497SC.J. Collier
101597f17497SC.J. Collier#define BUCKET_ENTRIES 4
101697f17497SC.J. Collier/*
101797f17497SC.J. Collier * Do tests for hash creation with bad parameters.
101897f17497SC.J. Collier */
101997f17497SC.J. Collierstatic int test_hash_creation_with_bad_parameters(void)
102097f17497SC.J. Collier{
102197f17497SC.J. Collier	struct rte_hash *handle, *tmp;
102297f17497SC.J. Collier	struct rte_hash_parameters params;
102397f17497SC.J. Collier
102497f17497SC.J. Collier	handle = rte_hash_create(NULL);
102597f17497SC.J. Collier	if (handle != NULL) {
102697f17497SC.J. Collier		rte_hash_free(handle);
102797f17497SC.J. Collier		printf("Impossible creating hash sucessfully without any parameter\n");
102897f17497SC.J. Collier		return -1;
102997f17497SC.J. Collier	}
103097f17497SC.J. Collier
103197f17497SC.J. Collier	memcpy(&params, &ut_params, sizeof(params));
103297f17497SC.J. Collier	params.name = "creation_with_bad_parameters_0";
103397f17497SC.J. Collier	params.entries = RTE_HASH_ENTRIES_MAX + 1;
103497f17497SC.J. Collier	handle = rte_hash_create(&params);
103597f17497SC.J. Collier	if (handle != NULL) {
103697f17497SC.J. Collier		rte_hash_free(handle);
103797f17497SC.J. Collier		printf("Impossible creating hash sucessfully with entries in parameter exceeded\n");
103897f17497SC.J. Collier		return -1;
103997f17497SC.J. Collier	}
104097f17497SC.J. Collier
104197f17497SC.J. Collier	memcpy(&params, &ut_params, sizeof(params));
104297f17497SC.J. Collier	params.name = "creation_with_bad_parameters_2";
104397f17497SC.J. Collier	params.entries = BUCKET_ENTRIES - 1;
104497f17497SC.J. Collier	handle = rte_hash_create(&params);
104597f17497SC.J. Collier	if (handle != NULL) {
104697f17497SC.J. Collier		rte_hash_free(handle);
104797f17497SC.J. Collier		printf("Impossible creating hash sucessfully if entries less than bucket_entries in parameter\n");
104897f17497SC.J. Collier		return -1;
104997f17497SC.J. Collier	}
105097f17497SC.J. Collier
105197f17497SC.J. Collier	memcpy(&params, &ut_params, sizeof(params));
105297f17497SC.J. Collier	params.name = "creation_with_bad_parameters_3";
105397f17497SC.J. Collier	params.key_len = 0;
105497f17497SC.J. Collier	handle = rte_hash_create(&params);
105597f17497SC.J. Collier	if (handle != NULL) {
105697f17497SC.J. Collier		rte_hash_free(handle);
105797f17497SC.J. Collier		printf("Impossible creating hash sucessfully if key_len in parameter is zero\n");
105897f17497SC.J. Collier		return -1;
105997f17497SC.J. Collier	}
106097f17497SC.J. Collier
106197f17497SC.J. Collier	memcpy(&params, &ut_params, sizeof(params));
1062