xref: /dpdk/app/test/test_hash.c (revision b5662e6d288762fe2c538551eb03d68854896e0b)
1a9de470cSBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
2a9de470cSBruce Richardson  * Copyright(c) 2010-2015 Intel Corporation
3a9de470cSBruce Richardson  */
4a9de470cSBruce Richardson 
5a9de470cSBruce Richardson #include <stdio.h>
6a9de470cSBruce Richardson #include <stdint.h>
7a9de470cSBruce Richardson #include <string.h>
8a9de470cSBruce Richardson #include <stdlib.h>
9a9de470cSBruce Richardson #include <stdarg.h>
10a9de470cSBruce Richardson #include <errno.h>
11a9de470cSBruce Richardson #include <sys/queue.h>
12a9de470cSBruce Richardson 
13a9de470cSBruce Richardson #include <rte_common.h>
14a9de470cSBruce Richardson #include <rte_malloc.h>
15a9de470cSBruce Richardson #include <rte_cycles.h>
16a9de470cSBruce Richardson #include <rte_random.h>
17a9de470cSBruce Richardson #include <rte_memory.h>
18a9de470cSBruce Richardson #include <rte_eal.h>
19a9de470cSBruce Richardson #include <rte_ip.h>
20a9de470cSBruce Richardson #include <rte_string_fns.h>
21a9de470cSBruce Richardson 
22a9de470cSBruce Richardson #include "test.h"
23a9de470cSBruce Richardson 
24a9de470cSBruce Richardson #include <rte_hash.h>
25a9de470cSBruce Richardson #include <rte_fbk_hash.h>
26a9de470cSBruce Richardson #include <rte_jhash.h>
27a9de470cSBruce Richardson #include <rte_hash_crc.h>
28a9de470cSBruce Richardson 
29a9de470cSBruce Richardson /*******************************************************************************
30a9de470cSBruce Richardson  * Hash function performance test configuration section. Each performance test
31a9de470cSBruce Richardson  * will be performed HASHTEST_ITERATIONS times.
32a9de470cSBruce Richardson  *
33a9de470cSBruce Richardson  * The five arrays below control what tests are performed. Every combination
34a9de470cSBruce Richardson  * from the array entries is tested.
35a9de470cSBruce Richardson  */
36a9de470cSBruce Richardson static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
37a9de470cSBruce Richardson static uint32_t hashtest_initvals[] = {0};
38a9de470cSBruce Richardson static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64};
39a9de470cSBruce Richardson #define MAX_KEYSIZE 64
40a9de470cSBruce Richardson /******************************************************************************/
41a9de470cSBruce Richardson #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
42a9de470cSBruce Richardson 
43a9de470cSBruce Richardson /*
44a9de470cSBruce Richardson  * Check condition and return an error if true. Assumes that "handle" is the
45a9de470cSBruce Richardson  * name of the hash structure pointer to be freed.
46a9de470cSBruce Richardson  */
47a9de470cSBruce Richardson #define RETURN_IF_ERROR(cond, str, ...) do {				\
48a9de470cSBruce Richardson 	if (cond) {							\
49a9de470cSBruce Richardson 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
50a9de470cSBruce Richardson 		if (handle) rte_hash_free(handle);			\
51a9de470cSBruce Richardson 		return -1;						\
52a9de470cSBruce Richardson 	}								\
53a9de470cSBruce Richardson } while(0)
54a9de470cSBruce Richardson 
55a9de470cSBruce Richardson #define RETURN_IF_ERROR_FBK(cond, str, ...) do {				\
56a9de470cSBruce Richardson 	if (cond) {							\
57a9de470cSBruce Richardson 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
58a9de470cSBruce Richardson 		if (handle) rte_fbk_hash_free(handle);			\
59a9de470cSBruce Richardson 		return -1;						\
60a9de470cSBruce Richardson 	}								\
61a9de470cSBruce Richardson } while(0)
62a9de470cSBruce Richardson 
639c7d8eedSDharmik Thakkar #define RETURN_IF_ERROR_RCU_QSBR(cond, str, ...) do {			\
649c7d8eedSDharmik Thakkar 	if (cond) {							\
659c7d8eedSDharmik Thakkar 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
669c7d8eedSDharmik Thakkar 		if (rcu_cfg.mode == RTE_HASH_QSBR_MODE_SYNC) {		\
679c7d8eedSDharmik Thakkar 			writer_done = 1;				\
689c7d8eedSDharmik Thakkar 			/* Wait until reader exited. */			\
699c7d8eedSDharmik Thakkar 			rte_eal_mp_wait_lcore();			\
709c7d8eedSDharmik Thakkar 		}							\
719c7d8eedSDharmik Thakkar 		rte_hash_free(g_handle);				\
729c7d8eedSDharmik Thakkar 		rte_free(g_qsv);					\
739c7d8eedSDharmik Thakkar 		return -1;						\
749c7d8eedSDharmik Thakkar 	}								\
759c7d8eedSDharmik Thakkar } while (0)
769c7d8eedSDharmik Thakkar 
77e30ef3a3SVladimir Medvedkin /*
78e30ef3a3SVladimir Medvedkin  * 5-tuple key type.
79e30ef3a3SVladimir Medvedkin  * Should be packed to avoid holes with potentially
80e30ef3a3SVladimir Medvedkin  * undefined content in the middle.
81e30ef3a3SVladimir Medvedkin  */
82*b5662e6dSAndre Muezerie struct __rte_packed_begin flow_key {
83a9de470cSBruce Richardson 	uint32_t ip_src;
84a9de470cSBruce Richardson 	uint32_t ip_dst;
85a9de470cSBruce Richardson 	uint16_t port_src;
86a9de470cSBruce Richardson 	uint16_t port_dst;
87e30ef3a3SVladimir Medvedkin 	uint32_t proto;
88*b5662e6dSAndre Muezerie } __rte_packed_end;
89a9de470cSBruce Richardson 
90a9de470cSBruce Richardson /*
91a9de470cSBruce Richardson  * Hash function that always returns the same value, to easily test what
92a9de470cSBruce Richardson  * happens when a bucket is full.
93a9de470cSBruce Richardson  */
94f2fc83b4SThomas Monjalon static uint32_t pseudo_hash(__rte_unused const void *keys,
95f2fc83b4SThomas Monjalon 			    __rte_unused uint32_t key_len,
96f2fc83b4SThomas Monjalon 			    __rte_unused uint32_t init_val)
97a9de470cSBruce Richardson {
9864b2907cSYoan Picchi 	return 3 | (3 << 16);
99a9de470cSBruce Richardson }
100a9de470cSBruce Richardson 
1019c99878aSJerin Jacob RTE_LOG_REGISTER(hash_logtype_test, test.hash, INFO);
10254e5545dSDharmik Thakkar 
103a9de470cSBruce Richardson /*
104a9de470cSBruce Richardson  * Print out result of unit test hash operation.
105a9de470cSBruce Richardson  */
106a9de470cSBruce Richardson static void print_key_info(const char *msg, const struct flow_key *key,
107a9de470cSBruce Richardson 								int32_t pos)
108a9de470cSBruce Richardson {
109a9de470cSBruce Richardson 	const uint8_t *p = (const uint8_t *)key;
110a9de470cSBruce Richardson 	unsigned int i;
111a9de470cSBruce Richardson 
11254e5545dSDharmik Thakkar 	rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%s key:0x", msg);
113a9de470cSBruce Richardson 	for (i = 0; i < sizeof(struct flow_key); i++)
11454e5545dSDharmik Thakkar 		rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%02X", p[i]);
11554e5545dSDharmik Thakkar 	rte_log(RTE_LOG_DEBUG, hash_logtype_test, " @ pos %d\n", pos);
116a9de470cSBruce Richardson }
117a9de470cSBruce Richardson 
11864b2907cSYoan Picchi #define KEY_PER_BUCKET 8
11964b2907cSYoan Picchi 
120a9de470cSBruce Richardson /* Keys used by unit test functions */
12164b2907cSYoan Picchi static struct flow_key keys[KEY_PER_BUCKET+1] = { {
1220c9da755SDavid Marchand 	.ip_src = RTE_IPV4(0x03, 0x02, 0x01, 0x00),
1230c9da755SDavid Marchand 	.ip_dst = RTE_IPV4(0x07, 0x06, 0x05, 0x04),
124a9de470cSBruce Richardson 	.port_src = 0x0908,
125a9de470cSBruce Richardson 	.port_dst = 0x0b0a,
126a9de470cSBruce Richardson 	.proto = 0x0c,
127a9de470cSBruce Richardson }, {
1280c9da755SDavid Marchand 	.ip_src = RTE_IPV4(0x13, 0x12, 0x11, 0x10),
1290c9da755SDavid Marchand 	.ip_dst = RTE_IPV4(0x17, 0x16, 0x15, 0x14),
130a9de470cSBruce Richardson 	.port_src = 0x1918,
131a9de470cSBruce Richardson 	.port_dst = 0x1b1a,
132a9de470cSBruce Richardson 	.proto = 0x1c,
133a9de470cSBruce Richardson }, {
1340c9da755SDavid Marchand 	.ip_src = RTE_IPV4(0x23, 0x22, 0x21, 0x20),
1350c9da755SDavid Marchand 	.ip_dst = RTE_IPV4(0x27, 0x26, 0x25, 0x24),
136a9de470cSBruce Richardson 	.port_src = 0x2928,
137a9de470cSBruce Richardson 	.port_dst = 0x2b2a,
138a9de470cSBruce Richardson 	.proto = 0x2c,
139a9de470cSBruce Richardson }, {
1400c9da755SDavid Marchand 	.ip_src = RTE_IPV4(0x33, 0x32, 0x31, 0x30),
1410c9da755SDavid Marchand 	.ip_dst = RTE_IPV4(0x37, 0x36, 0x35, 0x34),
142a9de470cSBruce Richardson 	.port_src = 0x3938,
143a9de470cSBruce Richardson 	.port_dst = 0x3b3a,
144a9de470cSBruce Richardson 	.proto = 0x3c,
145a9de470cSBruce Richardson }, {
1460c9da755SDavid Marchand 	.ip_src = RTE_IPV4(0x43, 0x42, 0x41, 0x40),
1470c9da755SDavid Marchand 	.ip_dst = RTE_IPV4(0x47, 0x46, 0x45, 0x44),
148a9de470cSBruce Richardson 	.port_src = 0x4948,
149a9de470cSBruce Richardson 	.port_dst = 0x4b4a,
150a9de470cSBruce Richardson 	.proto = 0x4c,
15164b2907cSYoan Picchi }, {
15264b2907cSYoan Picchi 	.ip_src = RTE_IPV4(0x53, 0x52, 0x51, 0x50),
15364b2907cSYoan Picchi 	.ip_dst = RTE_IPV4(0x57, 0x56, 0x55, 0x54),
15464b2907cSYoan Picchi 	.port_src = 0x5958,
15564b2907cSYoan Picchi 	.port_dst = 0x5b5a,
15664b2907cSYoan Picchi 	.proto = 0x5c,
15764b2907cSYoan Picchi }, {
15864b2907cSYoan Picchi 	.ip_src = RTE_IPV4(0x63, 0x62, 0x61, 0x60),
15964b2907cSYoan Picchi 	.ip_dst = RTE_IPV4(0x67, 0x66, 0x65, 0x64),
16064b2907cSYoan Picchi 	.port_src = 0x6968,
16164b2907cSYoan Picchi 	.port_dst = 0x6b6a,
16264b2907cSYoan Picchi 	.proto = 0x6c,
16364b2907cSYoan Picchi }, {
16464b2907cSYoan Picchi 	.ip_src = RTE_IPV4(0x73, 0x72, 0x71, 0x70),
16564b2907cSYoan Picchi 	.ip_dst = RTE_IPV4(0x77, 0x76, 0x75, 0x74),
16664b2907cSYoan Picchi 	.port_src = 0x7978,
16764b2907cSYoan Picchi 	.port_dst = 0x7b7a,
16864b2907cSYoan Picchi 	.proto = 0x7c,
16964b2907cSYoan Picchi }, {
17064b2907cSYoan Picchi 	.ip_src = RTE_IPV4(0x83, 0x82, 0x81, 0x80),
17164b2907cSYoan Picchi 	.ip_dst = RTE_IPV4(0x87, 0x86, 0x85, 0x84),
17264b2907cSYoan Picchi 	.port_src = 0x8988,
17364b2907cSYoan Picchi 	.port_dst = 0x8b8a,
17464b2907cSYoan Picchi 	.proto = 0x8c,
175a9de470cSBruce Richardson } };
176a9de470cSBruce Richardson 
177a9de470cSBruce Richardson /* Parameters used for hash table in unit test functions. Name set later. */
178a9de470cSBruce Richardson static struct rte_hash_parameters ut_params = {
179a9de470cSBruce Richardson 	.entries = 64,
180e30ef3a3SVladimir Medvedkin 	.key_len = sizeof(struct flow_key),
181a9de470cSBruce Richardson 	.hash_func = rte_jhash,
182a9de470cSBruce Richardson 	.hash_func_init_val = 0,
183a9de470cSBruce Richardson 	.socket_id = 0,
184a9de470cSBruce Richardson };
185a9de470cSBruce Richardson 
186a9de470cSBruce Richardson #define CRC32_ITERATIONS (1U << 10)
187a9de470cSBruce Richardson #define CRC32_DWORDS (1U << 6)
188a9de470cSBruce Richardson /*
189a9de470cSBruce Richardson  * Test if all CRC32 implementations yield the same hash value
190a9de470cSBruce Richardson  */
191a9de470cSBruce Richardson static int
192a9de470cSBruce Richardson test_crc32_hash_alg_equiv(void)
193a9de470cSBruce Richardson {
194a9de470cSBruce Richardson 	uint32_t hash_val;
195a9de470cSBruce Richardson 	uint32_t init_val;
196a9de470cSBruce Richardson 	uint64_t data64[CRC32_DWORDS];
197a9de470cSBruce Richardson 	unsigned i, j;
198a9de470cSBruce Richardson 	size_t data_len;
199a9de470cSBruce Richardson 
200a9de470cSBruce Richardson 	printf("\n# CRC32 implementations equivalence test\n");
201a9de470cSBruce Richardson 	for (i = 0; i < CRC32_ITERATIONS; i++) {
202a9de470cSBruce Richardson 		/* Randomizing data_len of data set */
203a9de470cSBruce Richardson 		data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
204a9de470cSBruce Richardson 		init_val = (uint32_t) rte_rand();
205a9de470cSBruce Richardson 
206a9de470cSBruce Richardson 		/* Fill the data set */
207a9de470cSBruce Richardson 		for (j = 0; j < CRC32_DWORDS; j++)
208a9de470cSBruce Richardson 			data64[j] = rte_rand();
209a9de470cSBruce Richardson 
210a9de470cSBruce Richardson 		/* Calculate software CRC32 */
211a9de470cSBruce Richardson 		rte_hash_crc_set_alg(CRC32_SW);
212a9de470cSBruce Richardson 		hash_val = rte_hash_crc(data64, data_len, init_val);
213a9de470cSBruce Richardson 
214a9de470cSBruce Richardson 		/* Check against 4-byte-operand sse4.2 CRC32 if available */
215a9de470cSBruce Richardson 		rte_hash_crc_set_alg(CRC32_SSE42);
216a9de470cSBruce Richardson 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
217a9de470cSBruce Richardson 			printf("Failed checking CRC32_SW against CRC32_SSE42\n");
218a9de470cSBruce Richardson 			break;
219a9de470cSBruce Richardson 		}
220a9de470cSBruce Richardson 
221a9de470cSBruce Richardson 		/* Check against 8-byte-operand sse4.2 CRC32 if available */
222a9de470cSBruce Richardson 		rte_hash_crc_set_alg(CRC32_SSE42_x64);
223a9de470cSBruce Richardson 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
224a9de470cSBruce Richardson 			printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
225a9de470cSBruce Richardson 			break;
226a9de470cSBruce Richardson 		}
227a9de470cSBruce Richardson 
228a9de470cSBruce Richardson 		/* Check against 8-byte-operand ARM64 CRC32 if available */
229a9de470cSBruce Richardson 		rte_hash_crc_set_alg(CRC32_ARM64);
230a9de470cSBruce Richardson 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
231a9de470cSBruce Richardson 			printf("Failed checking CRC32_SW against CRC32_ARM64\n");
232a9de470cSBruce Richardson 			break;
233a9de470cSBruce Richardson 		}
234a9de470cSBruce Richardson 	}
235a9de470cSBruce Richardson 
236a9de470cSBruce Richardson 	/* Resetting to best available algorithm */
237a9de470cSBruce Richardson 	rte_hash_crc_set_alg(CRC32_SSE42_x64);
238a9de470cSBruce Richardson 
239a9de470cSBruce Richardson 	if (i == CRC32_ITERATIONS)
240a9de470cSBruce Richardson 		return 0;
241a9de470cSBruce Richardson 
242a9de470cSBruce Richardson 	printf("Failed test data (hex, %zu bytes total):\n", data_len);
243a9de470cSBruce Richardson 	for (j = 0; j < data_len; j++)
244a9de470cSBruce Richardson 		printf("%02X%c", ((uint8_t *)data64)[j],
245a9de470cSBruce Richardson 				((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
246a9de470cSBruce Richardson 
247a9de470cSBruce Richardson 	return -1;
248a9de470cSBruce Richardson }
249a9de470cSBruce Richardson 
250a9de470cSBruce Richardson /*
251a9de470cSBruce Richardson  * Test a hash function.
252a9de470cSBruce Richardson  */
253a9de470cSBruce Richardson static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
254a9de470cSBruce Richardson 		uint32_t key_len)
255a9de470cSBruce Richardson {
256a9de470cSBruce Richardson 	static uint8_t key[MAX_KEYSIZE];
257a9de470cSBruce Richardson 	unsigned i;
258a9de470cSBruce Richardson 
259a9de470cSBruce Richardson 
260a9de470cSBruce Richardson 	for (i = 0; i < key_len; i++)
261a9de470cSBruce Richardson 		key[i] = (uint8_t) rte_rand();
262a9de470cSBruce Richardson 
263a9de470cSBruce Richardson 	/* just to be on the safe side */
264a9de470cSBruce Richardson 	if (!f)
265a9de470cSBruce Richardson 		return;
266a9de470cSBruce Richardson 
267a9de470cSBruce Richardson 	f(key, key_len, init_val);
268a9de470cSBruce Richardson }
269a9de470cSBruce Richardson 
270a9de470cSBruce Richardson /*
271a9de470cSBruce Richardson  * Test all hash functions.
272a9de470cSBruce Richardson  */
273a9de470cSBruce Richardson static void run_hash_func_tests(void)
274a9de470cSBruce Richardson {
275a9de470cSBruce Richardson 	unsigned i, j, k;
276a9de470cSBruce Richardson 
27771bdd8a1SPavan Nikhilesh 	for (i = 0; i < RTE_DIM(hashtest_funcs); i++) {
27871bdd8a1SPavan Nikhilesh 		for (j = 0; j < RTE_DIM(hashtest_initvals); j++) {
27971bdd8a1SPavan Nikhilesh 			for (k = 0; k < RTE_DIM(hashtest_key_lens); k++) {
280a9de470cSBruce Richardson 				run_hash_func_test(hashtest_funcs[i],
281a9de470cSBruce Richardson 						hashtest_initvals[j],
282a9de470cSBruce Richardson 						hashtest_key_lens[k]);
283a9de470cSBruce Richardson 			}
284a9de470cSBruce Richardson 		}
285a9de470cSBruce Richardson 	}
286a9de470cSBruce Richardson }
287a9de470cSBruce Richardson 
288a9de470cSBruce Richardson /*
289a9de470cSBruce Richardson  * Basic sequence of operations for a single key:
290a9de470cSBruce Richardson  *	- add
291a9de470cSBruce Richardson  *	- lookup (hit)
292a9de470cSBruce Richardson  *	- delete
293a9de470cSBruce Richardson  *	- lookup (miss)
294a9de470cSBruce Richardson  *
295a9de470cSBruce Richardson  * Repeat the test case when 'free on delete' is disabled.
296a9de470cSBruce Richardson  *	- add
297a9de470cSBruce Richardson  *	- lookup (hit)
298a9de470cSBruce Richardson  *	- delete
299a9de470cSBruce Richardson  *	- lookup (miss)
300a9de470cSBruce Richardson  *	- free
301a9de470cSBruce Richardson  */
302a9de470cSBruce Richardson static int test_add_delete(void)
303a9de470cSBruce Richardson {
304a9de470cSBruce Richardson 	struct rte_hash *handle;
305a9de470cSBruce Richardson 	/* test with standard add/lookup/delete functions */
306a9de470cSBruce Richardson 	int pos0, expectedPos0;
307a9de470cSBruce Richardson 
308a9de470cSBruce Richardson 	ut_params.name = "test1";
309a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
310a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
311a9de470cSBruce Richardson 
312a9de470cSBruce Richardson 	pos0 = rte_hash_add_key(handle, &keys[0]);
313a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos0);
314a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
315a9de470cSBruce Richardson 	expectedPos0 = pos0;
316a9de470cSBruce Richardson 
317a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
318a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
319a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
320a9de470cSBruce Richardson 			"failed to find key (pos0=%d)", pos0);
321a9de470cSBruce Richardson 
322a9de470cSBruce Richardson 	pos0 = rte_hash_del_key(handle, &keys[0]);
323a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos0);
324a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
325a9de470cSBruce Richardson 			"failed to delete key (pos0=%d)", pos0);
326a9de470cSBruce Richardson 
327a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
328a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
329a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
330a9de470cSBruce Richardson 			"fail: found key after deleting! (pos0=%d)", pos0);
331a9de470cSBruce Richardson 
332a9de470cSBruce Richardson 	rte_hash_free(handle);
333a9de470cSBruce Richardson 
334a9de470cSBruce Richardson 	/* repeat test with precomputed hash functions */
335a9de470cSBruce Richardson 	hash_sig_t hash_value;
336a9de470cSBruce Richardson 	int pos1, expectedPos1, delPos1;
337a9de470cSBruce Richardson 
338a9de470cSBruce Richardson 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
339a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
340a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
341a9de470cSBruce Richardson 	ut_params.extra_flag = 0;
342a9de470cSBruce Richardson 
343a9de470cSBruce Richardson 	hash_value = rte_hash_hash(handle, &keys[0]);
344a9de470cSBruce Richardson 	pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
345a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos1);
346a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
347a9de470cSBruce Richardson 	expectedPos1 = pos1;
348a9de470cSBruce Richardson 
349a9de470cSBruce Richardson 	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
350a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos1);
351a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos1 != expectedPos1,
352a9de470cSBruce Richardson 			"failed to find key (pos1=%d)", pos1);
353a9de470cSBruce Richardson 
354a9de470cSBruce Richardson 	pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
355a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos1);
356a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos1 != expectedPos1,
357a9de470cSBruce Richardson 			"failed to delete key (pos1=%d)", pos1);
358a9de470cSBruce Richardson 	delPos1 = pos1;
359a9de470cSBruce Richardson 
360a9de470cSBruce Richardson 	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
361a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos1);
362a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos1 != -ENOENT,
363a9de470cSBruce Richardson 			"fail: found key after deleting! (pos1=%d)", pos1);
364a9de470cSBruce Richardson 
365a9de470cSBruce Richardson 	pos1 = rte_hash_free_key_with_position(handle, delPos1);
366a9de470cSBruce Richardson 	print_key_info("Free", &keys[0], delPos1);
367a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos1 != 0,
368a9de470cSBruce Richardson 			"failed to free key (pos1=%d)", delPos1);
369a9de470cSBruce Richardson 
370a9de470cSBruce Richardson 	rte_hash_free(handle);
371a9de470cSBruce Richardson 
372a9de470cSBruce Richardson 	return 0;
373a9de470cSBruce Richardson }
374a9de470cSBruce Richardson 
375a9de470cSBruce Richardson /*
376a9de470cSBruce Richardson  * Sequence of operations for a single key:
377a9de470cSBruce Richardson  *	- delete: miss
378a9de470cSBruce Richardson  *	- add
379a9de470cSBruce Richardson  *	- lookup: hit
380a9de470cSBruce Richardson  *	- add: update
381a9de470cSBruce Richardson  *	- lookup: hit (updated data)
382a9de470cSBruce Richardson  *	- delete: hit
383a9de470cSBruce Richardson  *	- delete: miss
384a9de470cSBruce Richardson  *	- lookup: miss
385a9de470cSBruce Richardson  */
386a9de470cSBruce Richardson static int test_add_update_delete(void)
387a9de470cSBruce Richardson {
388a9de470cSBruce Richardson 	struct rte_hash *handle;
389a9de470cSBruce Richardson 	int pos0, expectedPos0;
390a9de470cSBruce Richardson 
391a9de470cSBruce Richardson 	ut_params.name = "test2";
392a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
393a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
394a9de470cSBruce Richardson 
395a9de470cSBruce Richardson 	pos0 = rte_hash_del_key(handle, &keys[0]);
396a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos0);
397a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
398a9de470cSBruce Richardson 			"fail: found non-existent key (pos0=%d)", pos0);
399a9de470cSBruce Richardson 
400a9de470cSBruce Richardson 	pos0 = rte_hash_add_key(handle, &keys[0]);
401a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos0);
402a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
403a9de470cSBruce Richardson 	expectedPos0 = pos0;
404a9de470cSBruce Richardson 
405a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
406a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
407a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
408a9de470cSBruce Richardson 			"failed to find key (pos0=%d)", pos0);
409a9de470cSBruce Richardson 
410a9de470cSBruce Richardson 	pos0 = rte_hash_add_key(handle, &keys[0]);
411a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos0);
412a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
413a9de470cSBruce Richardson 			"failed to re-add key (pos0=%d)", pos0);
414a9de470cSBruce Richardson 
415a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
416a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
417a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
418a9de470cSBruce Richardson 			"failed to find key (pos0=%d)", pos0);
419a9de470cSBruce Richardson 
420a9de470cSBruce Richardson 	pos0 = rte_hash_del_key(handle, &keys[0]);
421a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos0);
422a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
423a9de470cSBruce Richardson 			"failed to delete key (pos0=%d)", pos0);
424a9de470cSBruce Richardson 
425a9de470cSBruce Richardson 	pos0 = rte_hash_del_key(handle, &keys[0]);
426a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos0);
427a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
428a9de470cSBruce Richardson 			"fail: deleted already deleted key (pos0=%d)", pos0);
429a9de470cSBruce Richardson 
430a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
431a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
432a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
433a9de470cSBruce Richardson 			"fail: found key after deleting! (pos0=%d)", pos0);
434a9de470cSBruce Richardson 
435a9de470cSBruce Richardson 	rte_hash_free(handle);
436a9de470cSBruce Richardson 	return 0;
437a9de470cSBruce Richardson }
438a9de470cSBruce Richardson 
439a9de470cSBruce Richardson /*
440a9de470cSBruce Richardson  * Sequence of operations for a single key with 'disable free on del' set:
441a9de470cSBruce Richardson  *	- delete: miss
442a9de470cSBruce Richardson  *	- add
443a9de470cSBruce Richardson  *	- lookup: hit
444a9de470cSBruce Richardson  *	- add: update
445a9de470cSBruce Richardson  *	- lookup: hit (updated data)
446a9de470cSBruce Richardson  *	- delete: hit
447a9de470cSBruce Richardson  *	- delete: miss
448a9de470cSBruce Richardson  *	- lookup: miss
449a9de470cSBruce Richardson  *	- free: hit
450a9de470cSBruce Richardson  *	- lookup: miss
451a9de470cSBruce Richardson  */
452a9de470cSBruce Richardson static int test_add_update_delete_free(void)
453a9de470cSBruce Richardson {
454a9de470cSBruce Richardson 	struct rte_hash *handle;
455a9de470cSBruce Richardson 	int pos0, expectedPos0, delPos0, result;
456a9de470cSBruce Richardson 
457a9de470cSBruce Richardson 	ut_params.name = "test2";
458a9de470cSBruce Richardson 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
459a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
460a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
461a9de470cSBruce Richardson 	ut_params.extra_flag = 0;
462a9de470cSBruce Richardson 
463a9de470cSBruce Richardson 	pos0 = rte_hash_del_key(handle, &keys[0]);
464a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos0);
465a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
466a9de470cSBruce Richardson 			"fail: found non-existent key (pos0=%d)", pos0);
467a9de470cSBruce Richardson 
468a9de470cSBruce Richardson 	pos0 = rte_hash_add_key(handle, &keys[0]);
469a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos0);
470a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
471a9de470cSBruce Richardson 	expectedPos0 = pos0;
472a9de470cSBruce Richardson 
473a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
474a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
475a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
476a9de470cSBruce Richardson 			"failed to find key (pos0=%d)", pos0);
477a9de470cSBruce Richardson 
478a9de470cSBruce Richardson 	pos0 = rte_hash_add_key(handle, &keys[0]);
479a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos0);
480a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
481a9de470cSBruce Richardson 			"failed to re-add key (pos0=%d)", pos0);
482a9de470cSBruce Richardson 
483a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
484a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
485a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != expectedPos0,
486a9de470cSBruce Richardson 			"failed to find key (pos0=%d)", pos0);
487a9de470cSBruce Richardson 
488a9de470cSBruce Richardson 	delPos0 = rte_hash_del_key(handle, &keys[0]);
489a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], delPos0);
490a9de470cSBruce Richardson 	RETURN_IF_ERROR(delPos0 != expectedPos0,
491a9de470cSBruce Richardson 			"failed to delete key (pos0=%d)", delPos0);
492a9de470cSBruce Richardson 
493a9de470cSBruce Richardson 	pos0 = rte_hash_del_key(handle, &keys[0]);
494a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos0);
495a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
496a9de470cSBruce Richardson 			"fail: deleted already deleted key (pos0=%d)", pos0);
497a9de470cSBruce Richardson 
498a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
499a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
500a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
501a9de470cSBruce Richardson 			"fail: found key after deleting! (pos0=%d)", pos0);
502a9de470cSBruce Richardson 
503a9de470cSBruce Richardson 	result = rte_hash_free_key_with_position(handle, delPos0);
504a9de470cSBruce Richardson 	print_key_info("Free", &keys[0], delPos0);
505a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != 0,
506a9de470cSBruce Richardson 			"failed to free key (pos1=%d)", delPos0);
507a9de470cSBruce Richardson 
508a9de470cSBruce Richardson 	pos0 = rte_hash_lookup(handle, &keys[0]);
509a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[0], pos0);
510a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos0 != -ENOENT,
511a9de470cSBruce Richardson 			"fail: found key after deleting! (pos0=%d)", pos0);
512a9de470cSBruce Richardson 
513a9de470cSBruce Richardson 	rte_hash_free(handle);
514a9de470cSBruce Richardson 	return 0;
515a9de470cSBruce Richardson }
516a9de470cSBruce Richardson 
517a9de470cSBruce Richardson /*
518a55f182bSDharmik Thakkar  * Sequence of operations for a single key with 'rw concurrency lock free' set:
519a55f182bSDharmik Thakkar  *	- add
520a55f182bSDharmik Thakkar  *	- delete: hit
521a55f182bSDharmik Thakkar  *	- free: hit
522a55f182bSDharmik Thakkar  * Repeat the test case when 'multi writer add' is enabled.
523a55f182bSDharmik Thakkar  *	- add
524a55f182bSDharmik Thakkar  *	- delete: hit
525a55f182bSDharmik Thakkar  *	- free: hit
526a55f182bSDharmik Thakkar  */
527a55f182bSDharmik Thakkar static int test_add_delete_free_lf(void)
528a55f182bSDharmik Thakkar {
529a55f182bSDharmik Thakkar /* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */
530a55f182bSDharmik Thakkar #define LCORE_CACHE_SIZE	64
531a55f182bSDharmik Thakkar 	struct rte_hash *handle;
532a55f182bSDharmik Thakkar 	hash_sig_t hash_value;
533a55f182bSDharmik Thakkar 	int pos, expectedPos, delPos;
534a55f182bSDharmik Thakkar 	uint8_t extra_flag;
535a55f182bSDharmik Thakkar 	uint32_t i, ip_src;
536a55f182bSDharmik Thakkar 
537a55f182bSDharmik Thakkar 	extra_flag = ut_params.extra_flag;
538a55f182bSDharmik Thakkar 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
539a55f182bSDharmik Thakkar 	handle = rte_hash_create(&ut_params);
540a55f182bSDharmik Thakkar 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
541a55f182bSDharmik Thakkar 	ut_params.extra_flag = extra_flag;
542a55f182bSDharmik Thakkar 
543a55f182bSDharmik Thakkar 	/*
544a55f182bSDharmik Thakkar 	 * The number of iterations is at least the same as the number of slots
545a55f182bSDharmik Thakkar 	 * rte_hash allocates internally. This is to reveal potential issues of
546a55f182bSDharmik Thakkar 	 * not freeing keys successfully.
547a55f182bSDharmik Thakkar 	 */
548a55f182bSDharmik Thakkar 	for (i = 0; i < ut_params.entries + 1; i++) {
549a55f182bSDharmik Thakkar 		hash_value = rte_hash_hash(handle, &keys[0]);
550a55f182bSDharmik Thakkar 		pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
551a55f182bSDharmik Thakkar 		print_key_info("Add", &keys[0], pos);
552a55f182bSDharmik Thakkar 		RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
553a55f182bSDharmik Thakkar 		expectedPos = pos;
554a55f182bSDharmik Thakkar 
555a55f182bSDharmik Thakkar 		pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
556a55f182bSDharmik Thakkar 		print_key_info("Del", &keys[0], pos);
557a55f182bSDharmik Thakkar 		RETURN_IF_ERROR(pos != expectedPos,
558a55f182bSDharmik Thakkar 				"failed to delete key (pos=%d)", pos);
559a55f182bSDharmik Thakkar 		delPos = pos;
560a55f182bSDharmik Thakkar 
561a55f182bSDharmik Thakkar 		pos = rte_hash_free_key_with_position(handle, delPos);
562a55f182bSDharmik Thakkar 		print_key_info("Free", &keys[0], delPos);
563a55f182bSDharmik Thakkar 		RETURN_IF_ERROR(pos != 0,
564a55f182bSDharmik Thakkar 				"failed to free key (pos=%d)", delPos);
565a55f182bSDharmik Thakkar 	}
566a55f182bSDharmik Thakkar 
567a55f182bSDharmik Thakkar 	rte_hash_free(handle);
568a55f182bSDharmik Thakkar 
569a55f182bSDharmik Thakkar 	extra_flag = ut_params.extra_flag;
570a55f182bSDharmik Thakkar 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
571a55f182bSDharmik Thakkar 				RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
572a55f182bSDharmik Thakkar 	handle = rte_hash_create(&ut_params);
573a55f182bSDharmik Thakkar 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
574a55f182bSDharmik Thakkar 	ut_params.extra_flag = extra_flag;
575a55f182bSDharmik Thakkar 
576a55f182bSDharmik Thakkar 	ip_src = keys[0].ip_src;
577a55f182bSDharmik Thakkar 	/*
578a55f182bSDharmik Thakkar 	 * The number of iterations is at least the same as the number of slots
579a55f182bSDharmik Thakkar 	 * rte_hash allocates internally. This is to reveal potential issues of
580a55f182bSDharmik Thakkar 	 * not freeing keys successfully.
581a55f182bSDharmik Thakkar 	 */
582a55f182bSDharmik Thakkar 	for (i = 0; i < ut_params.entries + (RTE_MAX_LCORE - 1) *
583a55f182bSDharmik Thakkar 					(LCORE_CACHE_SIZE - 1) + 1; i++) {
584a55f182bSDharmik Thakkar 		keys[0].ip_src++;
585a55f182bSDharmik Thakkar 		hash_value = rte_hash_hash(handle, &keys[0]);
586a55f182bSDharmik Thakkar 		pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
587a55f182bSDharmik Thakkar 		print_key_info("Add", &keys[0], pos);
588a55f182bSDharmik Thakkar 		RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
589a55f182bSDharmik Thakkar 		expectedPos = pos;
590a55f182bSDharmik Thakkar 
591a55f182bSDharmik Thakkar 		pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
592a55f182bSDharmik Thakkar 		print_key_info("Del", &keys[0], pos);
593a55f182bSDharmik Thakkar 		RETURN_IF_ERROR(pos != expectedPos,
594a55f182bSDharmik Thakkar 			"failed to delete key (pos=%d)", pos);
595a55f182bSDharmik Thakkar 		delPos = pos;
596a55f182bSDharmik Thakkar 
597a55f182bSDharmik Thakkar 		pos = rte_hash_free_key_with_position(handle, delPos);
598a55f182bSDharmik Thakkar 		print_key_info("Free", &keys[0], delPos);
599a55f182bSDharmik Thakkar 		RETURN_IF_ERROR(pos != 0,
600a55f182bSDharmik Thakkar 			"failed to free key (pos=%d)", delPos);
601a55f182bSDharmik Thakkar 	}
602a55f182bSDharmik Thakkar 	keys[0].ip_src = ip_src;
603a55f182bSDharmik Thakkar 
604a55f182bSDharmik Thakkar 	rte_hash_free(handle);
605a55f182bSDharmik Thakkar 
606a55f182bSDharmik Thakkar 	return 0;
607a55f182bSDharmik Thakkar }
608a55f182bSDharmik Thakkar 
609a55f182bSDharmik Thakkar /*
610a9de470cSBruce Richardson  * Sequence of operations for retrieving a key with its position
611a9de470cSBruce Richardson  *
612a9de470cSBruce Richardson  *  - create table
613a9de470cSBruce Richardson  *  - add key
614a9de470cSBruce Richardson  *  - get the key with its position: hit
615a9de470cSBruce Richardson  *  - delete key
616a9de470cSBruce Richardson  *  - try to get the deleted key: miss
617a9de470cSBruce Richardson  *
618a9de470cSBruce Richardson  * Repeat the test case when 'free on delete' is disabled.
619a9de470cSBruce Richardson  *  - create table
620a9de470cSBruce Richardson  *  - add key
621a9de470cSBruce Richardson  *  - get the key with its position: hit
622a9de470cSBruce Richardson  *  - delete key
623a9de470cSBruce Richardson  *  - try to get the deleted key: hit
624a9de470cSBruce Richardson  *  - free key
625a9de470cSBruce Richardson  *  - try to get the deleted key: miss
626a9de470cSBruce Richardson  *
627a9de470cSBruce Richardson  */
628a9de470cSBruce Richardson static int test_hash_get_key_with_position(void)
629a9de470cSBruce Richardson {
630a9de470cSBruce Richardson 	struct rte_hash *handle = NULL;
631a9de470cSBruce Richardson 	int pos, expectedPos, delPos, result;
632a9de470cSBruce Richardson 	void *key;
633a9de470cSBruce Richardson 
634a9de470cSBruce Richardson 	ut_params.name = "hash_get_key_w_pos";
635a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
636a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
637a9de470cSBruce Richardson 
638a9de470cSBruce Richardson 	pos = rte_hash_add_key(handle, &keys[0]);
639a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos);
640a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
641a9de470cSBruce Richardson 	expectedPos = pos;
642a9de470cSBruce Richardson 
643a9de470cSBruce Richardson 	result = rte_hash_get_key_with_position(handle, pos, &key);
644a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != 0, "error retrieving a key");
645a9de470cSBruce Richardson 
646a9de470cSBruce Richardson 	pos = rte_hash_del_key(handle, &keys[0]);
647a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], pos);
648a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos != expectedPos,
649a9de470cSBruce Richardson 			"failed to delete key (pos0=%d)", pos);
650a9de470cSBruce Richardson 
651a9de470cSBruce Richardson 	result = rte_hash_get_key_with_position(handle, pos, &key);
652a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
653a9de470cSBruce Richardson 
654a9de470cSBruce Richardson 	rte_hash_free(handle);
655a9de470cSBruce Richardson 
656a9de470cSBruce Richardson 	ut_params.name = "hash_get_key_w_pos";
657a9de470cSBruce Richardson 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
658a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
659a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
660a9de470cSBruce Richardson 	ut_params.extra_flag = 0;
661a9de470cSBruce Richardson 
662a9de470cSBruce Richardson 	pos = rte_hash_add_key(handle, &keys[0]);
663a9de470cSBruce Richardson 	print_key_info("Add", &keys[0], pos);
664a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
665a9de470cSBruce Richardson 	expectedPos = pos;
666a9de470cSBruce Richardson 
667a9de470cSBruce Richardson 	result = rte_hash_get_key_with_position(handle, pos, &key);
668a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != 0, "error retrieving a key");
669a9de470cSBruce Richardson 
670a9de470cSBruce Richardson 	delPos = rte_hash_del_key(handle, &keys[0]);
671a9de470cSBruce Richardson 	print_key_info("Del", &keys[0], delPos);
672a9de470cSBruce Richardson 	RETURN_IF_ERROR(delPos != expectedPos,
673a9de470cSBruce Richardson 			"failed to delete key (pos0=%d)", delPos);
674a9de470cSBruce Richardson 
675a9de470cSBruce Richardson 	result = rte_hash_get_key_with_position(handle, delPos, &key);
676a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
677a9de470cSBruce Richardson 
678a9de470cSBruce Richardson 	result = rte_hash_free_key_with_position(handle, delPos);
679a9de470cSBruce Richardson 	print_key_info("Free", &keys[0], delPos);
680a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != 0,
681a9de470cSBruce Richardson 			"failed to free key (pos1=%d)", delPos);
682a9de470cSBruce Richardson 
683a9de470cSBruce Richardson 	result = rte_hash_get_key_with_position(handle, delPos, &key);
684a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
685a9de470cSBruce Richardson 
686a9de470cSBruce Richardson 	rte_hash_free(handle);
687a9de470cSBruce Richardson 	return 0;
688a9de470cSBruce Richardson }
689a9de470cSBruce Richardson 
690a9de470cSBruce Richardson /*
691a9de470cSBruce Richardson  * Sequence of operations for find existing hash table
692a9de470cSBruce Richardson  *
693a9de470cSBruce Richardson  *  - create table
694a9de470cSBruce Richardson  *  - find existing table: hit
695a9de470cSBruce Richardson  *  - find non-existing table: miss
696a9de470cSBruce Richardson  *
697a9de470cSBruce Richardson  */
698a9de470cSBruce Richardson static int test_hash_find_existing(void)
699a9de470cSBruce Richardson {
700a9de470cSBruce Richardson 	struct rte_hash *handle = NULL, *result = NULL;
701a9de470cSBruce Richardson 
702a9de470cSBruce Richardson 	/* Create hash table. */
703a9de470cSBruce Richardson 	ut_params.name = "hash_find_existing";
704a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
705a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
706a9de470cSBruce Richardson 
707a9de470cSBruce Richardson 	/* Try to find existing hash table */
708a9de470cSBruce Richardson 	result = rte_hash_find_existing("hash_find_existing");
709a9de470cSBruce Richardson 	RETURN_IF_ERROR(result != handle, "could not find existing hash table");
710a9de470cSBruce Richardson 
711a9de470cSBruce Richardson 	/* Try to find non-existing hash table */
712a9de470cSBruce Richardson 	result = rte_hash_find_existing("hash_find_non_existing");
713a9de470cSBruce Richardson 	RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
714a9de470cSBruce Richardson 
715a9de470cSBruce Richardson 	/* Cleanup. */
716a9de470cSBruce Richardson 	rte_hash_free(handle);
717a9de470cSBruce Richardson 
718a9de470cSBruce Richardson 	return 0;
719a9de470cSBruce Richardson }
720a9de470cSBruce Richardson 
721a9de470cSBruce Richardson /*
722a9de470cSBruce Richardson  * Sequence of operations for 5 keys
723a9de470cSBruce Richardson  *	- add keys
724a9de470cSBruce Richardson  *	- lookup keys: hit
725a9de470cSBruce Richardson  *	- add keys (update)
726a9de470cSBruce Richardson  *	- lookup keys: hit (updated data)
727a9de470cSBruce Richardson  *	- delete keys : hit
728a9de470cSBruce Richardson  *	- lookup keys: miss
729a9de470cSBruce Richardson  */
730a9de470cSBruce Richardson static int test_five_keys(void)
731a9de470cSBruce Richardson {
732a9de470cSBruce Richardson 	struct rte_hash *handle;
733a9de470cSBruce Richardson 	const void *key_array[5] = {0};
734a9de470cSBruce Richardson 	int pos[5];
735a9de470cSBruce Richardson 	int expected_pos[5];
736a9de470cSBruce Richardson 	unsigned i;
737a9de470cSBruce Richardson 	int ret;
738a9de470cSBruce Richardson 
739a9de470cSBruce Richardson 	ut_params.name = "test3";
740a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
741a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
742a9de470cSBruce Richardson 
743a9de470cSBruce Richardson 	/* Add */
744a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
745a9de470cSBruce Richardson 		pos[i] = rte_hash_add_key(handle, &keys[i]);
746a9de470cSBruce Richardson 		print_key_info("Add", &keys[i], pos[i]);
747a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] < 0,
748a9de470cSBruce Richardson 				"failed to add key (pos[%u]=%d)", i, pos[i]);
749a9de470cSBruce Richardson 		expected_pos[i] = pos[i];
750a9de470cSBruce Richardson 	}
751a9de470cSBruce Richardson 
752a9de470cSBruce Richardson 	/* Lookup */
753a9de470cSBruce Richardson 	for(i = 0; i < 5; i++)
754a9de470cSBruce Richardson 		key_array[i] = &keys[i];
755a9de470cSBruce Richardson 
756a9de470cSBruce Richardson 	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
757a9de470cSBruce Richardson 	if(ret == 0)
758a9de470cSBruce Richardson 		for(i = 0; i < 5; i++) {
759a9de470cSBruce Richardson 			print_key_info("Lkp", key_array[i], pos[i]);
760a9de470cSBruce Richardson 			RETURN_IF_ERROR(pos[i] != expected_pos[i],
761a9de470cSBruce Richardson 					"failed to find key (pos[%u]=%d)", i, pos[i]);
762a9de470cSBruce Richardson 		}
763a9de470cSBruce Richardson 
764a9de470cSBruce Richardson 	/* Add - update */
765a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
766a9de470cSBruce Richardson 		pos[i] = rte_hash_add_key(handle, &keys[i]);
767a9de470cSBruce Richardson 		print_key_info("Add", &keys[i], pos[i]);
768a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
769a9de470cSBruce Richardson 				"failed to add key (pos[%u]=%d)", i, pos[i]);
770a9de470cSBruce Richardson 	}
771a9de470cSBruce Richardson 
772a9de470cSBruce Richardson 	/* Lookup */
773a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
774a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &keys[i]);
775a9de470cSBruce Richardson 		print_key_info("Lkp", &keys[i], pos[i]);
776a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
777a9de470cSBruce Richardson 				"failed to find key (pos[%u]=%d)", i, pos[i]);
778a9de470cSBruce Richardson 	}
779a9de470cSBruce Richardson 
780a9de470cSBruce Richardson 	/* Delete */
781a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
782a9de470cSBruce Richardson 		pos[i] = rte_hash_del_key(handle, &keys[i]);
783a9de470cSBruce Richardson 		print_key_info("Del", &keys[i], pos[i]);
784a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
785a9de470cSBruce Richardson 				"failed to delete key (pos[%u]=%d)", i, pos[i]);
786a9de470cSBruce Richardson 	}
787a9de470cSBruce Richardson 
788a9de470cSBruce Richardson 	/* Lookup */
789a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
790a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &keys[i]);
791a9de470cSBruce Richardson 		print_key_info("Lkp", &keys[i], pos[i]);
792a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != -ENOENT,
793a9de470cSBruce Richardson 				"found non-existent key (pos[%u]=%d)", i, pos[i]);
794a9de470cSBruce Richardson 	}
795a9de470cSBruce Richardson 
796a9de470cSBruce Richardson 	/* Lookup multi */
797a9de470cSBruce Richardson 	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
798a9de470cSBruce Richardson 	if (ret == 0)
799a9de470cSBruce Richardson 		for (i = 0; i < 5; i++) {
800a9de470cSBruce Richardson 			print_key_info("Lkp", key_array[i], pos[i]);
801a9de470cSBruce Richardson 			RETURN_IF_ERROR(pos[i] != -ENOENT,
802a9de470cSBruce Richardson 					"found not-existent key (pos[%u]=%d)", i, pos[i]);
803a9de470cSBruce Richardson 		}
804a9de470cSBruce Richardson 
805a9de470cSBruce Richardson 	rte_hash_free(handle);
806a9de470cSBruce Richardson 
807a9de470cSBruce Richardson 	return 0;
808a9de470cSBruce Richardson }
809a9de470cSBruce Richardson 
810a9de470cSBruce Richardson /*
811a9de470cSBruce Richardson  * Add keys to the same bucket until bucket full.
81264b2907cSYoan Picchi  *	- add 9 keys to the same bucket (hash created with 8 keys per bucket):
81364b2907cSYoan Picchi  *	  first 8 successful, 9th successful, pushing existing item in bucket
81464b2907cSYoan Picchi  *	- lookup the 9 keys: 9 hits
81564b2907cSYoan Picchi  *	- bulk lookup for all the 9 keys: 9 hits
81664b2907cSYoan Picchi  *	- add the 9 keys again: 9 OK
81764b2907cSYoan Picchi  *	- lookup the 9 keys: 9 hits (updated data)
81864b2907cSYoan Picchi  *	- delete the 9 keys: 9 OK
81964b2907cSYoan Picchi  *	- lookup the 9 keys: 9 misses
82064b2907cSYoan Picchi  *	- bulk lookup for all the 9 keys: 9 misses
821a9de470cSBruce Richardson  */
822a9de470cSBruce Richardson static int test_full_bucket(void)
823a9de470cSBruce Richardson {
824a9de470cSBruce Richardson 	struct rte_hash_parameters params_pseudo_hash = {
825a9de470cSBruce Richardson 		.name = "test4",
826a9de470cSBruce Richardson 		.entries = 64,
827e30ef3a3SVladimir Medvedkin 		.key_len = sizeof(struct flow_key),
828a9de470cSBruce Richardson 		.hash_func = pseudo_hash,
829a9de470cSBruce Richardson 		.hash_func_init_val = 0,
830a9de470cSBruce Richardson 		.socket_id = 0,
831a9de470cSBruce Richardson 	};
83264b2907cSYoan Picchi 	const void *key_array[KEY_PER_BUCKET+1] = {0};
833a9de470cSBruce Richardson 	struct rte_hash *handle;
83464b2907cSYoan Picchi 	int pos[KEY_PER_BUCKET+1];
83564b2907cSYoan Picchi 	int expected_pos[KEY_PER_BUCKET+1];
836a9de470cSBruce Richardson 	unsigned i;
83764b2907cSYoan Picchi 	int ret;
838a9de470cSBruce Richardson 	handle = rte_hash_create(&params_pseudo_hash);
839a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
840a9de470cSBruce Richardson 
841a9de470cSBruce Richardson 	/* Fill bucket */
84264b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET; i++) {
843a9de470cSBruce Richardson 		pos[i] = rte_hash_add_key(handle, &keys[i]);
844a9de470cSBruce Richardson 		print_key_info("Add", &keys[i], pos[i]);
845a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] < 0,
846a9de470cSBruce Richardson 			"failed to add key (pos[%u]=%d)", i, pos[i]);
847a9de470cSBruce Richardson 		expected_pos[i] = pos[i];
848a9de470cSBruce Richardson 	}
849a9de470cSBruce Richardson 	/*
850a9de470cSBruce Richardson 	 * This should work and will push one of the items
851a9de470cSBruce Richardson 	 * in the bucket because it is full
852a9de470cSBruce Richardson 	 */
85364b2907cSYoan Picchi 	pos[KEY_PER_BUCKET] = rte_hash_add_key(handle, &keys[KEY_PER_BUCKET]);
85464b2907cSYoan Picchi 	print_key_info("Add", &keys[KEY_PER_BUCKET], pos[KEY_PER_BUCKET]);
85564b2907cSYoan Picchi 	RETURN_IF_ERROR(pos[KEY_PER_BUCKET] < 0,
85664b2907cSYoan Picchi 			"failed to add key (pos[%d]=%d)", KEY_PER_BUCKET, pos[KEY_PER_BUCKET]);
85764b2907cSYoan Picchi 	expected_pos[KEY_PER_BUCKET] = pos[KEY_PER_BUCKET];
858a9de470cSBruce Richardson 
859a9de470cSBruce Richardson 	/* Lookup */
86064b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
861a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &keys[i]);
862a9de470cSBruce Richardson 		print_key_info("Lkp", &keys[i], pos[i]);
863a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
864a9de470cSBruce Richardson 			"failed to find key (pos[%u]=%d)", i, pos[i]);
865a9de470cSBruce Richardson 	}
866a9de470cSBruce Richardson 
86764b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++)
86864b2907cSYoan Picchi 		key_array[i] = &keys[i];
86964b2907cSYoan Picchi 
87064b2907cSYoan Picchi 	/*Bulk lookup after add with same hash*/
87164b2907cSYoan Picchi 	ret = rte_hash_lookup_bulk(handle, key_array, KEY_PER_BUCKET+1, (int32_t *)pos);
87264b2907cSYoan Picchi 	RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret);
87364b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
87464b2907cSYoan Picchi 		print_key_info("Blk_Lkp", key_array[i], pos[i]);
87564b2907cSYoan Picchi 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
87664b2907cSYoan Picchi 				"failed to find key (pos[%u]=%d)", i, pos[i]);
87764b2907cSYoan Picchi 	}
87864b2907cSYoan Picchi 
87964b2907cSYoan Picchi 
88064b2907cSYoan Picchi 
881a9de470cSBruce Richardson 	/* Add - update */
88264b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
883a9de470cSBruce Richardson 		pos[i] = rte_hash_add_key(handle, &keys[i]);
884a9de470cSBruce Richardson 		print_key_info("Add", &keys[i], pos[i]);
885a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
886a9de470cSBruce Richardson 			"failed to add key (pos[%u]=%d)", i, pos[i]);
887a9de470cSBruce Richardson 	}
888a9de470cSBruce Richardson 
889a9de470cSBruce Richardson 	/* Lookup */
89064b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
891a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &keys[i]);
892a9de470cSBruce Richardson 		print_key_info("Lkp", &keys[i], pos[i]);
893a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
894a9de470cSBruce Richardson 			"failed to find key (pos[%u]=%d)", i, pos[i]);
895a9de470cSBruce Richardson 	}
896a9de470cSBruce Richardson 
897a9de470cSBruce Richardson 	/* Delete 1 key, check other keys are still found */
898a9de470cSBruce Richardson 	pos[1] = rte_hash_del_key(handle, &keys[1]);
899a9de470cSBruce Richardson 	print_key_info("Del", &keys[1], pos[1]);
900a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos[1] != expected_pos[1],
901a9de470cSBruce Richardson 			"failed to delete key (pos[1]=%d)", pos[1]);
902a9de470cSBruce Richardson 	pos[3] = rte_hash_lookup(handle, &keys[3]);
903a9de470cSBruce Richardson 	print_key_info("Lkp", &keys[3], pos[3]);
904a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos[3] != expected_pos[3],
905a9de470cSBruce Richardson 			"failed lookup after deleting key from same bucket "
906a9de470cSBruce Richardson 			"(pos[3]=%d)", pos[3]);
907a9de470cSBruce Richardson 
908a9de470cSBruce Richardson 	/* Go back to previous state */
909a9de470cSBruce Richardson 	pos[1] = rte_hash_add_key(handle, &keys[1]);
910a9de470cSBruce Richardson 	print_key_info("Add", &keys[1], pos[1]);
911a9de470cSBruce Richardson 	expected_pos[1] = pos[1];
912a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
913a9de470cSBruce Richardson 
914a9de470cSBruce Richardson 	/* Delete */
91564b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
916a9de470cSBruce Richardson 		pos[i] = rte_hash_del_key(handle, &keys[i]);
917a9de470cSBruce Richardson 		print_key_info("Del", &keys[i], pos[i]);
918a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
919a9de470cSBruce Richardson 			"failed to delete key (pos[%u]=%d)", i, pos[i]);
920a9de470cSBruce Richardson 	}
921a9de470cSBruce Richardson 
922a9de470cSBruce Richardson 	/* Lookup */
92364b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
924a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &keys[i]);
925a9de470cSBruce Richardson 		print_key_info("Lkp", &keys[i], pos[i]);
926a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != -ENOENT,
927a9de470cSBruce Richardson 			"fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
928a9de470cSBruce Richardson 	}
929a9de470cSBruce Richardson 
93064b2907cSYoan Picchi 	/* Bulk Lookup on empty table*/
93164b2907cSYoan Picchi 	ret = rte_hash_lookup_bulk(handle, &key_array[0], KEY_PER_BUCKET+1, (int32_t *)pos);
93264b2907cSYoan Picchi 	RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret);
93364b2907cSYoan Picchi 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
93464b2907cSYoan Picchi 		print_key_info("Blk_Lkp", key_array[i], pos[i]);
93564b2907cSYoan Picchi 		RETURN_IF_ERROR(pos[i] != -ENOENT,
93664b2907cSYoan Picchi 				"failed to find key (pos[%u]=%d)", i, pos[i]);
93764b2907cSYoan Picchi 	}
93864b2907cSYoan Picchi 
939a9de470cSBruce Richardson 	rte_hash_free(handle);
940a9de470cSBruce Richardson 
941a9de470cSBruce Richardson 	/* Cover the NULL case. */
942a9de470cSBruce Richardson 	rte_hash_free(0);
943a9de470cSBruce Richardson 	return 0;
944a9de470cSBruce Richardson }
945a9de470cSBruce Richardson 
946a9de470cSBruce Richardson /*
947a9de470cSBruce Richardson  * Similar to the test above (full bucket test), but for extendable buckets.
948a9de470cSBruce Richardson  */
949a9de470cSBruce Richardson static int test_extendable_bucket(void)
950a9de470cSBruce Richardson {
951a9de470cSBruce Richardson 	struct rte_hash_parameters params_pseudo_hash = {
952a9de470cSBruce Richardson 		.name = "test5",
953a9de470cSBruce Richardson 		.entries = 64,
954e30ef3a3SVladimir Medvedkin 		.key_len = sizeof(struct flow_key),
955a9de470cSBruce Richardson 		.hash_func = pseudo_hash,
956a9de470cSBruce Richardson 		.hash_func_init_val = 0,
957a9de470cSBruce Richardson 		.socket_id = 0,
958a9de470cSBruce Richardson 		.extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE
959a9de470cSBruce Richardson 	};
960a9de470cSBruce Richardson 	struct rte_hash *handle;
961a9de470cSBruce Richardson 	int pos[64];
962a9de470cSBruce Richardson 	int expected_pos[64];
963a9de470cSBruce Richardson 	unsigned int i;
964a9de470cSBruce Richardson 	struct flow_key rand_keys[64];
965a9de470cSBruce Richardson 
966a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
967a9de470cSBruce Richardson 		rand_keys[i].port_dst = i;
968a9de470cSBruce Richardson 		rand_keys[i].port_src = i+1;
969a9de470cSBruce Richardson 	}
970a9de470cSBruce Richardson 
971a9de470cSBruce Richardson 	handle = rte_hash_create(&params_pseudo_hash);
972a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
973a9de470cSBruce Richardson 
974a9de470cSBruce Richardson 	/* Fill bucket */
975a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
976a9de470cSBruce Richardson 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
977a9de470cSBruce Richardson 		print_key_info("Add", &rand_keys[i], pos[i]);
978a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] < 0,
979a9de470cSBruce Richardson 			"failed to add key (pos[%u]=%d)", i, pos[i]);
980a9de470cSBruce Richardson 		expected_pos[i] = pos[i];
981a9de470cSBruce Richardson 	}
982a9de470cSBruce Richardson 
983a9de470cSBruce Richardson 	/* Lookup */
984a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
985a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
986a9de470cSBruce Richardson 		print_key_info("Lkp", &rand_keys[i], pos[i]);
987a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
988a9de470cSBruce Richardson 			"failed to find key (pos[%u]=%d)", i, pos[i]);
989a9de470cSBruce Richardson 	}
990a9de470cSBruce Richardson 
991a9de470cSBruce Richardson 	/* Add - update */
992a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
993a9de470cSBruce Richardson 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
994a9de470cSBruce Richardson 		print_key_info("Add", &rand_keys[i], pos[i]);
995a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
996a9de470cSBruce Richardson 			"failed to add key (pos[%u]=%d)", i, pos[i]);
997a9de470cSBruce Richardson 	}
998a9de470cSBruce Richardson 
999a9de470cSBruce Richardson 	/* Lookup */
1000a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
1001a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
1002a9de470cSBruce Richardson 		print_key_info("Lkp", &rand_keys[i], pos[i]);
1003a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
1004a9de470cSBruce Richardson 			"failed to find key (pos[%u]=%d)", i, pos[i]);
1005a9de470cSBruce Richardson 	}
1006a9de470cSBruce Richardson 
1007a9de470cSBruce Richardson 	/* Delete 1 key, check other keys are still found */
1008a9de470cSBruce Richardson 	pos[35] = rte_hash_del_key(handle, &rand_keys[35]);
1009a9de470cSBruce Richardson 	print_key_info("Del", &rand_keys[35], pos[35]);
1010a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos[35] != expected_pos[35],
1011a9de470cSBruce Richardson 			"failed to delete key (pos[1]=%d)", pos[35]);
1012a9de470cSBruce Richardson 	pos[20] = rte_hash_lookup(handle, &rand_keys[20]);
1013a9de470cSBruce Richardson 	print_key_info("Lkp", &rand_keys[20], pos[20]);
1014a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos[20] != expected_pos[20],
1015a9de470cSBruce Richardson 			"failed lookup after deleting key from same bucket "
1016a9de470cSBruce Richardson 			"(pos[20]=%d)", pos[20]);
1017a9de470cSBruce Richardson 
1018a9de470cSBruce Richardson 	/* Go back to previous state */
1019a9de470cSBruce Richardson 	pos[35] = rte_hash_add_key(handle, &rand_keys[35]);
1020a9de470cSBruce Richardson 	print_key_info("Add", &rand_keys[35], pos[35]);
1021a9de470cSBruce Richardson 	expected_pos[35] = pos[35];
1022a9de470cSBruce Richardson 	RETURN_IF_ERROR(pos[35] < 0, "failed to add key (pos[1]=%d)", pos[35]);
1023a9de470cSBruce Richardson 
1024a9de470cSBruce Richardson 	/* Delete */
1025a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
1026a9de470cSBruce Richardson 		pos[i] = rte_hash_del_key(handle, &rand_keys[i]);
1027a9de470cSBruce Richardson 		print_key_info("Del", &rand_keys[i], pos[i]);
1028a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
1029a9de470cSBruce Richardson 			"failed to delete key (pos[%u]=%d)", i, pos[i]);
1030a9de470cSBruce Richardson 	}
1031a9de470cSBruce Richardson 
1032a9de470cSBruce Richardson 	/* Lookup */
1033a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
1034a9de470cSBruce Richardson 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
1035a9de470cSBruce Richardson 		print_key_info("Lkp", &rand_keys[i], pos[i]);
1036a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] != -ENOENT,
1037a9de470cSBruce Richardson 			"fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
1038a9de470cSBruce Richardson 	}
1039a9de470cSBruce Richardson 
1040a9de470cSBruce Richardson 	/* Add again */
1041a9de470cSBruce Richardson 	for (i = 0; i < 64; i++) {
1042a9de470cSBruce Richardson 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
1043a9de470cSBruce Richardson 		print_key_info("Add", &rand_keys[i], pos[i]);
1044a9de470cSBruce Richardson 		RETURN_IF_ERROR(pos[i] < 0,
1045a9de470cSBruce Richardson 			"failed to add key (pos[%u]=%d)", i, pos[i]);
1046a9de470cSBruce Richardson 		expected_pos[i] = pos[i];
1047a9de470cSBruce Richardson 	}
1048a9de470cSBruce Richardson 
1049a9de470cSBruce Richardson 	rte_hash_free(handle);
1050a9de470cSBruce Richardson 
1051a9de470cSBruce Richardson 	/* Cover the NULL case. */
1052a9de470cSBruce Richardson 	rte_hash_free(0);
1053a9de470cSBruce Richardson 	return 0;
1054a9de470cSBruce Richardson }
1055a9de470cSBruce Richardson 
1056a9de470cSBruce Richardson /******************************************************************************/
1057a9de470cSBruce Richardson static int
1058a9de470cSBruce Richardson fbk_hash_unit_test(void)
1059a9de470cSBruce Richardson {
1060a9de470cSBruce Richardson 	struct rte_fbk_hash_params params = {
1061a9de470cSBruce Richardson 		.name = "fbk_hash_test",
1062a9de470cSBruce Richardson 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1063a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1064a9de470cSBruce Richardson 		.socket_id = 0,
1065a9de470cSBruce Richardson 	};
1066a9de470cSBruce Richardson 
1067a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_1 = {
1068a9de470cSBruce Richardson 		.name = "invalid_1",
1069a9de470cSBruce Richardson 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
1070a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1071a9de470cSBruce Richardson 		.socket_id = 0,
1072a9de470cSBruce Richardson 	};
1073a9de470cSBruce Richardson 
1074a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_2 = {
1075a9de470cSBruce Richardson 		.name = "invalid_2",
1076a9de470cSBruce Richardson 		.entries = 4,
1077a9de470cSBruce Richardson 		.entries_per_bucket = 3,         /* Not power of 2 */
1078a9de470cSBruce Richardson 		.socket_id = 0,
1079a9de470cSBruce Richardson 	};
1080a9de470cSBruce Richardson 
1081a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_3 = {
1082a9de470cSBruce Richardson 		.name = "invalid_3",
1083a9de470cSBruce Richardson 		.entries = 0,                    /* Entries is 0 */
1084a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1085a9de470cSBruce Richardson 		.socket_id = 0,
1086a9de470cSBruce Richardson 	};
1087a9de470cSBruce Richardson 
1088a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_4 = {
1089a9de470cSBruce Richardson 		.name = "invalid_4",
1090a9de470cSBruce Richardson 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1091a9de470cSBruce Richardson 		.entries_per_bucket = 0,         /* Entries per bucket is 0 */
1092a9de470cSBruce Richardson 		.socket_id = 0,
1093a9de470cSBruce Richardson 	};
1094a9de470cSBruce Richardson 
1095a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_5 = {
1096a9de470cSBruce Richardson 		.name = "invalid_5",
1097a9de470cSBruce Richardson 		.entries = 4,
1098a9de470cSBruce Richardson 		.entries_per_bucket = 8,         /* Entries per bucket > entries */
1099a9de470cSBruce Richardson 		.socket_id = 0,
1100a9de470cSBruce Richardson 	};
1101a9de470cSBruce Richardson 
1102a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_6 = {
1103a9de470cSBruce Richardson 		.name = "invalid_6",
1104a9de470cSBruce Richardson 		.entries = RTE_FBK_HASH_ENTRIES_MAX * 2,   /* Entries > max allowed */
1105a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1106a9de470cSBruce Richardson 		.socket_id = 0,
1107a9de470cSBruce Richardson 	};
1108a9de470cSBruce Richardson 
1109a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_7 = {
1110a9de470cSBruce Richardson 		.name = "invalid_7",
1111a9de470cSBruce Richardson 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
1112a9de470cSBruce Richardson 		.entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2,	/* Entries > max allowed */
1113a9de470cSBruce Richardson 		.socket_id = 0,
1114a9de470cSBruce Richardson 	};
1115a9de470cSBruce Richardson 
1116a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_8 = {
1117a9de470cSBruce Richardson 		.name = "invalid_7",
1118a9de470cSBruce Richardson 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
1119a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1120a9de470cSBruce Richardson 		.socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
1121a9de470cSBruce Richardson 	};
1122a9de470cSBruce Richardson 
1123a9de470cSBruce Richardson 	/* try to create two hashes with identical names
1124a9de470cSBruce Richardson 	 * in this case, trying to create a second one will not
1125a9de470cSBruce Richardson 	 * fail but will simply return pointer to the existing
1126a9de470cSBruce Richardson 	 * hash with that name. sort of like a "find hash by name" :-)
1127a9de470cSBruce Richardson 	 */
1128a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_same_name_1 = {
1129a9de470cSBruce Richardson 		.name = "same_name",				/* hash with identical name */
1130a9de470cSBruce Richardson 		.entries = 4,
1131a9de470cSBruce Richardson 		.entries_per_bucket = 2,
1132a9de470cSBruce Richardson 		.socket_id = 0,
1133a9de470cSBruce Richardson 	};
1134a9de470cSBruce Richardson 
1135a9de470cSBruce Richardson 	/* trying to create this hash should return a pointer to an existing hash */
1136a9de470cSBruce Richardson 	struct rte_fbk_hash_params invalid_params_same_name_2 = {
1137a9de470cSBruce Richardson 		.name = "same_name",				/* hash with identical name */
1138a9de470cSBruce Richardson 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
1139a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1140a9de470cSBruce Richardson 		.socket_id = 0,
1141a9de470cSBruce Richardson 	};
1142a9de470cSBruce Richardson 
1143a9de470cSBruce Richardson 	/* this is a sanity check for "same name" test
1144a9de470cSBruce Richardson 	 * creating this hash will check if we are actually able to create
1145a9de470cSBruce Richardson 	 * multiple hashes with different names (instead of having just one).
1146a9de470cSBruce Richardson 	 */
1147a9de470cSBruce Richardson 	struct rte_fbk_hash_params different_name = {
1148a9de470cSBruce Richardson 		.name = "different_name",			/* different name */
1149a9de470cSBruce Richardson 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1150a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1151a9de470cSBruce Richardson 		.socket_id = 0,
1152a9de470cSBruce Richardson 	};
1153a9de470cSBruce Richardson 
1154a9de470cSBruce Richardson 	struct rte_fbk_hash_params params_jhash = {
1155a9de470cSBruce Richardson 		.name = "valid",
1156a9de470cSBruce Richardson 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1157a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1158a9de470cSBruce Richardson 		.socket_id = 0,
1159a9de470cSBruce Richardson 		.hash_func = rte_jhash_1word,              /* Tests for different hash_func */
1160a9de470cSBruce Richardson 		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1161a9de470cSBruce Richardson 	};
1162a9de470cSBruce Richardson 
1163a9de470cSBruce Richardson 	struct rte_fbk_hash_params params_nohash = {
1164a9de470cSBruce Richardson 		.name = "valid nohash",
1165a9de470cSBruce Richardson 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1166a9de470cSBruce Richardson 		.entries_per_bucket = 4,
1167a9de470cSBruce Richardson 		.socket_id = 0,
1168a9de470cSBruce Richardson 		.hash_func = NULL,                            /* Tests for null hash_func */
1169a9de470cSBruce Richardson 		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1170a9de470cSBruce Richardson 	};
1171a9de470cSBruce Richardson 
1172a9de470cSBruce Richardson 	struct rte_fbk_hash_table *handle, *tmp;
1173a9de470cSBruce Richardson 	uint32_t keys[5] =
1174a9de470cSBruce Richardson 		{0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
1175a9de470cSBruce Richardson 	uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
1176a9de470cSBruce Richardson 	int status;
1177a9de470cSBruce Richardson 	unsigned i;
1178a9de470cSBruce Richardson 	double used_entries;
1179a9de470cSBruce Richardson 
1180a9de470cSBruce Richardson 	/* Try creating hashes with invalid parameters */
1181a9de470cSBruce Richardson 	printf("# Testing hash creation with invalid parameters "
1182a9de470cSBruce Richardson 			"- expect error msgs\n");
1183a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_1);
1184a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1185a9de470cSBruce Richardson 
1186a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_2);
1187a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1188a9de470cSBruce Richardson 
1189a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_3);
1190a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1191a9de470cSBruce Richardson 
1192a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_4);
1193a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1194a9de470cSBruce Richardson 
1195a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_5);
1196a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1197a9de470cSBruce Richardson 
1198a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_6);
1199a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1200a9de470cSBruce Richardson 
1201a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_7);
1202a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1203a9de470cSBruce Richardson 
120427fb5dd2SRuifeng Wang 	if (rte_eal_has_hugepages()) {
1205a9de470cSBruce Richardson 		handle = rte_fbk_hash_create(&invalid_params_8);
120627fb5dd2SRuifeng Wang 		RETURN_IF_ERROR_FBK(handle != NULL,
120727fb5dd2SRuifeng Wang 					"fbk hash creation should have failed");
120827fb5dd2SRuifeng Wang 	}
1209a9de470cSBruce Richardson 
1210a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&invalid_params_same_name_1);
1211a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
1212a9de470cSBruce Richardson 
1213a9de470cSBruce Richardson 	tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
1214a9de470cSBruce Richardson 	rte_fbk_hash_free(tmp);
1215a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
1216a9de470cSBruce Richardson 
1217a9de470cSBruce Richardson 	/* we are not freeing  handle here because we need a hash list
1218a9de470cSBruce Richardson 	 * to be not empty for the next test */
1219a9de470cSBruce Richardson 
1220a9de470cSBruce Richardson 	/* create a hash in non-empty list - good for coverage */
1221a9de470cSBruce Richardson 	tmp = rte_fbk_hash_create(&different_name);
1222a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
1223a9de470cSBruce Richardson 
1224a9de470cSBruce Richardson 	/* free both hashes */
1225a9de470cSBruce Richardson 	rte_fbk_hash_free(handle);
1226a9de470cSBruce Richardson 	rte_fbk_hash_free(tmp);
1227a9de470cSBruce Richardson 
1228a9de470cSBruce Richardson 	/* Create empty jhash hash. */
1229a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&params_jhash);
1230a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
1231a9de470cSBruce Richardson 
1232a9de470cSBruce Richardson 	/* Cleanup. */
1233a9de470cSBruce Richardson 	rte_fbk_hash_free(handle);
1234a9de470cSBruce Richardson 
1235a9de470cSBruce Richardson 	/* Create empty jhash hash. */
1236a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&params_nohash);
1237a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
1238a9de470cSBruce Richardson 
1239a9de470cSBruce Richardson 	/* Cleanup. */
1240a9de470cSBruce Richardson 	rte_fbk_hash_free(handle);
1241a9de470cSBruce Richardson 
1242a9de470cSBruce Richardson 	/* Create empty hash. */
1243a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&params);
1244a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1245a9de470cSBruce Richardson 
1246a9de470cSBruce Richardson 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1247a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1248a9de470cSBruce Richardson 				"load factor right after creation is not zero but it should be");
1249a9de470cSBruce Richardson 	/* Add keys. */
1250a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1251a9de470cSBruce Richardson 		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1252a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1253a9de470cSBruce Richardson 	}
1254a9de470cSBruce Richardson 
1255a9de470cSBruce Richardson 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1256a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
1257a9de470cSBruce Richardson 				"load factor now is not as expected");
1258a9de470cSBruce Richardson 	/* Find value of added keys. */
1259a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1260a9de470cSBruce Richardson 		status = rte_fbk_hash_lookup(handle, keys[i]);
1261a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status != vals[i],
1262a9de470cSBruce Richardson 				"fbk hash lookup failed");
1263a9de470cSBruce Richardson 	}
1264a9de470cSBruce Richardson 
1265a9de470cSBruce Richardson 	/* Change value of added keys. */
1266a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1267a9de470cSBruce Richardson 		status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
1268a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
1269a9de470cSBruce Richardson 	}
1270a9de470cSBruce Richardson 
1271a9de470cSBruce Richardson 	/* Find new values. */
1272a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1273a9de470cSBruce Richardson 		status = rte_fbk_hash_lookup(handle, keys[i]);
1274a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status != vals[4-i],
1275a9de470cSBruce Richardson 				"fbk hash lookup failed");
1276a9de470cSBruce Richardson 	}
1277a9de470cSBruce Richardson 
1278a9de470cSBruce Richardson 	/* Delete keys individually. */
1279a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1280a9de470cSBruce Richardson 		status = rte_fbk_hash_delete_key(handle, keys[i]);
1281a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
1282a9de470cSBruce Richardson 	}
1283a9de470cSBruce Richardson 
1284a9de470cSBruce Richardson 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1285a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1286a9de470cSBruce Richardson 				"load factor right after deletion is not zero but it should be");
1287a9de470cSBruce Richardson 	/* Lookup should now fail. */
1288a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1289a9de470cSBruce Richardson 		status = rte_fbk_hash_lookup(handle, keys[i]);
1290a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status == 0,
1291a9de470cSBruce Richardson 				"fbk hash lookup should have failed");
1292a9de470cSBruce Richardson 	}
1293a9de470cSBruce Richardson 
1294a9de470cSBruce Richardson 	/* Add keys again. */
1295a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1296a9de470cSBruce Richardson 		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1297a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1298a9de470cSBruce Richardson 	}
1299a9de470cSBruce Richardson 
1300a9de470cSBruce Richardson 	/* Make sure they were added. */
1301a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1302a9de470cSBruce Richardson 		status = rte_fbk_hash_lookup(handle, keys[i]);
1303a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status != vals[i],
1304a9de470cSBruce Richardson 				"fbk hash lookup failed");
1305a9de470cSBruce Richardson 	}
1306a9de470cSBruce Richardson 
1307a9de470cSBruce Richardson 	/* Clear all entries. */
1308a9de470cSBruce Richardson 	rte_fbk_hash_clear_all(handle);
1309a9de470cSBruce Richardson 
1310a9de470cSBruce Richardson 	/* Lookup should fail. */
1311a9de470cSBruce Richardson 	for (i = 0; i < 5; i++) {
1312a9de470cSBruce Richardson 		status = rte_fbk_hash_lookup(handle, keys[i]);
1313a9de470cSBruce Richardson 		RETURN_IF_ERROR_FBK(status == 0,
1314a9de470cSBruce Richardson 				"fbk hash lookup should have failed");
1315a9de470cSBruce Richardson 	}
1316a9de470cSBruce Richardson 
1317a9de470cSBruce Richardson 	/* coverage */
1318a9de470cSBruce Richardson 
1319a9de470cSBruce Richardson 	/* fill up the hash_table */
1320a9de470cSBruce Richardson 	for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
1321a9de470cSBruce Richardson 		rte_fbk_hash_add_key(handle, i, (uint16_t) i);
1322a9de470cSBruce Richardson 
1323a9de470cSBruce Richardson 	/* Find non-existent key in a full hashtable */
1324a9de470cSBruce Richardson 	status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1325a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(status != -ENOENT,
1326a9de470cSBruce Richardson 			"fbk hash lookup succeeded");
1327a9de470cSBruce Richardson 
1328a9de470cSBruce Richardson 	/* Delete non-existent key in a full hashtable */
1329a9de470cSBruce Richardson 	status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1330a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(status != -ENOENT,
1331a9de470cSBruce Richardson 			"fbk hash delete succeeded");
1332a9de470cSBruce Richardson 
1333a9de470cSBruce Richardson 	/* Delete one key from a full hashtable */
1334a9de470cSBruce Richardson 	status = rte_fbk_hash_delete_key(handle, 1);
1335a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(status != 0,
1336a9de470cSBruce Richardson 			"fbk hash delete failed");
1337a9de470cSBruce Richardson 
1338a9de470cSBruce Richardson 	/* Clear all entries. */
1339a9de470cSBruce Richardson 	rte_fbk_hash_clear_all(handle);
1340a9de470cSBruce Richardson 
1341a9de470cSBruce Richardson 	/* Cleanup. */
1342a9de470cSBruce Richardson 	rte_fbk_hash_free(handle);
1343a9de470cSBruce Richardson 
1344a9de470cSBruce Richardson 	/* Cover the NULL case. */
1345a9de470cSBruce Richardson 	rte_fbk_hash_free(0);
1346a9de470cSBruce Richardson 
1347a9de470cSBruce Richardson 	return 0;
1348a9de470cSBruce Richardson }
1349a9de470cSBruce Richardson 
1350a9de470cSBruce Richardson /*
1351a9de470cSBruce Richardson  * Sequence of operations for find existing fbk hash table
1352a9de470cSBruce Richardson  *
1353a9de470cSBruce Richardson  *  - create table
1354a9de470cSBruce Richardson  *  - find existing table: hit
1355a9de470cSBruce Richardson  *  - find non-existing table: miss
1356a9de470cSBruce Richardson  *
1357a9de470cSBruce Richardson  */
1358a9de470cSBruce Richardson static int test_fbk_hash_find_existing(void)
1359a9de470cSBruce Richardson {
1360a9de470cSBruce Richardson 	struct rte_fbk_hash_params params = {
1361a9de470cSBruce Richardson 			.name = "fbk_hash_find_existing",
1362a9de470cSBruce Richardson 			.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1363a9de470cSBruce Richardson 			.entries_per_bucket = 4,
1364a9de470cSBruce Richardson 			.socket_id = 0,
1365a9de470cSBruce Richardson 	};
1366a9de470cSBruce Richardson 	struct rte_fbk_hash_table *handle = NULL, *result = NULL;
1367a9de470cSBruce Richardson 
1368a9de470cSBruce Richardson 	/* Create hash table. */
1369a9de470cSBruce Richardson 	handle = rte_fbk_hash_create(&params);
1370a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1371a9de470cSBruce Richardson 
1372a9de470cSBruce Richardson 	/* Try to find existing fbk hash table */
1373a9de470cSBruce Richardson 	result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
1374a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
1375a9de470cSBruce Richardson 
1376a9de470cSBruce Richardson 	/* Try to find non-existing fbk hash table */
1377a9de470cSBruce Richardson 	result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
1378a9de470cSBruce Richardson 	RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
1379a9de470cSBruce Richardson 
1380a9de470cSBruce Richardson 	/* Cleanup. */
1381a9de470cSBruce Richardson 	rte_fbk_hash_free(handle);
1382a9de470cSBruce Richardson 
1383a9de470cSBruce Richardson 	return 0;
1384a9de470cSBruce Richardson }
1385a9de470cSBruce Richardson 
1386a9de470cSBruce Richardson #define BUCKET_ENTRIES 4
1387a9de470cSBruce Richardson /*
1388a9de470cSBruce Richardson  * Do tests for hash creation with bad parameters.
1389a9de470cSBruce Richardson  */
1390a9de470cSBruce Richardson static int test_hash_creation_with_bad_parameters(void)
1391a9de470cSBruce Richardson {
1392a9de470cSBruce Richardson 	struct rte_hash *handle, *tmp;
1393a9de470cSBruce Richardson 	struct rte_hash_parameters params;
1394a9de470cSBruce Richardson 
1395a9de470cSBruce Richardson 	handle = rte_hash_create(NULL);
1396a9de470cSBruce Richardson 	if (handle != NULL) {
1397a9de470cSBruce Richardson 		rte_hash_free(handle);
1398a9de470cSBruce Richardson 		printf("Impossible creating hash successfully without any parameter\n");
1399a9de470cSBruce Richardson 		return -1;
1400a9de470cSBruce Richardson 	}
1401a9de470cSBruce Richardson 
1402a9de470cSBruce Richardson 	memcpy(&params, &ut_params, sizeof(params));
1403a9de470cSBruce Richardson 	params.name = "creation_with_bad_parameters_0";
1404a9de470cSBruce Richardson 	params.entries = RTE_HASH_ENTRIES_MAX + 1;
1405a9de470cSBruce Richardson 	handle = rte_hash_create(&params);
1406a9de470cSBruce Richardson 	if (handle != NULL) {
1407a9de470cSBruce Richardson 		rte_hash_free(handle);
1408a9de470cSBruce Richardson 		printf("Impossible creating hash successfully with entries in parameter exceeded\n");
1409a9de470cSBruce Richardson 		return -1;
1410a9de470cSBruce Richardson 	}
1411a9de470cSBruce Richardson 
1412a9de470cSBruce Richardson 	memcpy(&params, &ut_params, sizeof(params));
1413a9de470cSBruce Richardson 	params.name = "creation_with_bad_parameters_2";
1414a9de470cSBruce Richardson 	params.entries = BUCKET_ENTRIES - 1;
1415a9de470cSBruce Richardson 	handle = rte_hash_create(&params);
1416a9de470cSBruce Richardson 	if (handle != NULL) {
1417a9de470cSBruce Richardson 		rte_hash_free(handle);
1418a9de470cSBruce Richardson 		printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n");
1419a9de470cSBruce Richardson 		return -1;
1420a9de470cSBruce Richardson 	}
1421a9de470cSBruce Richardson 
1422a9de470cSBruce Richardson 	memcpy(&params, &ut_params, sizeof(params));
1423a9de470cSBruce Richardson 	params.name = "creation_with_bad_parameters_3";
1424a9de470cSBruce Richardson 	params.key_len = 0;
1425a9de470cSBruce Richardson 	handle = rte_hash_create(&params);
1426a9de470cSBruce Richardson 	if (handle != NULL) {
1427a9de470cSBruce Richardson 		rte_hash_free(handle);
1428a9de470cSBruce Richardson 		printf("Impossible creating hash successfully if key_len in parameter is zero\n");
1429a9de470cSBruce Richardson 		return -1;
1430a9de470cSBruce Richardson 	}
1431a9de470cSBruce Richardson 
1432a9de470cSBruce Richardson 	memcpy(&params, &ut_params, sizeof(params));
1433a9de470cSBruce Richardson 	params.name = "creation_with_bad_parameters_4";
1434a9de470cSBruce Richardson 	params.socket_id = RTE_MAX_NUMA_NODES + 1;
1435a9de470cSBruce Richardson 	handle = rte_hash_create(&params);
1436a9de470cSBruce Richardson 	if (handle != NULL) {
1437a9de470cSBruce Richardson 		rte_hash_free(handle);
1438a9de470cSBruce Richardson 		printf("Impossible creating hash successfully with invalid socket\n");
1439a9de470cSBruce Richardson 		return -1;
1440a9de470cSBruce Richardson 	}
1441a9de470cSBruce Richardson 
1442a9de470cSBruce Richardson 	/* test with same name should fail */
1443a9de470cSBruce Richardson 	memcpy(&params, &ut_params, sizeof(params));
1444a9de470cSBruce Richardson 	params.name = "same_name";
1445a9de470cSBruce Richardson 	handle = rte_hash_create(&params);
1446a9de470cSBruce Richardson 	if (handle == NULL) {
1447a9de470cSBruce Richardson 		printf("Cannot create first hash table with 'same_name'\n");
1448a9de470cSBruce Richardson 		return -1;
1449a9de470cSBruce Richardson 	}
1450a9de470cSBruce Richardson 	tmp = rte_hash_create(&params);
1451a9de470cSBruce Richardson 	if (tmp != NULL) {
1452a9de470cSBruce Richardson 		printf("Creation of hash table with same name should fail\n");
1453a9de470cSBruce Richardson 		rte_hash_free(handle);
1454a9de470cSBruce Richardson 		rte_hash_free(tmp);
1455a9de470cSBruce Richardson 		return -1;
1456a9de470cSBruce Richardson 	}
1457a9de470cSBruce Richardson 	rte_hash_free(handle);
1458a9de470cSBruce Richardson 
1459a9de470cSBruce Richardson 	printf("# Test successful. No more errors expected\n");
1460a9de470cSBruce Richardson 
1461a9de470cSBruce Richardson 	return 0;
1462a9de470cSBruce Richardson }
1463a9de470cSBruce Richardson 
1464a9de470cSBruce Richardson /*
1465a9de470cSBruce Richardson  * Do tests for hash creation with parameters that look incorrect
1466a9de470cSBruce Richardson  * but are actually valid.
1467a9de470cSBruce Richardson  */
1468a9de470cSBruce Richardson static int
1469a9de470cSBruce Richardson test_hash_creation_with_good_parameters(void)
1470a9de470cSBruce Richardson {
1471a9de470cSBruce Richardson 	struct rte_hash *handle;
1472a9de470cSBruce Richardson 	struct rte_hash_parameters params;
1473a9de470cSBruce Richardson 
1474a9de470cSBruce Richardson 	/* create with null hash function - should choose DEFAULT_HASH_FUNC */
1475a9de470cSBruce Richardson 	memcpy(&params, &ut_params, sizeof(params));
1476a9de470cSBruce Richardson 	params.name = "name";
1477a9de470cSBruce Richardson 	params.hash_func = NULL;
1478a9de470cSBruce Richardson 	handle = rte_hash_create(&params);
1479a9de470cSBruce Richardson 	if (handle == NULL) {
1480a9de470cSBruce Richardson 		printf("Creating hash with null hash_func failed\n");
1481a9de470cSBruce Richardson 		return -1;
1482a9de470cSBruce Richardson 	}
1483a9de470cSBruce Richardson 
1484a9de470cSBruce Richardson 	rte_hash_free(handle);
1485a9de470cSBruce Richardson 
1486a9de470cSBruce Richardson 	return 0;
1487a9de470cSBruce Richardson }
1488a9de470cSBruce Richardson 
1489a9de470cSBruce Richardson #define ITERATIONS 3
1490a9de470cSBruce Richardson /*
1491a9de470cSBruce Richardson  * Test to see the average table utilization (entries added/max entries)
1492a9de470cSBruce Richardson  * before hitting a random entry that cannot be added
1493a9de470cSBruce Richardson  */
1494a9de470cSBruce Richardson static int test_average_table_utilization(uint32_t ext_table)
1495a9de470cSBruce Richardson {
1496a9de470cSBruce Richardson 	struct rte_hash *handle;
1497a9de470cSBruce Richardson 	uint8_t simple_key[MAX_KEYSIZE];
1498a9de470cSBruce Richardson 	unsigned i, j;
1499a9de470cSBruce Richardson 	unsigned added_keys, average_keys_added = 0;
1500a9de470cSBruce Richardson 	int ret;
1501a9de470cSBruce Richardson 	unsigned int cnt;
1502a9de470cSBruce Richardson 
1503a9de470cSBruce Richardson 	printf("\n# Running test to determine average utilization"
1504a9de470cSBruce Richardson 	       "\n  before adding elements begins to fail\n");
1505a9de470cSBruce Richardson 	if (ext_table)
1506a9de470cSBruce Richardson 		printf("ext table is enabled\n");
1507a9de470cSBruce Richardson 	else
1508a9de470cSBruce Richardson 		printf("ext table is disabled\n");
1509a9de470cSBruce Richardson 
1510a9de470cSBruce Richardson 	printf("Measuring performance, please wait");
1511a9de470cSBruce Richardson 	fflush(stdout);
1512a9de470cSBruce Richardson 	ut_params.entries = 1 << 16;
1513a9de470cSBruce Richardson 	ut_params.name = "test_average_utilization";
1514a9de470cSBruce Richardson 	ut_params.hash_func = rte_jhash;
1515a9de470cSBruce Richardson 	if (ext_table)
1516a9de470cSBruce Richardson 		ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1517a9de470cSBruce Richardson 	else
1518a9de470cSBruce Richardson 		ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1519a9de470cSBruce Richardson 
1520a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
1521a9de470cSBruce Richardson 
1522a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1523a9de470cSBruce Richardson 
1524a9de470cSBruce Richardson 	for (j = 0; j < ITERATIONS; j++) {
1525a9de470cSBruce Richardson 		ret = 0;
1526a9de470cSBruce Richardson 		/* Add random entries until key cannot be added */
1527a9de470cSBruce Richardson 		for (added_keys = 0; ret >= 0; added_keys++) {
1528a9de470cSBruce Richardson 			for (i = 0; i < ut_params.key_len; i++)
1529a9de470cSBruce Richardson 				simple_key[i] = rte_rand() % 255;
1530a9de470cSBruce Richardson 			ret = rte_hash_add_key(handle, simple_key);
1531a9de470cSBruce Richardson 			if (ret < 0)
1532a9de470cSBruce Richardson 				break;
1533a9de470cSBruce Richardson 		}
1534a9de470cSBruce Richardson 
1535a9de470cSBruce Richardson 		if (ret != -ENOSPC) {
1536a9de470cSBruce Richardson 			printf("Unexpected error when adding keys\n");
1537a9de470cSBruce Richardson 			rte_hash_free(handle);
1538a9de470cSBruce Richardson 			return -1;
1539a9de470cSBruce Richardson 		}
1540a9de470cSBruce Richardson 
1541a9de470cSBruce Richardson 		cnt = rte_hash_count(handle);
1542a9de470cSBruce Richardson 		if (cnt != added_keys) {
1543a9de470cSBruce Richardson 			printf("rte_hash_count returned wrong value %u, %u,"
1544a9de470cSBruce Richardson 					"%u\n", j, added_keys, cnt);
1545a9de470cSBruce Richardson 			rte_hash_free(handle);
1546a9de470cSBruce Richardson 			return -1;
1547a9de470cSBruce Richardson 		}
1548a9de470cSBruce Richardson 		if (ext_table) {
1549a9de470cSBruce Richardson 			if (cnt != ut_params.entries) {
1550a9de470cSBruce Richardson 				printf("rte_hash_count returned wrong value "
1551a9de470cSBruce Richardson 					"%u, %u, %u\n", j, added_keys, cnt);
1552a9de470cSBruce Richardson 				rte_hash_free(handle);
1553a9de470cSBruce Richardson 				return -1;
1554a9de470cSBruce Richardson 			}
1555a9de470cSBruce Richardson 		}
1556a9de470cSBruce Richardson 
1557a9de470cSBruce Richardson 		average_keys_added += added_keys;
1558a9de470cSBruce Richardson 
1559a9de470cSBruce Richardson 		/* Reset the table */
1560a9de470cSBruce Richardson 		rte_hash_reset(handle);
1561a9de470cSBruce Richardson 
1562a9de470cSBruce Richardson 		/* Print a dot to show progress on operations */
1563a9de470cSBruce Richardson 		printf(".");
1564a9de470cSBruce Richardson 		fflush(stdout);
1565a9de470cSBruce Richardson 	}
1566a9de470cSBruce Richardson 
1567a9de470cSBruce Richardson 	average_keys_added /= ITERATIONS;
1568a9de470cSBruce Richardson 
1569a9de470cSBruce Richardson 	printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
1570a9de470cSBruce Richardson 		((double) average_keys_added / ut_params.entries * 100),
1571a9de470cSBruce Richardson 		average_keys_added, ut_params.entries);
1572a9de470cSBruce Richardson 	rte_hash_free(handle);
1573a9de470cSBruce Richardson 
1574a9de470cSBruce Richardson 	return 0;
1575a9de470cSBruce Richardson }
1576a9de470cSBruce Richardson 
1577a9de470cSBruce Richardson #define NUM_ENTRIES 256
1578a9de470cSBruce Richardson static int test_hash_iteration(uint32_t ext_table)
1579a9de470cSBruce Richardson {
1580a9de470cSBruce Richardson 	struct rte_hash *handle;
1581a9de470cSBruce Richardson 	unsigned i;
1582a9de470cSBruce Richardson 	uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE];
1583a9de470cSBruce Richardson 	const void *next_key;
1584a9de470cSBruce Richardson 	void *next_data;
1585a9de470cSBruce Richardson 	void *data[NUM_ENTRIES];
1586a9de470cSBruce Richardson 	unsigned added_keys;
1587a9de470cSBruce Richardson 	uint32_t iter = 0;
1588a9de470cSBruce Richardson 	int ret = 0;
1589a9de470cSBruce Richardson 
1590a9de470cSBruce Richardson 	ut_params.entries = NUM_ENTRIES;
1591a9de470cSBruce Richardson 	ut_params.name = "test_hash_iteration";
1592a9de470cSBruce Richardson 	ut_params.hash_func = rte_jhash;
1593a9de470cSBruce Richardson 	ut_params.key_len = 16;
1594a9de470cSBruce Richardson 	if (ext_table)
1595a9de470cSBruce Richardson 		ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1596a9de470cSBruce Richardson 	else
1597a9de470cSBruce Richardson 		ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1598a9de470cSBruce Richardson 
1599a9de470cSBruce Richardson 	handle = rte_hash_create(&ut_params);
1600a9de470cSBruce Richardson 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1601a9de470cSBruce Richardson 
1602a9de470cSBruce Richardson 	/* Add random entries until key cannot be added */
1603a9de470cSBruce Richardson 	for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
1604a9de470cSBruce Richardson 		data[added_keys] = (void *) ((uintptr_t) rte_rand());
1605a9de470cSBruce Richardson 		for (i = 0; i < ut_params.key_len; i++)
1606a9de470cSBruce Richardson 			keys[added_keys][i] = rte_rand() % 255;
1607a9de470cSBruce Richardson 		ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]);
1608a9de470cSBruce Richardson 		if (ret < 0) {
1609a9de470cSBruce Richardson 			if (ext_table) {
1610a9de470cSBruce Richardson 				printf("Insertion failed for ext table\n");
1611a9de470cSBruce Richardson 				goto err;
1612a9de470cSBruce Richardson 			}
1613a9de470cSBruce Richardson 			break;
1614a9de470cSBruce Richardson 		}
1615a9de470cSBruce Richardson 	}
1616a9de470cSBruce Richardson 
1617a9de470cSBruce Richardson 	/* Iterate through the hash table */
1618a9de470cSBruce Richardson 	while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
1619a9de470cSBruce Richardson 		/* Search for the key in the list of keys added */
1620a9de470cSBruce Richardson 		for (i = 0; i < NUM_ENTRIES; i++) {
1621a9de470cSBruce Richardson 			if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
1622a9de470cSBruce Richardson 				if (next_data != data[i]) {
1623a9de470cSBruce Richardson 					printf("Data found in the hash table is"
1624a9de470cSBruce Richardson 					       "not the data added with the key\n");
1625a9de470cSBruce Richardson 					goto err;
1626a9de470cSBruce Richardson 				}
1627a9de470cSBruce Richardson 				added_keys--;
1628a9de470cSBruce Richardson 				break;
1629a9de470cSBruce Richardson 			}
1630a9de470cSBruce Richardson 		}
1631a9de470cSBruce Richardson 		if (i == NUM_ENTRIES) {
1632a9de470cSBruce Richardson 			printf("Key found in the hash table was not added\n");
1633a9de470cSBruce Richardson 			goto err;
1634a9de470cSBruce Richardson 		}
1635a9de470cSBruce Richardson 	}
1636a9de470cSBruce Richardson 
1637a9de470cSBruce Richardson 	/* Check if all keys have been iterated */
1638a9de470cSBruce Richardson 	if (added_keys != 0) {
1639a9de470cSBruce Richardson 		printf("There were still %u keys to iterate\n", added_keys);
1640a9de470cSBruce Richardson 		goto err;
1641a9de470cSBruce Richardson 	}
1642a9de470cSBruce Richardson 
1643a9de470cSBruce Richardson 	rte_hash_free(handle);
1644a9de470cSBruce Richardson 	return 0;
1645a9de470cSBruce Richardson 
1646a9de470cSBruce Richardson err:
1647a9de470cSBruce Richardson 	rte_hash_free(handle);
1648a9de470cSBruce Richardson 	return -1;
1649a9de470cSBruce Richardson }
1650a9de470cSBruce Richardson 
1651a9de470cSBruce Richardson static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
1652a9de470cSBruce Richardson 			0x04, 0x05, 0x06, 0x07,
1653a9de470cSBruce Richardson 			0x08, 0x09, 0x0a, 0x0b,
1654a9de470cSBruce Richardson 			0x0c, 0x0d, 0x0e, 0x0f};
1655a9de470cSBruce Richardson static struct rte_hash_parameters hash_params_ex = {
1656a9de470cSBruce Richardson 	.name = NULL,
1657a9de470cSBruce Richardson 	.entries = 64,
1658a9de470cSBruce Richardson 	.key_len = 0,
1659a9de470cSBruce Richardson 	.hash_func = NULL,
1660a9de470cSBruce Richardson 	.hash_func_init_val = 0,
1661a9de470cSBruce Richardson 	.socket_id = 0,
1662a9de470cSBruce Richardson };
1663a9de470cSBruce Richardson 
1664a9de470cSBruce Richardson /*
1665e30ef3a3SVladimir Medvedkin  * Wrapper function around rte_jhash_32b.
1666e30ef3a3SVladimir Medvedkin  * It is required because rte_jhash_32b() accepts the length
1667e30ef3a3SVladimir Medvedkin  * as size of 4-byte units.
1668e30ef3a3SVladimir Medvedkin  */
1669e30ef3a3SVladimir Medvedkin static inline uint32_t
1670e30ef3a3SVladimir Medvedkin test_jhash_32b(const void *k, uint32_t length, uint32_t initval)
1671e30ef3a3SVladimir Medvedkin {
1672e30ef3a3SVladimir Medvedkin 	return rte_jhash_32b(k, length >> 2, initval);
1673e30ef3a3SVladimir Medvedkin }
1674e30ef3a3SVladimir Medvedkin 
1675e30ef3a3SVladimir Medvedkin /*
1676a9de470cSBruce Richardson  * add/delete key with jhash2
1677a9de470cSBruce Richardson  */
1678a9de470cSBruce Richardson static int
1679a9de470cSBruce Richardson test_hash_add_delete_jhash2(void)
1680a9de470cSBruce Richardson {
1681a9de470cSBruce Richardson 	int ret = -1;
1682a9de470cSBruce Richardson 	struct rte_hash *handle;
1683a9de470cSBruce Richardson 	int32_t pos1, pos2;
1684a9de470cSBruce Richardson 
1685a9de470cSBruce Richardson 	hash_params_ex.name = "hash_test_jhash2";
1686a9de470cSBruce Richardson 	hash_params_ex.key_len = 4;
1687e30ef3a3SVladimir Medvedkin 	hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1688a9de470cSBruce Richardson 
1689a9de470cSBruce Richardson 	handle = rte_hash_create(&hash_params_ex);
1690a9de470cSBruce Richardson 	if (handle == NULL) {
1691a9de470cSBruce Richardson 		printf("test_hash_add_delete_jhash2 fail to create hash\n");
1692a9de470cSBruce Richardson 		goto fail_jhash2;
1693a9de470cSBruce Richardson 	}
1694a9de470cSBruce Richardson 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1695a9de470cSBruce Richardson 	if (pos1 < 0) {
1696a9de470cSBruce Richardson 		printf("test_hash_add_delete_jhash2 fail to add hash key\n");
1697a9de470cSBruce Richardson 		goto fail_jhash2;
1698a9de470cSBruce Richardson 	}
1699a9de470cSBruce Richardson 
1700a9de470cSBruce Richardson 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1701a9de470cSBruce Richardson 	if (pos2 < 0 || pos1 != pos2) {
1702a9de470cSBruce Richardson 		printf("test_hash_add_delete_jhash2 delete different key from being added\n");
1703a9de470cSBruce Richardson 		goto fail_jhash2;
1704a9de470cSBruce Richardson 	}
1705a9de470cSBruce Richardson 	ret = 0;
1706a9de470cSBruce Richardson 
1707a9de470cSBruce Richardson fail_jhash2:
1708a9de470cSBruce Richardson 	rte_hash_free(handle);
1709a9de470cSBruce Richardson 
1710a9de470cSBruce Richardson 	return ret;
1711a9de470cSBruce Richardson }
1712a9de470cSBruce Richardson 
1713a9de470cSBruce Richardson /*
1714a9de470cSBruce Richardson  * add/delete (2) key with jhash2
1715a9de470cSBruce Richardson  */
1716a9de470cSBruce Richardson static int
1717a9de470cSBruce Richardson test_hash_add_delete_2_jhash2(void)
1718a9de470cSBruce Richardson {
1719a9de470cSBruce Richardson 	int ret = -1;
1720a9de470cSBruce Richardson 	struct rte_hash *handle;
1721a9de470cSBruce Richardson 	int32_t pos1, pos2;
1722a9de470cSBruce Richardson 
1723a9de470cSBruce Richardson 	hash_params_ex.name = "hash_test_2_jhash2";
1724a9de470cSBruce Richardson 	hash_params_ex.key_len = 8;
1725e30ef3a3SVladimir Medvedkin 	hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1726a9de470cSBruce Richardson 
1727a9de470cSBruce Richardson 	handle = rte_hash_create(&hash_params_ex);
1728a9de470cSBruce Richardson 	if (handle == NULL)
1729a9de470cSBruce Richardson 		goto fail_2_jhash2;
1730a9de470cSBruce Richardson 
1731a9de470cSBruce Richardson 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1732a9de470cSBruce Richardson 	if (pos1 < 0)
1733a9de470cSBruce Richardson 		goto fail_2_jhash2;
1734a9de470cSBruce Richardson 
1735a9de470cSBruce Richardson 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1736a9de470cSBruce Richardson 	if (pos2 < 0 || pos1 != pos2)
1737a9de470cSBruce Richardson 		goto fail_2_jhash2;
1738a9de470cSBruce Richardson 
1739a9de470cSBruce Richardson 	ret = 0;
1740a9de470cSBruce Richardson 
1741a9de470cSBruce Richardson fail_2_jhash2:
1742a9de470cSBruce Richardson 	rte_hash_free(handle);
1743a9de470cSBruce Richardson 
1744a9de470cSBruce Richardson 	return ret;
1745a9de470cSBruce Richardson }
1746a9de470cSBruce Richardson 
1747a9de470cSBruce Richardson static uint32_t
1748a9de470cSBruce Richardson test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
1749a9de470cSBruce Richardson {
1750a9de470cSBruce Richardson 	const uint32_t *k = key;
1751a9de470cSBruce Richardson 
1752a9de470cSBruce Richardson 	RTE_SET_USED(length);
1753a9de470cSBruce Richardson 
1754a9de470cSBruce Richardson 	return rte_jhash_1word(k[0], initval);
1755a9de470cSBruce Richardson }
1756a9de470cSBruce Richardson 
1757a9de470cSBruce Richardson static uint32_t
1758a9de470cSBruce Richardson test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
1759a9de470cSBruce Richardson {
1760a9de470cSBruce Richardson 	const uint32_t *k = key;
1761a9de470cSBruce Richardson 
1762a9de470cSBruce Richardson 	RTE_SET_USED(length);
1763a9de470cSBruce Richardson 
1764a9de470cSBruce Richardson 	return rte_jhash_2words(k[0], k[1], initval);
1765a9de470cSBruce Richardson }
1766a9de470cSBruce Richardson 
1767a9de470cSBruce Richardson static uint32_t
1768a9de470cSBruce Richardson test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
1769a9de470cSBruce Richardson {
1770a9de470cSBruce Richardson 	const uint32_t *k = key;
1771a9de470cSBruce Richardson 
1772a9de470cSBruce Richardson 	RTE_SET_USED(length);
1773a9de470cSBruce Richardson 
1774a9de470cSBruce Richardson 	return rte_jhash_3words(k[0], k[1], k[2], initval);
1775a9de470cSBruce Richardson }
1776a9de470cSBruce Richardson 
1777a9de470cSBruce Richardson /*
1778a9de470cSBruce Richardson  * add/delete key with jhash 1word
1779a9de470cSBruce Richardson  */
1780a9de470cSBruce Richardson static int
1781a9de470cSBruce Richardson test_hash_add_delete_jhash_1word(void)
1782a9de470cSBruce Richardson {
1783a9de470cSBruce Richardson 	int ret = -1;
1784a9de470cSBruce Richardson 	struct rte_hash *handle;
1785a9de470cSBruce Richardson 	int32_t pos1, pos2;
1786a9de470cSBruce Richardson 
1787a9de470cSBruce Richardson 	hash_params_ex.name = "hash_test_jhash_1word";
1788a9de470cSBruce Richardson 	hash_params_ex.key_len = 4;
1789a9de470cSBruce Richardson 	hash_params_ex.hash_func = test_hash_jhash_1word;
1790a9de470cSBruce Richardson 
1791a9de470cSBruce Richardson 	handle = rte_hash_create(&hash_params_ex);
1792a9de470cSBruce Richardson 	if (handle == NULL)
1793a9de470cSBruce Richardson 		goto fail_jhash_1word;
1794a9de470cSBruce Richardson 
1795a9de470cSBruce Richardson 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1796a9de470cSBruce Richardson 	if (pos1 < 0)
1797a9de470cSBruce Richardson 		goto fail_jhash_1word;
1798a9de470cSBruce Richardson 
1799a9de470cSBruce Richardson 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1800a9de470cSBruce Richardson 	if (pos2 < 0 || pos1 != pos2)
1801a9de470cSBruce Richardson 		goto fail_jhash_1word;
1802a9de470cSBruce Richardson 
1803a9de470cSBruce Richardson 	ret = 0;
1804a9de470cSBruce Richardson 
1805a9de470cSBruce Richardson fail_jhash_1word:
1806a9de470cSBruce Richardson 	rte_hash_free(handle);
1807a9de470cSBruce Richardson 
1808a9de470cSBruce Richardson 	return ret;
1809a9de470cSBruce Richardson }
1810a9de470cSBruce Richardson 
1811a9de470cSBruce Richardson /*
1812a9de470cSBruce Richardson  * add/delete key with jhash 2word
1813a9de470cSBruce Richardson  */
1814a9de470cSBruce Richardson static int
1815a9de470cSBruce Richardson test_hash_add_delete_jhash_2word(void)
1816a9de470cSBruce Richardson {
1817a9de470cSBruce Richardson 	int ret = -1;
1818a9de470cSBruce Richardson 	struct rte_hash *handle;
1819a9de470cSBruce Richardson 	int32_t pos1, pos2;
1820a9de470cSBruce Richardson 
1821a9de470cSBruce Richardson 	hash_params_ex.name = "hash_test_jhash_2word";
1822a9de470cSBruce Richardson 	hash_params_ex.key_len = 8;
1823a9de470cSBruce Richardson 	hash_params_ex.hash_func = test_hash_jhash_2word;
1824a9de470cSBruce Richardson 
1825a9de470cSBruce Richardson 	handle = rte_hash_create(&hash_params_ex);
1826a9de470cSBruce Richardson 	if (handle == NULL)
1827a9de470cSBruce Richardson 		goto fail_jhash_2word;
1828a9de470cSBruce Richardson 
1829a9de470cSBruce Richardson 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1830a9de470cSBruce Richardson 	if (pos1 < 0)
1831a9de470cSBruce Richardson 		goto fail_jhash_2word;
1832a9de470cSBruce Richardson 
1833a9de470cSBruce Richardson 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1834a9de470cSBruce Richardson 	if (pos2 < 0 || pos1 != pos2)
1835a9de470cSBruce Richardson 		goto fail_jhash_2word;
1836a9de470cSBruce Richardson 
1837a9de470cSBruce Richardson 	ret = 0;
1838a9de470cSBruce Richardson 
1839a9de470cSBruce Richardson fail_jhash_2word:
1840a9de470cSBruce Richardson 	rte_hash_free(handle);
1841a9de470cSBruce Richardson 
1842a9de470cSBruce Richardson 	return ret;
1843a9de470cSBruce Richardson }
1844a9de470cSBruce Richardson 
1845a9de470cSBruce Richardson /*
1846a9de470cSBruce Richardson  * add/delete key with jhash 3word
1847a9de470cSBruce Richardson  */
1848a9de470cSBruce Richardson static int
1849a9de470cSBruce Richardson test_hash_add_delete_jhash_3word(void)
1850a9de470cSBruce Richardson {
1851a9de470cSBruce Richardson 	int ret = -1;
1852a9de470cSBruce Richardson 	struct rte_hash *handle;
1853a9de470cSBruce Richardson 	int32_t pos1, pos2;
1854a9de470cSBruce Richardson 
1855a9de470cSBruce Richardson 	hash_params_ex.name = "hash_test_jhash_3word";
1856a9de470cSBruce Richardson 	hash_params_ex.key_len = 12;
1857a9de470cSBruce Richardson 	hash_params_ex.hash_func = test_hash_jhash_3word;
1858a9de470cSBruce Richardson 
1859a9de470cSBruce Richardson 	handle = rte_hash_create(&hash_params_ex);
1860a9de470cSBruce Richardson 	if (handle == NULL)
1861a9de470cSBruce Richardson 		goto fail_jhash_3word;
1862a9de470cSBruce Richardson 
1863a9de470cSBruce Richardson 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1864a9de470cSBruce Richardson 	if (pos1 < 0)
1865a9de470cSBruce Richardson 		goto fail_jhash_3word;
1866a9de470cSBruce Richardson 
1867a9de470cSBruce Richardson 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1868a9de470cSBruce Richardson 	if (pos2 < 0 || pos1 != pos2)
1869a9de470cSBruce Richardson 		goto fail_jhash_3word;
1870a9de470cSBruce Richardson 
1871a9de470cSBruce Richardson 	ret = 0;
1872a9de470cSBruce Richardson 
1873a9de470cSBruce Richardson fail_jhash_3word:
1874a9de470cSBruce Richardson 	rte_hash_free(handle);
1875a9de470cSBruce Richardson 
1876a9de470cSBruce Richardson 	return ret;
1877a9de470cSBruce Richardson }
1878a9de470cSBruce Richardson 
18799c7d8eedSDharmik Thakkar static struct rte_hash *g_handle;
18809c7d8eedSDharmik Thakkar static struct rte_rcu_qsbr *g_qsv;
18819c7d8eedSDharmik Thakkar static volatile uint8_t writer_done;
18829c7d8eedSDharmik Thakkar struct flow_key g_rand_keys[9];
18839c7d8eedSDharmik Thakkar 
18849c7d8eedSDharmik Thakkar /*
18859c7d8eedSDharmik Thakkar  * rte_hash_rcu_qsbr_add positive and negative tests.
18869c7d8eedSDharmik Thakkar  *  - Add RCU QSBR variable to Hash
18879c7d8eedSDharmik Thakkar  *  - Add another RCU QSBR variable to Hash
18889c7d8eedSDharmik Thakkar  *  - Check returns
18899c7d8eedSDharmik Thakkar  */
18909c7d8eedSDharmik Thakkar static int
18919c7d8eedSDharmik Thakkar test_hash_rcu_qsbr_add(void)
18929c7d8eedSDharmik Thakkar {
18939c7d8eedSDharmik Thakkar 	size_t sz;
18949c7d8eedSDharmik Thakkar 	struct rte_rcu_qsbr *qsv2 = NULL;
18959c7d8eedSDharmik Thakkar 	int32_t status;
18969c7d8eedSDharmik Thakkar 	struct rte_hash_rcu_config rcu_cfg = {0};
18979c7d8eedSDharmik Thakkar 	struct rte_hash_parameters params;
18989c7d8eedSDharmik Thakkar 
18999c7d8eedSDharmik Thakkar 	printf("\n# Running RCU QSBR add tests\n");
19009c7d8eedSDharmik Thakkar 	memcpy(&params, &ut_params, sizeof(params));
19019c7d8eedSDharmik Thakkar 	params.name = "test_hash_rcu_qsbr_add";
19029c7d8eedSDharmik Thakkar 	params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
19039c7d8eedSDharmik Thakkar 				RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
19049c7d8eedSDharmik Thakkar 	g_handle = rte_hash_create(&params);
19059c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
19069c7d8eedSDharmik Thakkar 
19079c7d8eedSDharmik Thakkar 	/* Create RCU QSBR variable */
19089c7d8eedSDharmik Thakkar 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
19099c7d8eedSDharmik Thakkar 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
19109c7d8eedSDharmik Thakkar 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
19119c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
19129c7d8eedSDharmik Thakkar 				 "RCU QSBR variable creation failed");
19139c7d8eedSDharmik Thakkar 
19149c7d8eedSDharmik Thakkar 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
19159c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
19169c7d8eedSDharmik Thakkar 				 "RCU QSBR variable initialization failed");
19179c7d8eedSDharmik Thakkar 
19189c7d8eedSDharmik Thakkar 	rcu_cfg.v = g_qsv;
19199c7d8eedSDharmik Thakkar 	/* Invalid QSBR mode */
19209c7d8eedSDharmik Thakkar 	rcu_cfg.mode = 0xff;
19219c7d8eedSDharmik Thakkar 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
19229c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status == 0, "Invalid QSBR mode test failed");
19239c7d8eedSDharmik Thakkar 
19249c7d8eedSDharmik Thakkar 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
19259c7d8eedSDharmik Thakkar 	/* Attach RCU QSBR to hash table */
19269c7d8eedSDharmik Thakkar 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
19279c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
19289c7d8eedSDharmik Thakkar 				 "Attach RCU QSBR to hash table failed");
19299c7d8eedSDharmik Thakkar 
19309c7d8eedSDharmik Thakkar 	/* Create and attach another RCU QSBR to hash table */
19319c7d8eedSDharmik Thakkar 	qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
19329c7d8eedSDharmik Thakkar 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
19339c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(qsv2 == NULL,
19349c7d8eedSDharmik Thakkar 				 "RCU QSBR variable creation failed");
19359c7d8eedSDharmik Thakkar 
19369c7d8eedSDharmik Thakkar 	rcu_cfg.v = qsv2;
19379c7d8eedSDharmik Thakkar 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
19389c7d8eedSDharmik Thakkar 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
19399c7d8eedSDharmik Thakkar 	rte_free(qsv2);
19409c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status == 0,
19419c7d8eedSDharmik Thakkar 			"Attach RCU QSBR to hash table succeeded where failure"
19429c7d8eedSDharmik Thakkar 			" is expected");
19439c7d8eedSDharmik Thakkar 
19449c7d8eedSDharmik Thakkar 	rte_hash_free(g_handle);
19459c7d8eedSDharmik Thakkar 	rte_free(g_qsv);
19469c7d8eedSDharmik Thakkar 
19479c7d8eedSDharmik Thakkar 	return 0;
19489c7d8eedSDharmik Thakkar }
19499c7d8eedSDharmik Thakkar 
19509c7d8eedSDharmik Thakkar /*
19519c7d8eedSDharmik Thakkar  * rte_hash_rcu_qsbr_add DQ mode functional test.
19529c7d8eedSDharmik Thakkar  * Reader and writer are in the same thread in this test.
19539c7d8eedSDharmik Thakkar  *  - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
19549c7d8eedSDharmik Thakkar  *  - Add RCU QSBR variable to hash
19559c7d8eedSDharmik Thakkar  *  - Add 8 hash entries and fill the bucket
19569c7d8eedSDharmik Thakkar  *  - If ext bkt is enabled, add 1 extra entry that is available in the ext bkt
19579c7d8eedSDharmik Thakkar  *  - Register a reader thread (not a real thread)
19589c7d8eedSDharmik Thakkar  *  - Reader lookup existing entry
19599c7d8eedSDharmik Thakkar  *  - Writer deletes the entry
19609c7d8eedSDharmik Thakkar  *  - Reader lookup the entry
19619c7d8eedSDharmik Thakkar  *  - Writer re-add the entry (no available free index)
19629c7d8eedSDharmik Thakkar  *  - Reader report quiescent state and unregister
19639c7d8eedSDharmik Thakkar  *  - Writer re-add the entry
19649c7d8eedSDharmik Thakkar  *  - Reader lookup the entry
19659c7d8eedSDharmik Thakkar  */
19669c7d8eedSDharmik Thakkar static int
19679c7d8eedSDharmik Thakkar test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt)
19689c7d8eedSDharmik Thakkar {
19699c7d8eedSDharmik Thakkar 	uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
19709c7d8eedSDharmik Thakkar 
19719c7d8eedSDharmik Thakkar 	uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
19729c7d8eedSDharmik Thakkar 
19739c7d8eedSDharmik Thakkar 	if (ext_bkt)
19749c7d8eedSDharmik Thakkar 		hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
19759c7d8eedSDharmik Thakkar 
19769c7d8eedSDharmik Thakkar 	struct rte_hash_parameters params_pseudo_hash = {
19779c7d8eedSDharmik Thakkar 		.name = "test_hash_rcu_qsbr_dq_mode",
19789c7d8eedSDharmik Thakkar 		.entries = total_entries,
1979e30ef3a3SVladimir Medvedkin 		.key_len = sizeof(struct flow_key),
19809c7d8eedSDharmik Thakkar 		.hash_func = pseudo_hash,
19819c7d8eedSDharmik Thakkar 		.hash_func_init_val = 0,
19829c7d8eedSDharmik Thakkar 		.socket_id = 0,
19839c7d8eedSDharmik Thakkar 		.extra_flag = hash_extra_flag,
19849c7d8eedSDharmik Thakkar 	};
19859c7d8eedSDharmik Thakkar 	int pos[total_entries];
19869c7d8eedSDharmik Thakkar 	int expected_pos[total_entries];
19879c7d8eedSDharmik Thakkar 	unsigned int i;
19889c7d8eedSDharmik Thakkar 	size_t sz;
19899c7d8eedSDharmik Thakkar 	int32_t status;
19909c7d8eedSDharmik Thakkar 	struct rte_hash_rcu_config rcu_cfg = {0};
19919c7d8eedSDharmik Thakkar 
19929c7d8eedSDharmik Thakkar 	g_qsv = NULL;
19939c7d8eedSDharmik Thakkar 	g_handle = NULL;
19949c7d8eedSDharmik Thakkar 
19959c7d8eedSDharmik Thakkar 	for (i = 0; i < total_entries; i++) {
19969c7d8eedSDharmik Thakkar 		g_rand_keys[i].port_dst = i;
19979c7d8eedSDharmik Thakkar 		g_rand_keys[i].port_src = i+1;
19989c7d8eedSDharmik Thakkar 	}
19999c7d8eedSDharmik Thakkar 
20009c7d8eedSDharmik Thakkar 	if (ext_bkt)
20019c7d8eedSDharmik Thakkar 		printf("\n# Running RCU QSBR DQ mode functional test with"
20029c7d8eedSDharmik Thakkar 		       " ext bkt\n");
20039c7d8eedSDharmik Thakkar 	else
20049c7d8eedSDharmik Thakkar 		printf("\n# Running RCU QSBR DQ mode functional test\n");
20059c7d8eedSDharmik Thakkar 
20069c7d8eedSDharmik Thakkar 	g_handle = rte_hash_create(&params_pseudo_hash);
20079c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
20089c7d8eedSDharmik Thakkar 
20099c7d8eedSDharmik Thakkar 	/* Create RCU QSBR variable */
20109c7d8eedSDharmik Thakkar 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
20119c7d8eedSDharmik Thakkar 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
20129c7d8eedSDharmik Thakkar 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
20139c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
20149c7d8eedSDharmik Thakkar 				 "RCU QSBR variable creation failed");
20159c7d8eedSDharmik Thakkar 
20169c7d8eedSDharmik Thakkar 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
20179c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
20189c7d8eedSDharmik Thakkar 				 "RCU QSBR variable initialization failed");
20199c7d8eedSDharmik Thakkar 
20209c7d8eedSDharmik Thakkar 	rcu_cfg.v = g_qsv;
20219c7d8eedSDharmik Thakkar 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
20229c7d8eedSDharmik Thakkar 	/* Attach RCU QSBR to hash table */
20239c7d8eedSDharmik Thakkar 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
20249c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
20259c7d8eedSDharmik Thakkar 				 "Attach RCU QSBR to hash table failed");
20269c7d8eedSDharmik Thakkar 
20279c7d8eedSDharmik Thakkar 	/* Fill bucket */
20289c7d8eedSDharmik Thakkar 	for (i = 0; i < total_entries; i++) {
20299c7d8eedSDharmik Thakkar 		pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
20309c7d8eedSDharmik Thakkar 		print_key_info("Add", &g_rand_keys[i], pos[i]);
20319c7d8eedSDharmik Thakkar 		RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
20329c7d8eedSDharmik Thakkar 					 "failed to add key (pos[%u]=%d)", i,
20339c7d8eedSDharmik Thakkar 					 pos[i]);
20349c7d8eedSDharmik Thakkar 		expected_pos[i] = pos[i];
20359c7d8eedSDharmik Thakkar 	}
20369c7d8eedSDharmik Thakkar 
20379c7d8eedSDharmik Thakkar 	/* Register pseudo reader */
20389c7d8eedSDharmik Thakkar 	status = rte_rcu_qsbr_thread_register(g_qsv, 0);
20399c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
20409c7d8eedSDharmik Thakkar 				 "RCU QSBR thread registration failed");
20419c7d8eedSDharmik Thakkar 	rte_rcu_qsbr_thread_online(g_qsv, 0);
20429c7d8eedSDharmik Thakkar 
20439c7d8eedSDharmik Thakkar 	/* Lookup */
20449c7d8eedSDharmik Thakkar 	pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
20459c7d8eedSDharmik Thakkar 	print_key_info("Lkp", &g_rand_keys[0], pos[0]);
20469c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
20479c7d8eedSDharmik Thakkar 				 "failed to find correct key (pos[%u]=%d)", 0,
20489c7d8eedSDharmik Thakkar 				 pos[0]);
20499c7d8eedSDharmik Thakkar 
20509c7d8eedSDharmik Thakkar 	/* Writer update */
20519c7d8eedSDharmik Thakkar 	pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
20529c7d8eedSDharmik Thakkar 	print_key_info("Del", &g_rand_keys[0], pos[0]);
20539c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
20549c7d8eedSDharmik Thakkar 				 "failed to del correct key (pos[%u]=%d)", 0,
20559c7d8eedSDharmik Thakkar 				 pos[0]);
20569c7d8eedSDharmik Thakkar 
20579c7d8eedSDharmik Thakkar 	/* Lookup */
20589c7d8eedSDharmik Thakkar 	pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
20599c7d8eedSDharmik Thakkar 	print_key_info("Lkp", &g_rand_keys[0], pos[0]);
20609c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOENT,
20619c7d8eedSDharmik Thakkar 				 "found deleted key (pos[%u]=%d)", 0, pos[0]);
20629c7d8eedSDharmik Thakkar 
20639c7d8eedSDharmik Thakkar 	/* Fill bucket */
20649c7d8eedSDharmik Thakkar 	pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
20659c7d8eedSDharmik Thakkar 	print_key_info("Add", &g_rand_keys[0], pos[0]);
20669c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOSPC,
20679c7d8eedSDharmik Thakkar 				 "Added key successfully (pos[%u]=%d)", 0, pos[0]);
20689c7d8eedSDharmik Thakkar 
20699c7d8eedSDharmik Thakkar 	/* Reader quiescent */
20709c7d8eedSDharmik Thakkar 	rte_rcu_qsbr_quiescent(g_qsv, 0);
20719c7d8eedSDharmik Thakkar 
20729c7d8eedSDharmik Thakkar 	/* Fill bucket */
20739c7d8eedSDharmik Thakkar 	pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
20749c7d8eedSDharmik Thakkar 	print_key_info("Add", &g_rand_keys[0], pos[0]);
20759c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
20769c7d8eedSDharmik Thakkar 				 "failed to add key (pos[%u]=%d)", 0, pos[0]);
20779c7d8eedSDharmik Thakkar 	expected_pos[0] = pos[0];
20789c7d8eedSDharmik Thakkar 
20799c7d8eedSDharmik Thakkar 	rte_rcu_qsbr_thread_offline(g_qsv, 0);
20809c7d8eedSDharmik Thakkar 	(void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
20819c7d8eedSDharmik Thakkar 
20829c7d8eedSDharmik Thakkar 	/* Lookup */
20839c7d8eedSDharmik Thakkar 	pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
20849c7d8eedSDharmik Thakkar 	print_key_info("Lkp", &g_rand_keys[0], pos[0]);
20859c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
20869c7d8eedSDharmik Thakkar 				 "failed to find correct key (pos[%u]=%d)", 0,
20879c7d8eedSDharmik Thakkar 				 pos[0]);
20889c7d8eedSDharmik Thakkar 
20899c7d8eedSDharmik Thakkar 	rte_hash_free(g_handle);
20909c7d8eedSDharmik Thakkar 	rte_free(g_qsv);
20919c7d8eedSDharmik Thakkar 	return 0;
20929c7d8eedSDharmik Thakkar 
20939c7d8eedSDharmik Thakkar }
20949c7d8eedSDharmik Thakkar 
20959c7d8eedSDharmik Thakkar /* Report quiescent state interval every 1024 lookups. Larger critical
20969c7d8eedSDharmik Thakkar  * sections in reader will result in writer polling multiple times.
20979c7d8eedSDharmik Thakkar  */
20989c7d8eedSDharmik Thakkar #define QSBR_REPORTING_INTERVAL 1024
20999c7d8eedSDharmik Thakkar #define WRITER_ITERATIONS	512
21009c7d8eedSDharmik Thakkar 
21019c7d8eedSDharmik Thakkar /*
21029c7d8eedSDharmik Thakkar  * Reader thread using rte_hash data structure with RCU.
21039c7d8eedSDharmik Thakkar  */
21049c7d8eedSDharmik Thakkar static int
21059c7d8eedSDharmik Thakkar test_hash_rcu_qsbr_reader(void *arg)
21069c7d8eedSDharmik Thakkar {
21079c7d8eedSDharmik Thakkar 	int i;
21089c7d8eedSDharmik Thakkar 
21099c7d8eedSDharmik Thakkar 	RTE_SET_USED(arg);
21109c7d8eedSDharmik Thakkar 	/* Register this thread to report quiescent state */
21119c7d8eedSDharmik Thakkar 	(void)rte_rcu_qsbr_thread_register(g_qsv, 0);
21129c7d8eedSDharmik Thakkar 	rte_rcu_qsbr_thread_online(g_qsv, 0);
21139c7d8eedSDharmik Thakkar 
21149c7d8eedSDharmik Thakkar 	do {
21159c7d8eedSDharmik Thakkar 		for (i = 0; i < QSBR_REPORTING_INTERVAL; i++)
21169c7d8eedSDharmik Thakkar 			rte_hash_lookup(g_handle, &g_rand_keys[0]);
21179c7d8eedSDharmik Thakkar 
21189c7d8eedSDharmik Thakkar 		/* Update quiescent state */
21199c7d8eedSDharmik Thakkar 		rte_rcu_qsbr_quiescent(g_qsv, 0);
21209c7d8eedSDharmik Thakkar 	} while (!writer_done);
21219c7d8eedSDharmik Thakkar 
21229c7d8eedSDharmik Thakkar 	rte_rcu_qsbr_thread_offline(g_qsv, 0);
21239c7d8eedSDharmik Thakkar 	(void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
21249c7d8eedSDharmik Thakkar 
21259c7d8eedSDharmik Thakkar 	return 0;
21269c7d8eedSDharmik Thakkar }
21279c7d8eedSDharmik Thakkar 
21289c7d8eedSDharmik Thakkar /*
21299c7d8eedSDharmik Thakkar  * rte_hash_rcu_qsbr_add sync mode functional test.
21309c7d8eedSDharmik Thakkar  * 1 Reader and 1 writer. They cannot be in the same thread in this test.
21319c7d8eedSDharmik Thakkar  *  - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
21329c7d8eedSDharmik Thakkar  *  - Add RCU QSBR variable to hash
21339c7d8eedSDharmik Thakkar  *  - Register a reader thread. Reader keeps looking up a specific key.
21349c7d8eedSDharmik Thakkar  *  - Writer keeps adding and deleting a specific key.
21359c7d8eedSDharmik Thakkar  */
21369c7d8eedSDharmik Thakkar static int
21379c7d8eedSDharmik Thakkar test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt)
21389c7d8eedSDharmik Thakkar {
21399c7d8eedSDharmik Thakkar 	uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
21409c7d8eedSDharmik Thakkar 
21419c7d8eedSDharmik Thakkar 	uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
21429c7d8eedSDharmik Thakkar 
21439c7d8eedSDharmik Thakkar 	if (ext_bkt)
21449c7d8eedSDharmik Thakkar 		hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
21459c7d8eedSDharmik Thakkar 
21469c7d8eedSDharmik Thakkar 	struct rte_hash_parameters params_pseudo_hash = {
21479c7d8eedSDharmik Thakkar 		.name = "test_hash_rcu_qsbr_sync_mode",
21489c7d8eedSDharmik Thakkar 		.entries = total_entries,
2149e30ef3a3SVladimir Medvedkin 		.key_len = sizeof(struct flow_key),
21509c7d8eedSDharmik Thakkar 		.hash_func = pseudo_hash,
21519c7d8eedSDharmik Thakkar 		.hash_func_init_val = 0,
21529c7d8eedSDharmik Thakkar 		.socket_id = 0,
21539c7d8eedSDharmik Thakkar 		.extra_flag = hash_extra_flag,
21549c7d8eedSDharmik Thakkar 	};
21559c7d8eedSDharmik Thakkar 	int pos[total_entries];
21569c7d8eedSDharmik Thakkar 	int expected_pos[total_entries];
21579c7d8eedSDharmik Thakkar 	unsigned int i;
21589c7d8eedSDharmik Thakkar 	size_t sz;
21599c7d8eedSDharmik Thakkar 	int32_t status;
21609c7d8eedSDharmik Thakkar 	struct rte_hash_rcu_config rcu_cfg = {0};
21619c7d8eedSDharmik Thakkar 
21629c7d8eedSDharmik Thakkar 	g_qsv = NULL;
21639c7d8eedSDharmik Thakkar 	g_handle = NULL;
21649c7d8eedSDharmik Thakkar 
21659c7d8eedSDharmik Thakkar 	for (i = 0; i < total_entries; i++) {
21669c7d8eedSDharmik Thakkar 		g_rand_keys[i].port_dst = i;
21679c7d8eedSDharmik Thakkar 		g_rand_keys[i].port_src = i+1;
21689c7d8eedSDharmik Thakkar 	}
21699c7d8eedSDharmik Thakkar 
21709c7d8eedSDharmik Thakkar 	if (ext_bkt)
21719c7d8eedSDharmik Thakkar 		printf("\n# Running RCU QSBR sync mode functional test with"
21729c7d8eedSDharmik Thakkar 		       " ext bkt\n");
21739c7d8eedSDharmik Thakkar 	else
21749c7d8eedSDharmik Thakkar 		printf("\n# Running RCU QSBR sync mode functional test\n");
21759c7d8eedSDharmik Thakkar 
21769c7d8eedSDharmik Thakkar 	g_handle = rte_hash_create(&params_pseudo_hash);
21779c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
21789c7d8eedSDharmik Thakkar 
21799c7d8eedSDharmik Thakkar 	/* Create RCU QSBR variable */
21809c7d8eedSDharmik Thakkar 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
21819c7d8eedSDharmik Thakkar 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
21829c7d8eedSDharmik Thakkar 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
21839c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
21849c7d8eedSDharmik Thakkar 				 "RCU QSBR variable creation failed");
21859c7d8eedSDharmik Thakkar 
21869c7d8eedSDharmik Thakkar 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
21879c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
21889c7d8eedSDharmik Thakkar 				 "RCU QSBR variable initialization failed");
21899c7d8eedSDharmik Thakkar 
21909c7d8eedSDharmik Thakkar 	rcu_cfg.v = g_qsv;
21919c7d8eedSDharmik Thakkar 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
21929c7d8eedSDharmik Thakkar 	/* Attach RCU QSBR to hash table */
21939c7d8eedSDharmik Thakkar 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
21949c7d8eedSDharmik Thakkar 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
21959c7d8eedSDharmik Thakkar 				 "Attach RCU QSBR to hash table failed");
21969c7d8eedSDharmik Thakkar 
21979c7d8eedSDharmik Thakkar 	/* Launch reader thread */
21989c7d8eedSDharmik Thakkar 	rte_eal_remote_launch(test_hash_rcu_qsbr_reader, NULL,
21999c7d8eedSDharmik Thakkar 				rte_get_next_lcore(-1, 1, 0));
22009c7d8eedSDharmik Thakkar 
22019c7d8eedSDharmik Thakkar 	/* Fill bucket */
22029c7d8eedSDharmik Thakkar 	for (i = 0; i < total_entries; i++) {
22039c7d8eedSDharmik Thakkar 		pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
22049c7d8eedSDharmik Thakkar 		print_key_info("Add", &g_rand_keys[i], pos[i]);
22059c7d8eedSDharmik Thakkar 		RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
22069c7d8eedSDharmik Thakkar 				"failed to add key (pos[%u]=%d)", i, pos[i]);
22079c7d8eedSDharmik Thakkar 		expected_pos[i] = pos[i];
22089c7d8eedSDharmik Thakkar 	}
22099c7d8eedSDharmik Thakkar 	writer_done = 0;
22109c7d8eedSDharmik Thakkar 
22119c7d8eedSDharmik Thakkar 	/* Writer Update */
22129c7d8eedSDharmik Thakkar 	for (i = 0; i < WRITER_ITERATIONS; i++) {
22139c7d8eedSDharmik Thakkar 		expected_pos[0] = pos[0];
22149c7d8eedSDharmik Thakkar 		pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
22159c7d8eedSDharmik Thakkar 		print_key_info("Del", &g_rand_keys[0], status);
22169c7d8eedSDharmik Thakkar 		RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
22179c7d8eedSDharmik Thakkar 					 "failed to del correct key (pos[%u]=%d)"
22189c7d8eedSDharmik Thakkar 					 , 0, pos[0]);
22199c7d8eedSDharmik Thakkar 
22209c7d8eedSDharmik Thakkar 		pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
22219c7d8eedSDharmik Thakkar 		print_key_info("Add", &g_rand_keys[0], pos[0]);
22229c7d8eedSDharmik Thakkar 		RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
22239c7d8eedSDharmik Thakkar 					 "failed to add key (pos[%u]=%d)", 0,
22249c7d8eedSDharmik Thakkar 					 pos[0]);
22259c7d8eedSDharmik Thakkar 	}
22269c7d8eedSDharmik Thakkar 
22279c7d8eedSDharmik Thakkar 	writer_done = 1;
22289c7d8eedSDharmik Thakkar 	/* Wait until reader exited. */
22299c7d8eedSDharmik Thakkar 	rte_eal_mp_wait_lcore();
22309c7d8eedSDharmik Thakkar 
22319c7d8eedSDharmik Thakkar 	rte_hash_free(g_handle);
22329c7d8eedSDharmik Thakkar 	rte_free(g_qsv);
22339c7d8eedSDharmik Thakkar 
22349c7d8eedSDharmik Thakkar 	return  0;
22359c7d8eedSDharmik Thakkar 
22369c7d8eedSDharmik Thakkar }
22379c7d8eedSDharmik Thakkar 
2238a9de470cSBruce Richardson /*
2239567bb951SAbdullah Ömer Yamaç  * rte_hash_rcu_qsbr_dq_reclaim unit test.
2240567bb951SAbdullah Ömer Yamaç  */
2241567bb951SAbdullah Ömer Yamaç static int
2242567bb951SAbdullah Ömer Yamaç test_hash_rcu_qsbr_dq_reclaim(void)
2243567bb951SAbdullah Ömer Yamaç {
2244567bb951SAbdullah Ömer Yamaç 	size_t sz;
2245567bb951SAbdullah Ömer Yamaç 	int32_t status;
2246567bb951SAbdullah Ömer Yamaç 	unsigned int total_entries = 8;
2247567bb951SAbdullah Ömer Yamaç 	unsigned int freed, pending, available;
2248567bb951SAbdullah Ömer Yamaç 	uint32_t reclaim_keys[8] = {10, 11, 12, 13, 14, 15, 16, 17};
2249567bb951SAbdullah Ömer Yamaç 	struct rte_hash_rcu_config rcu_cfg = {0};
2250567bb951SAbdullah Ömer Yamaç 	struct rte_hash_parameters hash_params = {
2251567bb951SAbdullah Ömer Yamaç 			.name = "test_hash_rcu_qsbr_dq_reclaim",
2252567bb951SAbdullah Ömer Yamaç 			.entries = total_entries,
2253567bb951SAbdullah Ömer Yamaç 			.key_len = sizeof(uint32_t),
2254567bb951SAbdullah Ömer Yamaç 			.hash_func = NULL,
2255567bb951SAbdullah Ömer Yamaç 			.hash_func_init_val = 0,
2256567bb951SAbdullah Ömer Yamaç 			.socket_id = 0,
2257567bb951SAbdullah Ömer Yamaç 	};
2258567bb951SAbdullah Ömer Yamaç 
2259567bb951SAbdullah Ömer Yamaç 	hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2260567bb951SAbdullah Ömer Yamaç 
2261567bb951SAbdullah Ömer Yamaç 	g_qsv = NULL;
2262567bb951SAbdullah Ömer Yamaç 	g_handle = NULL;
2263567bb951SAbdullah Ömer Yamaç 
2264567bb951SAbdullah Ömer Yamaç 	printf("\n# Running RCU QSBR DQ mode, reclaim defer queue functional test\n");
2265567bb951SAbdullah Ömer Yamaç 
2266567bb951SAbdullah Ömer Yamaç 	g_handle = rte_hash_create(&hash_params);
2267567bb951SAbdullah Ömer Yamaç 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2268567bb951SAbdullah Ömer Yamaç 
2269567bb951SAbdullah Ömer Yamaç 	/* Create RCU QSBR variable */
2270567bb951SAbdullah Ömer Yamaç 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2271567bb951SAbdullah Ömer Yamaç 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(
2272567bb951SAbdullah Ömer Yamaç 			NULL, sz, RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2273567bb951SAbdullah Ömer Yamaç 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, "RCU QSBR variable creation failed");
2274567bb951SAbdullah Ömer Yamaç 
2275567bb951SAbdullah Ömer Yamaç 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2276567bb951SAbdullah Ömer Yamaç 	RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR variable initialization failed");
2277567bb951SAbdullah Ömer Yamaç 
2278567bb951SAbdullah Ömer Yamaç 	rcu_cfg.v = g_qsv;
2279567bb951SAbdullah Ömer Yamaç 	rcu_cfg.dq_size = total_entries;
2280567bb951SAbdullah Ömer Yamaç 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2281567bb951SAbdullah Ömer Yamaç 
2282567bb951SAbdullah Ömer Yamaç 	/* Attach RCU QSBR to hash table */
2283567bb951SAbdullah Ömer Yamaç 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2284567bb951SAbdullah Ömer Yamaç 	RETURN_IF_ERROR_RCU_QSBR(status != 0, "Attach RCU QSBR to hash table failed");
2285567bb951SAbdullah Ömer Yamaç 
2286567bb951SAbdullah Ömer Yamaç 	/* Register pseudo reader */
2287567bb951SAbdullah Ömer Yamaç 	status = rte_rcu_qsbr_thread_register(g_qsv, 0);
2288567bb951SAbdullah Ömer Yamaç 	RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR thread registration failed");
2289567bb951SAbdullah Ömer Yamaç 	rte_rcu_qsbr_thread_online(g_qsv, 0);
2290567bb951SAbdullah Ömer Yamaç 
2291567bb951SAbdullah Ömer Yamaç 	/* Fill half of the hash table */
2292567bb951SAbdullah Ömer Yamaç 	for (size_t i = 0; i < total_entries / 2; i++)
2293567bb951SAbdullah Ömer Yamaç 		status = rte_hash_add_key(g_handle, &reclaim_keys[i]);
2294567bb951SAbdullah Ömer Yamaç 
2295567bb951SAbdullah Ömer Yamaç 	/* Try to put these elements into the defer queue*/
2296567bb951SAbdullah Ömer Yamaç 	for (size_t i = 0; i < total_entries / 2; i++)
2297567bb951SAbdullah Ömer Yamaç 		rte_hash_del_key(g_handle, &reclaim_keys[i]);
2298567bb951SAbdullah Ömer Yamaç 
2299567bb951SAbdullah Ömer Yamaç 	/* Reader quiescent */
2300567bb951SAbdullah Ömer Yamaç 	rte_rcu_qsbr_quiescent(g_qsv, 0);
2301567bb951SAbdullah Ömer Yamaç 
2302567bb951SAbdullah Ömer Yamaç 	status = rte_hash_add_key(g_handle, &reclaim_keys[0]);
2303567bb951SAbdullah Ömer Yamaç 	RETURN_IF_ERROR_RCU_QSBR(status < 0, "failed to add key (pos[%u]=%d)", 0, status);
2304567bb951SAbdullah Ömer Yamaç 
2305567bb951SAbdullah Ömer Yamaç 	/* This should be (total_entries / 2) + 1 (last add) */
2306567bb951SAbdullah Ömer Yamaç 	unsigned int hash_size = rte_hash_count(g_handle);
2307567bb951SAbdullah Ömer Yamaç 
2308567bb951SAbdullah Ömer Yamaç 	/* Freed size should be (total_entries / 2) */
2309567bb951SAbdullah Ömer Yamaç 	rte_hash_rcu_qsbr_dq_reclaim(g_handle, &freed, &pending, &available);
2310567bb951SAbdullah Ömer Yamaç 
2311567bb951SAbdullah Ömer Yamaç 	rte_hash_free(g_handle);
2312567bb951SAbdullah Ömer Yamaç 	rte_free(g_qsv);
2313567bb951SAbdullah Ömer Yamaç 
2314567bb951SAbdullah Ömer Yamaç 	if (hash_size != (total_entries / 2 + 1) || freed != (total_entries / 2)) {
2315567bb951SAbdullah Ömer Yamaç 		printf("Failed to reclaim defer queue\n");
2316567bb951SAbdullah Ömer Yamaç 		return -1;
2317567bb951SAbdullah Ömer Yamaç 	}
2318567bb951SAbdullah Ömer Yamaç 
2319567bb951SAbdullah Ömer Yamaç 	return 0;
2320567bb951SAbdullah Ömer Yamaç }
2321567bb951SAbdullah Ömer Yamaç 
2322567bb951SAbdullah Ömer Yamaç /*
2323a9de470cSBruce Richardson  * Do all unit and performance tests.
2324a9de470cSBruce Richardson  */
2325a9de470cSBruce Richardson static int
2326a9de470cSBruce Richardson test_hash(void)
2327a9de470cSBruce Richardson {
2328e30ef3a3SVladimir Medvedkin 	RTE_BUILD_BUG_ON(sizeof(struct flow_key) % sizeof(uint32_t) != 0);
2329e30ef3a3SVladimir Medvedkin 
2330a9de470cSBruce Richardson 	if (test_add_delete() < 0)
2331a9de470cSBruce Richardson 		return -1;
2332a9de470cSBruce Richardson 	if (test_hash_add_delete_jhash2() < 0)
2333a9de470cSBruce Richardson 		return -1;
2334a9de470cSBruce Richardson 	if (test_hash_add_delete_2_jhash2() < 0)
2335a9de470cSBruce Richardson 		return -1;
2336a9de470cSBruce Richardson 	if (test_hash_add_delete_jhash_1word() < 0)
2337a9de470cSBruce Richardson 		return -1;
2338a9de470cSBruce Richardson 	if (test_hash_add_delete_jhash_2word() < 0)
2339a9de470cSBruce Richardson 		return -1;
2340a9de470cSBruce Richardson 	if (test_hash_add_delete_jhash_3word() < 0)
2341a9de470cSBruce Richardson 		return -1;
2342a9de470cSBruce Richardson 	if (test_hash_get_key_with_position() < 0)
2343a9de470cSBruce Richardson 		return -1;
2344a9de470cSBruce Richardson 	if (test_hash_find_existing() < 0)
2345a9de470cSBruce Richardson 		return -1;
2346a9de470cSBruce Richardson 	if (test_add_update_delete() < 0)
2347a9de470cSBruce Richardson 		return -1;
2348a9de470cSBruce Richardson 	if (test_add_update_delete_free() < 0)
2349a9de470cSBruce Richardson 		return -1;
2350a55f182bSDharmik Thakkar 	if (test_add_delete_free_lf() < 0)
2351a55f182bSDharmik Thakkar 		return -1;
2352a9de470cSBruce Richardson 	if (test_five_keys() < 0)
2353a9de470cSBruce Richardson 		return -1;
2354a9de470cSBruce Richardson 	if (test_full_bucket() < 0)
2355a9de470cSBruce Richardson 		return -1;
2356a9de470cSBruce Richardson 	if (test_extendable_bucket() < 0)
2357a9de470cSBruce Richardson 		return -1;
2358a9de470cSBruce Richardson 
2359a9de470cSBruce Richardson 	if (test_fbk_hash_find_existing() < 0)
2360a9de470cSBruce Richardson 		return -1;
2361a9de470cSBruce Richardson 	if (fbk_hash_unit_test() < 0)
2362a9de470cSBruce Richardson 		return -1;
2363a9de470cSBruce Richardson 	if (test_hash_creation_with_bad_parameters() < 0)
2364a9de470cSBruce Richardson 		return -1;
2365a9de470cSBruce Richardson 	if (test_hash_creation_with_good_parameters() < 0)
2366a9de470cSBruce Richardson 		return -1;
2367a9de470cSBruce Richardson 
2368a9de470cSBruce Richardson 	/* ext table disabled */
2369a9de470cSBruce Richardson 	if (test_average_table_utilization(0) < 0)
2370a9de470cSBruce Richardson 		return -1;
2371a9de470cSBruce Richardson 	if (test_hash_iteration(0) < 0)
2372a9de470cSBruce Richardson 		return -1;
2373a9de470cSBruce Richardson 
2374a9de470cSBruce Richardson 	/* ext table enabled */
2375a9de470cSBruce Richardson 	if (test_average_table_utilization(1) < 0)
2376a9de470cSBruce Richardson 		return -1;
2377a9de470cSBruce Richardson 	if (test_hash_iteration(1) < 0)
2378a9de470cSBruce Richardson 		return -1;
2379a9de470cSBruce Richardson 
2380a9de470cSBruce Richardson 	run_hash_func_tests();
2381a9de470cSBruce Richardson 
2382a9de470cSBruce Richardson 	if (test_crc32_hash_alg_equiv() < 0)
2383a9de470cSBruce Richardson 		return -1;
2384a9de470cSBruce Richardson 
23859c7d8eedSDharmik Thakkar 	if (test_hash_rcu_qsbr_add() < 0)
23869c7d8eedSDharmik Thakkar 		return -1;
23879c7d8eedSDharmik Thakkar 
23889c7d8eedSDharmik Thakkar 	if (test_hash_rcu_qsbr_dq_mode(0) < 0)
23899c7d8eedSDharmik Thakkar 		return -1;
23909c7d8eedSDharmik Thakkar 
23919c7d8eedSDharmik Thakkar 	if (test_hash_rcu_qsbr_dq_mode(1) < 0)
23929c7d8eedSDharmik Thakkar 		return -1;
23939c7d8eedSDharmik Thakkar 
23949c7d8eedSDharmik Thakkar 	if (test_hash_rcu_qsbr_sync_mode(0) < 0)
23959c7d8eedSDharmik Thakkar 		return -1;
23969c7d8eedSDharmik Thakkar 
23979c7d8eedSDharmik Thakkar 	if (test_hash_rcu_qsbr_sync_mode(1) < 0)
23989c7d8eedSDharmik Thakkar 		return -1;
23999c7d8eedSDharmik Thakkar 
2400567bb951SAbdullah Ömer Yamaç 	if (test_hash_rcu_qsbr_dq_reclaim() < 0)
2401567bb951SAbdullah Ömer Yamaç 		return -1;
2402567bb951SAbdullah Ömer Yamaç 
2403a9de470cSBruce Richardson 	return 0;
2404a9de470cSBruce Richardson }
2405a9de470cSBruce Richardson 
2406e0a8442cSBruce Richardson REGISTER_FAST_TEST(hash_autotest, true, true, test_hash);
2407