xref: /dpdk/app/test/test_hash.c (revision b5662e6d288762fe2c538551eb03d68854896e0b)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2015 Intel Corporation
3  */
4 
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <stdlib.h>
9 #include <stdarg.h>
10 #include <errno.h>
11 #include <sys/queue.h>
12 
13 #include <rte_common.h>
14 #include <rte_malloc.h>
15 #include <rte_cycles.h>
16 #include <rte_random.h>
17 #include <rte_memory.h>
18 #include <rte_eal.h>
19 #include <rte_ip.h>
20 #include <rte_string_fns.h>
21 
22 #include "test.h"
23 
24 #include <rte_hash.h>
25 #include <rte_fbk_hash.h>
26 #include <rte_jhash.h>
27 #include <rte_hash_crc.h>
28 
29 /*******************************************************************************
30  * Hash function performance test configuration section. Each performance test
31  * will be performed HASHTEST_ITERATIONS times.
32  *
33  * The five arrays below control what tests are performed. Every combination
34  * from the array entries is tested.
35  */
36 static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
37 static uint32_t hashtest_initvals[] = {0};
38 static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64};
39 #define MAX_KEYSIZE 64
40 /******************************************************************************/
41 #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
42 
43 /*
44  * Check condition and return an error if true. Assumes that "handle" is the
45  * name of the hash structure pointer to be freed.
46  */
47 #define RETURN_IF_ERROR(cond, str, ...) do {				\
48 	if (cond) {							\
49 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
50 		if (handle) rte_hash_free(handle);			\
51 		return -1;						\
52 	}								\
53 } while(0)
54 
55 #define RETURN_IF_ERROR_FBK(cond, str, ...) do {				\
56 	if (cond) {							\
57 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
58 		if (handle) rte_fbk_hash_free(handle);			\
59 		return -1;						\
60 	}								\
61 } while(0)
62 
63 #define RETURN_IF_ERROR_RCU_QSBR(cond, str, ...) do {			\
64 	if (cond) {							\
65 		printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
66 		if (rcu_cfg.mode == RTE_HASH_QSBR_MODE_SYNC) {		\
67 			writer_done = 1;				\
68 			/* Wait until reader exited. */			\
69 			rte_eal_mp_wait_lcore();			\
70 		}							\
71 		rte_hash_free(g_handle);				\
72 		rte_free(g_qsv);					\
73 		return -1;						\
74 	}								\
75 } while (0)
76 
77 /*
78  * 5-tuple key type.
79  * Should be packed to avoid holes with potentially
80  * undefined content in the middle.
81  */
82 struct __rte_packed_begin flow_key {
83 	uint32_t ip_src;
84 	uint32_t ip_dst;
85 	uint16_t port_src;
86 	uint16_t port_dst;
87 	uint32_t proto;
88 } __rte_packed_end;
89 
90 /*
91  * Hash function that always returns the same value, to easily test what
92  * happens when a bucket is full.
93  */
94 static uint32_t pseudo_hash(__rte_unused const void *keys,
95 			    __rte_unused uint32_t key_len,
96 			    __rte_unused uint32_t init_val)
97 {
98 	return 3 | (3 << 16);
99 }
100 
101 RTE_LOG_REGISTER(hash_logtype_test, test.hash, INFO);
102 
103 /*
104  * Print out result of unit test hash operation.
105  */
106 static void print_key_info(const char *msg, const struct flow_key *key,
107 								int32_t pos)
108 {
109 	const uint8_t *p = (const uint8_t *)key;
110 	unsigned int i;
111 
112 	rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%s key:0x", msg);
113 	for (i = 0; i < sizeof(struct flow_key); i++)
114 		rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%02X", p[i]);
115 	rte_log(RTE_LOG_DEBUG, hash_logtype_test, " @ pos %d\n", pos);
116 }
117 
118 #define KEY_PER_BUCKET 8
119 
120 /* Keys used by unit test functions */
121 static struct flow_key keys[KEY_PER_BUCKET+1] = { {
122 	.ip_src = RTE_IPV4(0x03, 0x02, 0x01, 0x00),
123 	.ip_dst = RTE_IPV4(0x07, 0x06, 0x05, 0x04),
124 	.port_src = 0x0908,
125 	.port_dst = 0x0b0a,
126 	.proto = 0x0c,
127 }, {
128 	.ip_src = RTE_IPV4(0x13, 0x12, 0x11, 0x10),
129 	.ip_dst = RTE_IPV4(0x17, 0x16, 0x15, 0x14),
130 	.port_src = 0x1918,
131 	.port_dst = 0x1b1a,
132 	.proto = 0x1c,
133 }, {
134 	.ip_src = RTE_IPV4(0x23, 0x22, 0x21, 0x20),
135 	.ip_dst = RTE_IPV4(0x27, 0x26, 0x25, 0x24),
136 	.port_src = 0x2928,
137 	.port_dst = 0x2b2a,
138 	.proto = 0x2c,
139 }, {
140 	.ip_src = RTE_IPV4(0x33, 0x32, 0x31, 0x30),
141 	.ip_dst = RTE_IPV4(0x37, 0x36, 0x35, 0x34),
142 	.port_src = 0x3938,
143 	.port_dst = 0x3b3a,
144 	.proto = 0x3c,
145 }, {
146 	.ip_src = RTE_IPV4(0x43, 0x42, 0x41, 0x40),
147 	.ip_dst = RTE_IPV4(0x47, 0x46, 0x45, 0x44),
148 	.port_src = 0x4948,
149 	.port_dst = 0x4b4a,
150 	.proto = 0x4c,
151 }, {
152 	.ip_src = RTE_IPV4(0x53, 0x52, 0x51, 0x50),
153 	.ip_dst = RTE_IPV4(0x57, 0x56, 0x55, 0x54),
154 	.port_src = 0x5958,
155 	.port_dst = 0x5b5a,
156 	.proto = 0x5c,
157 }, {
158 	.ip_src = RTE_IPV4(0x63, 0x62, 0x61, 0x60),
159 	.ip_dst = RTE_IPV4(0x67, 0x66, 0x65, 0x64),
160 	.port_src = 0x6968,
161 	.port_dst = 0x6b6a,
162 	.proto = 0x6c,
163 }, {
164 	.ip_src = RTE_IPV4(0x73, 0x72, 0x71, 0x70),
165 	.ip_dst = RTE_IPV4(0x77, 0x76, 0x75, 0x74),
166 	.port_src = 0x7978,
167 	.port_dst = 0x7b7a,
168 	.proto = 0x7c,
169 }, {
170 	.ip_src = RTE_IPV4(0x83, 0x82, 0x81, 0x80),
171 	.ip_dst = RTE_IPV4(0x87, 0x86, 0x85, 0x84),
172 	.port_src = 0x8988,
173 	.port_dst = 0x8b8a,
174 	.proto = 0x8c,
175 } };
176 
177 /* Parameters used for hash table in unit test functions. Name set later. */
178 static struct rte_hash_parameters ut_params = {
179 	.entries = 64,
180 	.key_len = sizeof(struct flow_key),
181 	.hash_func = rte_jhash,
182 	.hash_func_init_val = 0,
183 	.socket_id = 0,
184 };
185 
186 #define CRC32_ITERATIONS (1U << 10)
187 #define CRC32_DWORDS (1U << 6)
188 /*
189  * Test if all CRC32 implementations yield the same hash value
190  */
191 static int
192 test_crc32_hash_alg_equiv(void)
193 {
194 	uint32_t hash_val;
195 	uint32_t init_val;
196 	uint64_t data64[CRC32_DWORDS];
197 	unsigned i, j;
198 	size_t data_len;
199 
200 	printf("\n# CRC32 implementations equivalence test\n");
201 	for (i = 0; i < CRC32_ITERATIONS; i++) {
202 		/* Randomizing data_len of data set */
203 		data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
204 		init_val = (uint32_t) rte_rand();
205 
206 		/* Fill the data set */
207 		for (j = 0; j < CRC32_DWORDS; j++)
208 			data64[j] = rte_rand();
209 
210 		/* Calculate software CRC32 */
211 		rte_hash_crc_set_alg(CRC32_SW);
212 		hash_val = rte_hash_crc(data64, data_len, init_val);
213 
214 		/* Check against 4-byte-operand sse4.2 CRC32 if available */
215 		rte_hash_crc_set_alg(CRC32_SSE42);
216 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
217 			printf("Failed checking CRC32_SW against CRC32_SSE42\n");
218 			break;
219 		}
220 
221 		/* Check against 8-byte-operand sse4.2 CRC32 if available */
222 		rte_hash_crc_set_alg(CRC32_SSE42_x64);
223 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
224 			printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
225 			break;
226 		}
227 
228 		/* Check against 8-byte-operand ARM64 CRC32 if available */
229 		rte_hash_crc_set_alg(CRC32_ARM64);
230 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
231 			printf("Failed checking CRC32_SW against CRC32_ARM64\n");
232 			break;
233 		}
234 	}
235 
236 	/* Resetting to best available algorithm */
237 	rte_hash_crc_set_alg(CRC32_SSE42_x64);
238 
239 	if (i == CRC32_ITERATIONS)
240 		return 0;
241 
242 	printf("Failed test data (hex, %zu bytes total):\n", data_len);
243 	for (j = 0; j < data_len; j++)
244 		printf("%02X%c", ((uint8_t *)data64)[j],
245 				((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
246 
247 	return -1;
248 }
249 
250 /*
251  * Test a hash function.
252  */
253 static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
254 		uint32_t key_len)
255 {
256 	static uint8_t key[MAX_KEYSIZE];
257 	unsigned i;
258 
259 
260 	for (i = 0; i < key_len; i++)
261 		key[i] = (uint8_t) rte_rand();
262 
263 	/* just to be on the safe side */
264 	if (!f)
265 		return;
266 
267 	f(key, key_len, init_val);
268 }
269 
270 /*
271  * Test all hash functions.
272  */
273 static void run_hash_func_tests(void)
274 {
275 	unsigned i, j, k;
276 
277 	for (i = 0; i < RTE_DIM(hashtest_funcs); i++) {
278 		for (j = 0; j < RTE_DIM(hashtest_initvals); j++) {
279 			for (k = 0; k < RTE_DIM(hashtest_key_lens); k++) {
280 				run_hash_func_test(hashtest_funcs[i],
281 						hashtest_initvals[j],
282 						hashtest_key_lens[k]);
283 			}
284 		}
285 	}
286 }
287 
288 /*
289  * Basic sequence of operations for a single key:
290  *	- add
291  *	- lookup (hit)
292  *	- delete
293  *	- lookup (miss)
294  *
295  * Repeat the test case when 'free on delete' is disabled.
296  *	- add
297  *	- lookup (hit)
298  *	- delete
299  *	- lookup (miss)
300  *	- free
301  */
302 static int test_add_delete(void)
303 {
304 	struct rte_hash *handle;
305 	/* test with standard add/lookup/delete functions */
306 	int pos0, expectedPos0;
307 
308 	ut_params.name = "test1";
309 	handle = rte_hash_create(&ut_params);
310 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
311 
312 	pos0 = rte_hash_add_key(handle, &keys[0]);
313 	print_key_info("Add", &keys[0], pos0);
314 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
315 	expectedPos0 = pos0;
316 
317 	pos0 = rte_hash_lookup(handle, &keys[0]);
318 	print_key_info("Lkp", &keys[0], pos0);
319 	RETURN_IF_ERROR(pos0 != expectedPos0,
320 			"failed to find key (pos0=%d)", pos0);
321 
322 	pos0 = rte_hash_del_key(handle, &keys[0]);
323 	print_key_info("Del", &keys[0], pos0);
324 	RETURN_IF_ERROR(pos0 != expectedPos0,
325 			"failed to delete key (pos0=%d)", pos0);
326 
327 	pos0 = rte_hash_lookup(handle, &keys[0]);
328 	print_key_info("Lkp", &keys[0], pos0);
329 	RETURN_IF_ERROR(pos0 != -ENOENT,
330 			"fail: found key after deleting! (pos0=%d)", pos0);
331 
332 	rte_hash_free(handle);
333 
334 	/* repeat test with precomputed hash functions */
335 	hash_sig_t hash_value;
336 	int pos1, expectedPos1, delPos1;
337 
338 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
339 	handle = rte_hash_create(&ut_params);
340 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
341 	ut_params.extra_flag = 0;
342 
343 	hash_value = rte_hash_hash(handle, &keys[0]);
344 	pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
345 	print_key_info("Add", &keys[0], pos1);
346 	RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
347 	expectedPos1 = pos1;
348 
349 	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
350 	print_key_info("Lkp", &keys[0], pos1);
351 	RETURN_IF_ERROR(pos1 != expectedPos1,
352 			"failed to find key (pos1=%d)", pos1);
353 
354 	pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
355 	print_key_info("Del", &keys[0], pos1);
356 	RETURN_IF_ERROR(pos1 != expectedPos1,
357 			"failed to delete key (pos1=%d)", pos1);
358 	delPos1 = pos1;
359 
360 	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
361 	print_key_info("Lkp", &keys[0], pos1);
362 	RETURN_IF_ERROR(pos1 != -ENOENT,
363 			"fail: found key after deleting! (pos1=%d)", pos1);
364 
365 	pos1 = rte_hash_free_key_with_position(handle, delPos1);
366 	print_key_info("Free", &keys[0], delPos1);
367 	RETURN_IF_ERROR(pos1 != 0,
368 			"failed to free key (pos1=%d)", delPos1);
369 
370 	rte_hash_free(handle);
371 
372 	return 0;
373 }
374 
375 /*
376  * Sequence of operations for a single key:
377  *	- delete: miss
378  *	- add
379  *	- lookup: hit
380  *	- add: update
381  *	- lookup: hit (updated data)
382  *	- delete: hit
383  *	- delete: miss
384  *	- lookup: miss
385  */
386 static int test_add_update_delete(void)
387 {
388 	struct rte_hash *handle;
389 	int pos0, expectedPos0;
390 
391 	ut_params.name = "test2";
392 	handle = rte_hash_create(&ut_params);
393 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
394 
395 	pos0 = rte_hash_del_key(handle, &keys[0]);
396 	print_key_info("Del", &keys[0], pos0);
397 	RETURN_IF_ERROR(pos0 != -ENOENT,
398 			"fail: found non-existent key (pos0=%d)", pos0);
399 
400 	pos0 = rte_hash_add_key(handle, &keys[0]);
401 	print_key_info("Add", &keys[0], pos0);
402 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
403 	expectedPos0 = pos0;
404 
405 	pos0 = rte_hash_lookup(handle, &keys[0]);
406 	print_key_info("Lkp", &keys[0], pos0);
407 	RETURN_IF_ERROR(pos0 != expectedPos0,
408 			"failed to find key (pos0=%d)", pos0);
409 
410 	pos0 = rte_hash_add_key(handle, &keys[0]);
411 	print_key_info("Add", &keys[0], pos0);
412 	RETURN_IF_ERROR(pos0 != expectedPos0,
413 			"failed to re-add key (pos0=%d)", pos0);
414 
415 	pos0 = rte_hash_lookup(handle, &keys[0]);
416 	print_key_info("Lkp", &keys[0], pos0);
417 	RETURN_IF_ERROR(pos0 != expectedPos0,
418 			"failed to find key (pos0=%d)", pos0);
419 
420 	pos0 = rte_hash_del_key(handle, &keys[0]);
421 	print_key_info("Del", &keys[0], pos0);
422 	RETURN_IF_ERROR(pos0 != expectedPos0,
423 			"failed to delete key (pos0=%d)", pos0);
424 
425 	pos0 = rte_hash_del_key(handle, &keys[0]);
426 	print_key_info("Del", &keys[0], pos0);
427 	RETURN_IF_ERROR(pos0 != -ENOENT,
428 			"fail: deleted already deleted key (pos0=%d)", pos0);
429 
430 	pos0 = rte_hash_lookup(handle, &keys[0]);
431 	print_key_info("Lkp", &keys[0], pos0);
432 	RETURN_IF_ERROR(pos0 != -ENOENT,
433 			"fail: found key after deleting! (pos0=%d)", pos0);
434 
435 	rte_hash_free(handle);
436 	return 0;
437 }
438 
439 /*
440  * Sequence of operations for a single key with 'disable free on del' set:
441  *	- delete: miss
442  *	- add
443  *	- lookup: hit
444  *	- add: update
445  *	- lookup: hit (updated data)
446  *	- delete: hit
447  *	- delete: miss
448  *	- lookup: miss
449  *	- free: hit
450  *	- lookup: miss
451  */
452 static int test_add_update_delete_free(void)
453 {
454 	struct rte_hash *handle;
455 	int pos0, expectedPos0, delPos0, result;
456 
457 	ut_params.name = "test2";
458 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
459 	handle = rte_hash_create(&ut_params);
460 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
461 	ut_params.extra_flag = 0;
462 
463 	pos0 = rte_hash_del_key(handle, &keys[0]);
464 	print_key_info("Del", &keys[0], pos0);
465 	RETURN_IF_ERROR(pos0 != -ENOENT,
466 			"fail: found non-existent key (pos0=%d)", pos0);
467 
468 	pos0 = rte_hash_add_key(handle, &keys[0]);
469 	print_key_info("Add", &keys[0], pos0);
470 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
471 	expectedPos0 = pos0;
472 
473 	pos0 = rte_hash_lookup(handle, &keys[0]);
474 	print_key_info("Lkp", &keys[0], pos0);
475 	RETURN_IF_ERROR(pos0 != expectedPos0,
476 			"failed to find key (pos0=%d)", pos0);
477 
478 	pos0 = rte_hash_add_key(handle, &keys[0]);
479 	print_key_info("Add", &keys[0], pos0);
480 	RETURN_IF_ERROR(pos0 != expectedPos0,
481 			"failed to re-add key (pos0=%d)", pos0);
482 
483 	pos0 = rte_hash_lookup(handle, &keys[0]);
484 	print_key_info("Lkp", &keys[0], pos0);
485 	RETURN_IF_ERROR(pos0 != expectedPos0,
486 			"failed to find key (pos0=%d)", pos0);
487 
488 	delPos0 = rte_hash_del_key(handle, &keys[0]);
489 	print_key_info("Del", &keys[0], delPos0);
490 	RETURN_IF_ERROR(delPos0 != expectedPos0,
491 			"failed to delete key (pos0=%d)", delPos0);
492 
493 	pos0 = rte_hash_del_key(handle, &keys[0]);
494 	print_key_info("Del", &keys[0], pos0);
495 	RETURN_IF_ERROR(pos0 != -ENOENT,
496 			"fail: deleted already deleted key (pos0=%d)", pos0);
497 
498 	pos0 = rte_hash_lookup(handle, &keys[0]);
499 	print_key_info("Lkp", &keys[0], pos0);
500 	RETURN_IF_ERROR(pos0 != -ENOENT,
501 			"fail: found key after deleting! (pos0=%d)", pos0);
502 
503 	result = rte_hash_free_key_with_position(handle, delPos0);
504 	print_key_info("Free", &keys[0], delPos0);
505 	RETURN_IF_ERROR(result != 0,
506 			"failed to free key (pos1=%d)", delPos0);
507 
508 	pos0 = rte_hash_lookup(handle, &keys[0]);
509 	print_key_info("Lkp", &keys[0], pos0);
510 	RETURN_IF_ERROR(pos0 != -ENOENT,
511 			"fail: found key after deleting! (pos0=%d)", pos0);
512 
513 	rte_hash_free(handle);
514 	return 0;
515 }
516 
517 /*
518  * Sequence of operations for a single key with 'rw concurrency lock free' set:
519  *	- add
520  *	- delete: hit
521  *	- free: hit
522  * Repeat the test case when 'multi writer add' is enabled.
523  *	- add
524  *	- delete: hit
525  *	- free: hit
526  */
527 static int test_add_delete_free_lf(void)
528 {
529 /* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */
530 #define LCORE_CACHE_SIZE	64
531 	struct rte_hash *handle;
532 	hash_sig_t hash_value;
533 	int pos, expectedPos, delPos;
534 	uint8_t extra_flag;
535 	uint32_t i, ip_src;
536 
537 	extra_flag = ut_params.extra_flag;
538 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
539 	handle = rte_hash_create(&ut_params);
540 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
541 	ut_params.extra_flag = extra_flag;
542 
543 	/*
544 	 * The number of iterations is at least the same as the number of slots
545 	 * rte_hash allocates internally. This is to reveal potential issues of
546 	 * not freeing keys successfully.
547 	 */
548 	for (i = 0; i < ut_params.entries + 1; i++) {
549 		hash_value = rte_hash_hash(handle, &keys[0]);
550 		pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
551 		print_key_info("Add", &keys[0], pos);
552 		RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
553 		expectedPos = pos;
554 
555 		pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
556 		print_key_info("Del", &keys[0], pos);
557 		RETURN_IF_ERROR(pos != expectedPos,
558 				"failed to delete key (pos=%d)", pos);
559 		delPos = pos;
560 
561 		pos = rte_hash_free_key_with_position(handle, delPos);
562 		print_key_info("Free", &keys[0], delPos);
563 		RETURN_IF_ERROR(pos != 0,
564 				"failed to free key (pos=%d)", delPos);
565 	}
566 
567 	rte_hash_free(handle);
568 
569 	extra_flag = ut_params.extra_flag;
570 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
571 				RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
572 	handle = rte_hash_create(&ut_params);
573 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
574 	ut_params.extra_flag = extra_flag;
575 
576 	ip_src = keys[0].ip_src;
577 	/*
578 	 * The number of iterations is at least the same as the number of slots
579 	 * rte_hash allocates internally. This is to reveal potential issues of
580 	 * not freeing keys successfully.
581 	 */
582 	for (i = 0; i < ut_params.entries + (RTE_MAX_LCORE - 1) *
583 					(LCORE_CACHE_SIZE - 1) + 1; i++) {
584 		keys[0].ip_src++;
585 		hash_value = rte_hash_hash(handle, &keys[0]);
586 		pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
587 		print_key_info("Add", &keys[0], pos);
588 		RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
589 		expectedPos = pos;
590 
591 		pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
592 		print_key_info("Del", &keys[0], pos);
593 		RETURN_IF_ERROR(pos != expectedPos,
594 			"failed to delete key (pos=%d)", pos);
595 		delPos = pos;
596 
597 		pos = rte_hash_free_key_with_position(handle, delPos);
598 		print_key_info("Free", &keys[0], delPos);
599 		RETURN_IF_ERROR(pos != 0,
600 			"failed to free key (pos=%d)", delPos);
601 	}
602 	keys[0].ip_src = ip_src;
603 
604 	rte_hash_free(handle);
605 
606 	return 0;
607 }
608 
609 /*
610  * Sequence of operations for retrieving a key with its position
611  *
612  *  - create table
613  *  - add key
614  *  - get the key with its position: hit
615  *  - delete key
616  *  - try to get the deleted key: miss
617  *
618  * Repeat the test case when 'free on delete' is disabled.
619  *  - create table
620  *  - add key
621  *  - get the key with its position: hit
622  *  - delete key
623  *  - try to get the deleted key: hit
624  *  - free key
625  *  - try to get the deleted key: miss
626  *
627  */
628 static int test_hash_get_key_with_position(void)
629 {
630 	struct rte_hash *handle = NULL;
631 	int pos, expectedPos, delPos, result;
632 	void *key;
633 
634 	ut_params.name = "hash_get_key_w_pos";
635 	handle = rte_hash_create(&ut_params);
636 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
637 
638 	pos = rte_hash_add_key(handle, &keys[0]);
639 	print_key_info("Add", &keys[0], pos);
640 	RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
641 	expectedPos = pos;
642 
643 	result = rte_hash_get_key_with_position(handle, pos, &key);
644 	RETURN_IF_ERROR(result != 0, "error retrieving a key");
645 
646 	pos = rte_hash_del_key(handle, &keys[0]);
647 	print_key_info("Del", &keys[0], pos);
648 	RETURN_IF_ERROR(pos != expectedPos,
649 			"failed to delete key (pos0=%d)", pos);
650 
651 	result = rte_hash_get_key_with_position(handle, pos, &key);
652 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
653 
654 	rte_hash_free(handle);
655 
656 	ut_params.name = "hash_get_key_w_pos";
657 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
658 	handle = rte_hash_create(&ut_params);
659 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
660 	ut_params.extra_flag = 0;
661 
662 	pos = rte_hash_add_key(handle, &keys[0]);
663 	print_key_info("Add", &keys[0], pos);
664 	RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
665 	expectedPos = pos;
666 
667 	result = rte_hash_get_key_with_position(handle, pos, &key);
668 	RETURN_IF_ERROR(result != 0, "error retrieving a key");
669 
670 	delPos = rte_hash_del_key(handle, &keys[0]);
671 	print_key_info("Del", &keys[0], delPos);
672 	RETURN_IF_ERROR(delPos != expectedPos,
673 			"failed to delete key (pos0=%d)", delPos);
674 
675 	result = rte_hash_get_key_with_position(handle, delPos, &key);
676 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
677 
678 	result = rte_hash_free_key_with_position(handle, delPos);
679 	print_key_info("Free", &keys[0], delPos);
680 	RETURN_IF_ERROR(result != 0,
681 			"failed to free key (pos1=%d)", delPos);
682 
683 	result = rte_hash_get_key_with_position(handle, delPos, &key);
684 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
685 
686 	rte_hash_free(handle);
687 	return 0;
688 }
689 
690 /*
691  * Sequence of operations for find existing hash table
692  *
693  *  - create table
694  *  - find existing table: hit
695  *  - find non-existing table: miss
696  *
697  */
698 static int test_hash_find_existing(void)
699 {
700 	struct rte_hash *handle = NULL, *result = NULL;
701 
702 	/* Create hash table. */
703 	ut_params.name = "hash_find_existing";
704 	handle = rte_hash_create(&ut_params);
705 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
706 
707 	/* Try to find existing hash table */
708 	result = rte_hash_find_existing("hash_find_existing");
709 	RETURN_IF_ERROR(result != handle, "could not find existing hash table");
710 
711 	/* Try to find non-existing hash table */
712 	result = rte_hash_find_existing("hash_find_non_existing");
713 	RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
714 
715 	/* Cleanup. */
716 	rte_hash_free(handle);
717 
718 	return 0;
719 }
720 
721 /*
722  * Sequence of operations for 5 keys
723  *	- add keys
724  *	- lookup keys: hit
725  *	- add keys (update)
726  *	- lookup keys: hit (updated data)
727  *	- delete keys : hit
728  *	- lookup keys: miss
729  */
730 static int test_five_keys(void)
731 {
732 	struct rte_hash *handle;
733 	const void *key_array[5] = {0};
734 	int pos[5];
735 	int expected_pos[5];
736 	unsigned i;
737 	int ret;
738 
739 	ut_params.name = "test3";
740 	handle = rte_hash_create(&ut_params);
741 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
742 
743 	/* Add */
744 	for (i = 0; i < 5; i++) {
745 		pos[i] = rte_hash_add_key(handle, &keys[i]);
746 		print_key_info("Add", &keys[i], pos[i]);
747 		RETURN_IF_ERROR(pos[i] < 0,
748 				"failed to add key (pos[%u]=%d)", i, pos[i]);
749 		expected_pos[i] = pos[i];
750 	}
751 
752 	/* Lookup */
753 	for(i = 0; i < 5; i++)
754 		key_array[i] = &keys[i];
755 
756 	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
757 	if(ret == 0)
758 		for(i = 0; i < 5; i++) {
759 			print_key_info("Lkp", key_array[i], pos[i]);
760 			RETURN_IF_ERROR(pos[i] != expected_pos[i],
761 					"failed to find key (pos[%u]=%d)", i, pos[i]);
762 		}
763 
764 	/* Add - update */
765 	for (i = 0; i < 5; i++) {
766 		pos[i] = rte_hash_add_key(handle, &keys[i]);
767 		print_key_info("Add", &keys[i], pos[i]);
768 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
769 				"failed to add key (pos[%u]=%d)", i, pos[i]);
770 	}
771 
772 	/* Lookup */
773 	for (i = 0; i < 5; i++) {
774 		pos[i] = rte_hash_lookup(handle, &keys[i]);
775 		print_key_info("Lkp", &keys[i], pos[i]);
776 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
777 				"failed to find key (pos[%u]=%d)", i, pos[i]);
778 	}
779 
780 	/* Delete */
781 	for (i = 0; i < 5; i++) {
782 		pos[i] = rte_hash_del_key(handle, &keys[i]);
783 		print_key_info("Del", &keys[i], pos[i]);
784 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
785 				"failed to delete key (pos[%u]=%d)", i, pos[i]);
786 	}
787 
788 	/* Lookup */
789 	for (i = 0; i < 5; i++) {
790 		pos[i] = rte_hash_lookup(handle, &keys[i]);
791 		print_key_info("Lkp", &keys[i], pos[i]);
792 		RETURN_IF_ERROR(pos[i] != -ENOENT,
793 				"found non-existent key (pos[%u]=%d)", i, pos[i]);
794 	}
795 
796 	/* Lookup multi */
797 	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
798 	if (ret == 0)
799 		for (i = 0; i < 5; i++) {
800 			print_key_info("Lkp", key_array[i], pos[i]);
801 			RETURN_IF_ERROR(pos[i] != -ENOENT,
802 					"found not-existent key (pos[%u]=%d)", i, pos[i]);
803 		}
804 
805 	rte_hash_free(handle);
806 
807 	return 0;
808 }
809 
810 /*
811  * Add keys to the same bucket until bucket full.
812  *	- add 9 keys to the same bucket (hash created with 8 keys per bucket):
813  *	  first 8 successful, 9th successful, pushing existing item in bucket
814  *	- lookup the 9 keys: 9 hits
815  *	- bulk lookup for all the 9 keys: 9 hits
816  *	- add the 9 keys again: 9 OK
817  *	- lookup the 9 keys: 9 hits (updated data)
818  *	- delete the 9 keys: 9 OK
819  *	- lookup the 9 keys: 9 misses
820  *	- bulk lookup for all the 9 keys: 9 misses
821  */
822 static int test_full_bucket(void)
823 {
824 	struct rte_hash_parameters params_pseudo_hash = {
825 		.name = "test4",
826 		.entries = 64,
827 		.key_len = sizeof(struct flow_key),
828 		.hash_func = pseudo_hash,
829 		.hash_func_init_val = 0,
830 		.socket_id = 0,
831 	};
832 	const void *key_array[KEY_PER_BUCKET+1] = {0};
833 	struct rte_hash *handle;
834 	int pos[KEY_PER_BUCKET+1];
835 	int expected_pos[KEY_PER_BUCKET+1];
836 	unsigned i;
837 	int ret;
838 	handle = rte_hash_create(&params_pseudo_hash);
839 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
840 
841 	/* Fill bucket */
842 	for (i = 0; i < KEY_PER_BUCKET; i++) {
843 		pos[i] = rte_hash_add_key(handle, &keys[i]);
844 		print_key_info("Add", &keys[i], pos[i]);
845 		RETURN_IF_ERROR(pos[i] < 0,
846 			"failed to add key (pos[%u]=%d)", i, pos[i]);
847 		expected_pos[i] = pos[i];
848 	}
849 	/*
850 	 * This should work and will push one of the items
851 	 * in the bucket because it is full
852 	 */
853 	pos[KEY_PER_BUCKET] = rte_hash_add_key(handle, &keys[KEY_PER_BUCKET]);
854 	print_key_info("Add", &keys[KEY_PER_BUCKET], pos[KEY_PER_BUCKET]);
855 	RETURN_IF_ERROR(pos[KEY_PER_BUCKET] < 0,
856 			"failed to add key (pos[%d]=%d)", KEY_PER_BUCKET, pos[KEY_PER_BUCKET]);
857 	expected_pos[KEY_PER_BUCKET] = pos[KEY_PER_BUCKET];
858 
859 	/* Lookup */
860 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
861 		pos[i] = rte_hash_lookup(handle, &keys[i]);
862 		print_key_info("Lkp", &keys[i], pos[i]);
863 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
864 			"failed to find key (pos[%u]=%d)", i, pos[i]);
865 	}
866 
867 	for (i = 0; i < KEY_PER_BUCKET+1; i++)
868 		key_array[i] = &keys[i];
869 
870 	/*Bulk lookup after add with same hash*/
871 	ret = rte_hash_lookup_bulk(handle, key_array, KEY_PER_BUCKET+1, (int32_t *)pos);
872 	RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret);
873 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
874 		print_key_info("Blk_Lkp", key_array[i], pos[i]);
875 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
876 				"failed to find key (pos[%u]=%d)", i, pos[i]);
877 	}
878 
879 
880 
881 	/* Add - update */
882 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
883 		pos[i] = rte_hash_add_key(handle, &keys[i]);
884 		print_key_info("Add", &keys[i], pos[i]);
885 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
886 			"failed to add key (pos[%u]=%d)", i, pos[i]);
887 	}
888 
889 	/* Lookup */
890 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
891 		pos[i] = rte_hash_lookup(handle, &keys[i]);
892 		print_key_info("Lkp", &keys[i], pos[i]);
893 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
894 			"failed to find key (pos[%u]=%d)", i, pos[i]);
895 	}
896 
897 	/* Delete 1 key, check other keys are still found */
898 	pos[1] = rte_hash_del_key(handle, &keys[1]);
899 	print_key_info("Del", &keys[1], pos[1]);
900 	RETURN_IF_ERROR(pos[1] != expected_pos[1],
901 			"failed to delete key (pos[1]=%d)", pos[1]);
902 	pos[3] = rte_hash_lookup(handle, &keys[3]);
903 	print_key_info("Lkp", &keys[3], pos[3]);
904 	RETURN_IF_ERROR(pos[3] != expected_pos[3],
905 			"failed lookup after deleting key from same bucket "
906 			"(pos[3]=%d)", pos[3]);
907 
908 	/* Go back to previous state */
909 	pos[1] = rte_hash_add_key(handle, &keys[1]);
910 	print_key_info("Add", &keys[1], pos[1]);
911 	expected_pos[1] = pos[1];
912 	RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
913 
914 	/* Delete */
915 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
916 		pos[i] = rte_hash_del_key(handle, &keys[i]);
917 		print_key_info("Del", &keys[i], pos[i]);
918 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
919 			"failed to delete key (pos[%u]=%d)", i, pos[i]);
920 	}
921 
922 	/* Lookup */
923 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
924 		pos[i] = rte_hash_lookup(handle, &keys[i]);
925 		print_key_info("Lkp", &keys[i], pos[i]);
926 		RETURN_IF_ERROR(pos[i] != -ENOENT,
927 			"fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
928 	}
929 
930 	/* Bulk Lookup on empty table*/
931 	ret = rte_hash_lookup_bulk(handle, &key_array[0], KEY_PER_BUCKET+1, (int32_t *)pos);
932 	RETURN_IF_ERROR(ret, "rte_hash_lookup_bulk returned an error: %d\n", ret);
933 	for (i = 0; i < KEY_PER_BUCKET+1; i++) {
934 		print_key_info("Blk_Lkp", key_array[i], pos[i]);
935 		RETURN_IF_ERROR(pos[i] != -ENOENT,
936 				"failed to find key (pos[%u]=%d)", i, pos[i]);
937 	}
938 
939 	rte_hash_free(handle);
940 
941 	/* Cover the NULL case. */
942 	rte_hash_free(0);
943 	return 0;
944 }
945 
946 /*
947  * Similar to the test above (full bucket test), but for extendable buckets.
948  */
949 static int test_extendable_bucket(void)
950 {
951 	struct rte_hash_parameters params_pseudo_hash = {
952 		.name = "test5",
953 		.entries = 64,
954 		.key_len = sizeof(struct flow_key),
955 		.hash_func = pseudo_hash,
956 		.hash_func_init_val = 0,
957 		.socket_id = 0,
958 		.extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE
959 	};
960 	struct rte_hash *handle;
961 	int pos[64];
962 	int expected_pos[64];
963 	unsigned int i;
964 	struct flow_key rand_keys[64];
965 
966 	for (i = 0; i < 64; i++) {
967 		rand_keys[i].port_dst = i;
968 		rand_keys[i].port_src = i+1;
969 	}
970 
971 	handle = rte_hash_create(&params_pseudo_hash);
972 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
973 
974 	/* Fill bucket */
975 	for (i = 0; i < 64; i++) {
976 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
977 		print_key_info("Add", &rand_keys[i], pos[i]);
978 		RETURN_IF_ERROR(pos[i] < 0,
979 			"failed to add key (pos[%u]=%d)", i, pos[i]);
980 		expected_pos[i] = pos[i];
981 	}
982 
983 	/* Lookup */
984 	for (i = 0; i < 64; i++) {
985 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
986 		print_key_info("Lkp", &rand_keys[i], pos[i]);
987 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
988 			"failed to find key (pos[%u]=%d)", i, pos[i]);
989 	}
990 
991 	/* Add - update */
992 	for (i = 0; i < 64; i++) {
993 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
994 		print_key_info("Add", &rand_keys[i], pos[i]);
995 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
996 			"failed to add key (pos[%u]=%d)", i, pos[i]);
997 	}
998 
999 	/* Lookup */
1000 	for (i = 0; i < 64; i++) {
1001 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
1002 		print_key_info("Lkp", &rand_keys[i], pos[i]);
1003 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
1004 			"failed to find key (pos[%u]=%d)", i, pos[i]);
1005 	}
1006 
1007 	/* Delete 1 key, check other keys are still found */
1008 	pos[35] = rte_hash_del_key(handle, &rand_keys[35]);
1009 	print_key_info("Del", &rand_keys[35], pos[35]);
1010 	RETURN_IF_ERROR(pos[35] != expected_pos[35],
1011 			"failed to delete key (pos[1]=%d)", pos[35]);
1012 	pos[20] = rte_hash_lookup(handle, &rand_keys[20]);
1013 	print_key_info("Lkp", &rand_keys[20], pos[20]);
1014 	RETURN_IF_ERROR(pos[20] != expected_pos[20],
1015 			"failed lookup after deleting key from same bucket "
1016 			"(pos[20]=%d)", pos[20]);
1017 
1018 	/* Go back to previous state */
1019 	pos[35] = rte_hash_add_key(handle, &rand_keys[35]);
1020 	print_key_info("Add", &rand_keys[35], pos[35]);
1021 	expected_pos[35] = pos[35];
1022 	RETURN_IF_ERROR(pos[35] < 0, "failed to add key (pos[1]=%d)", pos[35]);
1023 
1024 	/* Delete */
1025 	for (i = 0; i < 64; i++) {
1026 		pos[i] = rte_hash_del_key(handle, &rand_keys[i]);
1027 		print_key_info("Del", &rand_keys[i], pos[i]);
1028 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
1029 			"failed to delete key (pos[%u]=%d)", i, pos[i]);
1030 	}
1031 
1032 	/* Lookup */
1033 	for (i = 0; i < 64; i++) {
1034 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
1035 		print_key_info("Lkp", &rand_keys[i], pos[i]);
1036 		RETURN_IF_ERROR(pos[i] != -ENOENT,
1037 			"fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
1038 	}
1039 
1040 	/* Add again */
1041 	for (i = 0; i < 64; i++) {
1042 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
1043 		print_key_info("Add", &rand_keys[i], pos[i]);
1044 		RETURN_IF_ERROR(pos[i] < 0,
1045 			"failed to add key (pos[%u]=%d)", i, pos[i]);
1046 		expected_pos[i] = pos[i];
1047 	}
1048 
1049 	rte_hash_free(handle);
1050 
1051 	/* Cover the NULL case. */
1052 	rte_hash_free(0);
1053 	return 0;
1054 }
1055 
1056 /******************************************************************************/
1057 static int
1058 fbk_hash_unit_test(void)
1059 {
1060 	struct rte_fbk_hash_params params = {
1061 		.name = "fbk_hash_test",
1062 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1063 		.entries_per_bucket = 4,
1064 		.socket_id = 0,
1065 	};
1066 
1067 	struct rte_fbk_hash_params invalid_params_1 = {
1068 		.name = "invalid_1",
1069 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
1070 		.entries_per_bucket = 4,
1071 		.socket_id = 0,
1072 	};
1073 
1074 	struct rte_fbk_hash_params invalid_params_2 = {
1075 		.name = "invalid_2",
1076 		.entries = 4,
1077 		.entries_per_bucket = 3,         /* Not power of 2 */
1078 		.socket_id = 0,
1079 	};
1080 
1081 	struct rte_fbk_hash_params invalid_params_3 = {
1082 		.name = "invalid_3",
1083 		.entries = 0,                    /* Entries is 0 */
1084 		.entries_per_bucket = 4,
1085 		.socket_id = 0,
1086 	};
1087 
1088 	struct rte_fbk_hash_params invalid_params_4 = {
1089 		.name = "invalid_4",
1090 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1091 		.entries_per_bucket = 0,         /* Entries per bucket is 0 */
1092 		.socket_id = 0,
1093 	};
1094 
1095 	struct rte_fbk_hash_params invalid_params_5 = {
1096 		.name = "invalid_5",
1097 		.entries = 4,
1098 		.entries_per_bucket = 8,         /* Entries per bucket > entries */
1099 		.socket_id = 0,
1100 	};
1101 
1102 	struct rte_fbk_hash_params invalid_params_6 = {
1103 		.name = "invalid_6",
1104 		.entries = RTE_FBK_HASH_ENTRIES_MAX * 2,   /* Entries > max allowed */
1105 		.entries_per_bucket = 4,
1106 		.socket_id = 0,
1107 	};
1108 
1109 	struct rte_fbk_hash_params invalid_params_7 = {
1110 		.name = "invalid_7",
1111 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
1112 		.entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2,	/* Entries > max allowed */
1113 		.socket_id = 0,
1114 	};
1115 
1116 	struct rte_fbk_hash_params invalid_params_8 = {
1117 		.name = "invalid_7",
1118 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
1119 		.entries_per_bucket = 4,
1120 		.socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
1121 	};
1122 
1123 	/* try to create two hashes with identical names
1124 	 * in this case, trying to create a second one will not
1125 	 * fail but will simply return pointer to the existing
1126 	 * hash with that name. sort of like a "find hash by name" :-)
1127 	 */
1128 	struct rte_fbk_hash_params invalid_params_same_name_1 = {
1129 		.name = "same_name",				/* hash with identical name */
1130 		.entries = 4,
1131 		.entries_per_bucket = 2,
1132 		.socket_id = 0,
1133 	};
1134 
1135 	/* trying to create this hash should return a pointer to an existing hash */
1136 	struct rte_fbk_hash_params invalid_params_same_name_2 = {
1137 		.name = "same_name",				/* hash with identical name */
1138 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
1139 		.entries_per_bucket = 4,
1140 		.socket_id = 0,
1141 	};
1142 
1143 	/* this is a sanity check for "same name" test
1144 	 * creating this hash will check if we are actually able to create
1145 	 * multiple hashes with different names (instead of having just one).
1146 	 */
1147 	struct rte_fbk_hash_params different_name = {
1148 		.name = "different_name",			/* different name */
1149 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1150 		.entries_per_bucket = 4,
1151 		.socket_id = 0,
1152 	};
1153 
1154 	struct rte_fbk_hash_params params_jhash = {
1155 		.name = "valid",
1156 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1157 		.entries_per_bucket = 4,
1158 		.socket_id = 0,
1159 		.hash_func = rte_jhash_1word,              /* Tests for different hash_func */
1160 		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1161 	};
1162 
1163 	struct rte_fbk_hash_params params_nohash = {
1164 		.name = "valid nohash",
1165 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1166 		.entries_per_bucket = 4,
1167 		.socket_id = 0,
1168 		.hash_func = NULL,                            /* Tests for null hash_func */
1169 		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1170 	};
1171 
1172 	struct rte_fbk_hash_table *handle, *tmp;
1173 	uint32_t keys[5] =
1174 		{0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
1175 	uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
1176 	int status;
1177 	unsigned i;
1178 	double used_entries;
1179 
1180 	/* Try creating hashes with invalid parameters */
1181 	printf("# Testing hash creation with invalid parameters "
1182 			"- expect error msgs\n");
1183 	handle = rte_fbk_hash_create(&invalid_params_1);
1184 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1185 
1186 	handle = rte_fbk_hash_create(&invalid_params_2);
1187 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1188 
1189 	handle = rte_fbk_hash_create(&invalid_params_3);
1190 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1191 
1192 	handle = rte_fbk_hash_create(&invalid_params_4);
1193 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1194 
1195 	handle = rte_fbk_hash_create(&invalid_params_5);
1196 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1197 
1198 	handle = rte_fbk_hash_create(&invalid_params_6);
1199 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1200 
1201 	handle = rte_fbk_hash_create(&invalid_params_7);
1202 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1203 
1204 	if (rte_eal_has_hugepages()) {
1205 		handle = rte_fbk_hash_create(&invalid_params_8);
1206 		RETURN_IF_ERROR_FBK(handle != NULL,
1207 					"fbk hash creation should have failed");
1208 	}
1209 
1210 	handle = rte_fbk_hash_create(&invalid_params_same_name_1);
1211 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
1212 
1213 	tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
1214 	rte_fbk_hash_free(tmp);
1215 	RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
1216 
1217 	/* we are not freeing  handle here because we need a hash list
1218 	 * to be not empty for the next test */
1219 
1220 	/* create a hash in non-empty list - good for coverage */
1221 	tmp = rte_fbk_hash_create(&different_name);
1222 	RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
1223 
1224 	/* free both hashes */
1225 	rte_fbk_hash_free(handle);
1226 	rte_fbk_hash_free(tmp);
1227 
1228 	/* Create empty jhash hash. */
1229 	handle = rte_fbk_hash_create(&params_jhash);
1230 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
1231 
1232 	/* Cleanup. */
1233 	rte_fbk_hash_free(handle);
1234 
1235 	/* Create empty jhash hash. */
1236 	handle = rte_fbk_hash_create(&params_nohash);
1237 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
1238 
1239 	/* Cleanup. */
1240 	rte_fbk_hash_free(handle);
1241 
1242 	/* Create empty hash. */
1243 	handle = rte_fbk_hash_create(&params);
1244 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1245 
1246 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1247 	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1248 				"load factor right after creation is not zero but it should be");
1249 	/* Add keys. */
1250 	for (i = 0; i < 5; i++) {
1251 		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1252 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1253 	}
1254 
1255 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1256 	RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
1257 				"load factor now is not as expected");
1258 	/* Find value of added keys. */
1259 	for (i = 0; i < 5; i++) {
1260 		status = rte_fbk_hash_lookup(handle, keys[i]);
1261 		RETURN_IF_ERROR_FBK(status != vals[i],
1262 				"fbk hash lookup failed");
1263 	}
1264 
1265 	/* Change value of added keys. */
1266 	for (i = 0; i < 5; i++) {
1267 		status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
1268 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
1269 	}
1270 
1271 	/* Find new values. */
1272 	for (i = 0; i < 5; i++) {
1273 		status = rte_fbk_hash_lookup(handle, keys[i]);
1274 		RETURN_IF_ERROR_FBK(status != vals[4-i],
1275 				"fbk hash lookup failed");
1276 	}
1277 
1278 	/* Delete keys individually. */
1279 	for (i = 0; i < 5; i++) {
1280 		status = rte_fbk_hash_delete_key(handle, keys[i]);
1281 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
1282 	}
1283 
1284 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1285 	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1286 				"load factor right after deletion is not zero but it should be");
1287 	/* Lookup should now fail. */
1288 	for (i = 0; i < 5; i++) {
1289 		status = rte_fbk_hash_lookup(handle, keys[i]);
1290 		RETURN_IF_ERROR_FBK(status == 0,
1291 				"fbk hash lookup should have failed");
1292 	}
1293 
1294 	/* Add keys again. */
1295 	for (i = 0; i < 5; i++) {
1296 		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1297 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1298 	}
1299 
1300 	/* Make sure they were added. */
1301 	for (i = 0; i < 5; i++) {
1302 		status = rte_fbk_hash_lookup(handle, keys[i]);
1303 		RETURN_IF_ERROR_FBK(status != vals[i],
1304 				"fbk hash lookup failed");
1305 	}
1306 
1307 	/* Clear all entries. */
1308 	rte_fbk_hash_clear_all(handle);
1309 
1310 	/* Lookup should fail. */
1311 	for (i = 0; i < 5; i++) {
1312 		status = rte_fbk_hash_lookup(handle, keys[i]);
1313 		RETURN_IF_ERROR_FBK(status == 0,
1314 				"fbk hash lookup should have failed");
1315 	}
1316 
1317 	/* coverage */
1318 
1319 	/* fill up the hash_table */
1320 	for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
1321 		rte_fbk_hash_add_key(handle, i, (uint16_t) i);
1322 
1323 	/* Find non-existent key in a full hashtable */
1324 	status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1325 	RETURN_IF_ERROR_FBK(status != -ENOENT,
1326 			"fbk hash lookup succeeded");
1327 
1328 	/* Delete non-existent key in a full hashtable */
1329 	status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1330 	RETURN_IF_ERROR_FBK(status != -ENOENT,
1331 			"fbk hash delete succeeded");
1332 
1333 	/* Delete one key from a full hashtable */
1334 	status = rte_fbk_hash_delete_key(handle, 1);
1335 	RETURN_IF_ERROR_FBK(status != 0,
1336 			"fbk hash delete failed");
1337 
1338 	/* Clear all entries. */
1339 	rte_fbk_hash_clear_all(handle);
1340 
1341 	/* Cleanup. */
1342 	rte_fbk_hash_free(handle);
1343 
1344 	/* Cover the NULL case. */
1345 	rte_fbk_hash_free(0);
1346 
1347 	return 0;
1348 }
1349 
1350 /*
1351  * Sequence of operations for find existing fbk hash table
1352  *
1353  *  - create table
1354  *  - find existing table: hit
1355  *  - find non-existing table: miss
1356  *
1357  */
1358 static int test_fbk_hash_find_existing(void)
1359 {
1360 	struct rte_fbk_hash_params params = {
1361 			.name = "fbk_hash_find_existing",
1362 			.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1363 			.entries_per_bucket = 4,
1364 			.socket_id = 0,
1365 	};
1366 	struct rte_fbk_hash_table *handle = NULL, *result = NULL;
1367 
1368 	/* Create hash table. */
1369 	handle = rte_fbk_hash_create(&params);
1370 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1371 
1372 	/* Try to find existing fbk hash table */
1373 	result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
1374 	RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
1375 
1376 	/* Try to find non-existing fbk hash table */
1377 	result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
1378 	RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
1379 
1380 	/* Cleanup. */
1381 	rte_fbk_hash_free(handle);
1382 
1383 	return 0;
1384 }
1385 
1386 #define BUCKET_ENTRIES 4
1387 /*
1388  * Do tests for hash creation with bad parameters.
1389  */
1390 static int test_hash_creation_with_bad_parameters(void)
1391 {
1392 	struct rte_hash *handle, *tmp;
1393 	struct rte_hash_parameters params;
1394 
1395 	handle = rte_hash_create(NULL);
1396 	if (handle != NULL) {
1397 		rte_hash_free(handle);
1398 		printf("Impossible creating hash successfully without any parameter\n");
1399 		return -1;
1400 	}
1401 
1402 	memcpy(&params, &ut_params, sizeof(params));
1403 	params.name = "creation_with_bad_parameters_0";
1404 	params.entries = RTE_HASH_ENTRIES_MAX + 1;
1405 	handle = rte_hash_create(&params);
1406 	if (handle != NULL) {
1407 		rte_hash_free(handle);
1408 		printf("Impossible creating hash successfully with entries in parameter exceeded\n");
1409 		return -1;
1410 	}
1411 
1412 	memcpy(&params, &ut_params, sizeof(params));
1413 	params.name = "creation_with_bad_parameters_2";
1414 	params.entries = BUCKET_ENTRIES - 1;
1415 	handle = rte_hash_create(&params);
1416 	if (handle != NULL) {
1417 		rte_hash_free(handle);
1418 		printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n");
1419 		return -1;
1420 	}
1421 
1422 	memcpy(&params, &ut_params, sizeof(params));
1423 	params.name = "creation_with_bad_parameters_3";
1424 	params.key_len = 0;
1425 	handle = rte_hash_create(&params);
1426 	if (handle != NULL) {
1427 		rte_hash_free(handle);
1428 		printf("Impossible creating hash successfully if key_len in parameter is zero\n");
1429 		return -1;
1430 	}
1431 
1432 	memcpy(&params, &ut_params, sizeof(params));
1433 	params.name = "creation_with_bad_parameters_4";
1434 	params.socket_id = RTE_MAX_NUMA_NODES + 1;
1435 	handle = rte_hash_create(&params);
1436 	if (handle != NULL) {
1437 		rte_hash_free(handle);
1438 		printf("Impossible creating hash successfully with invalid socket\n");
1439 		return -1;
1440 	}
1441 
1442 	/* test with same name should fail */
1443 	memcpy(&params, &ut_params, sizeof(params));
1444 	params.name = "same_name";
1445 	handle = rte_hash_create(&params);
1446 	if (handle == NULL) {
1447 		printf("Cannot create first hash table with 'same_name'\n");
1448 		return -1;
1449 	}
1450 	tmp = rte_hash_create(&params);
1451 	if (tmp != NULL) {
1452 		printf("Creation of hash table with same name should fail\n");
1453 		rte_hash_free(handle);
1454 		rte_hash_free(tmp);
1455 		return -1;
1456 	}
1457 	rte_hash_free(handle);
1458 
1459 	printf("# Test successful. No more errors expected\n");
1460 
1461 	return 0;
1462 }
1463 
1464 /*
1465  * Do tests for hash creation with parameters that look incorrect
1466  * but are actually valid.
1467  */
1468 static int
1469 test_hash_creation_with_good_parameters(void)
1470 {
1471 	struct rte_hash *handle;
1472 	struct rte_hash_parameters params;
1473 
1474 	/* create with null hash function - should choose DEFAULT_HASH_FUNC */
1475 	memcpy(&params, &ut_params, sizeof(params));
1476 	params.name = "name";
1477 	params.hash_func = NULL;
1478 	handle = rte_hash_create(&params);
1479 	if (handle == NULL) {
1480 		printf("Creating hash with null hash_func failed\n");
1481 		return -1;
1482 	}
1483 
1484 	rte_hash_free(handle);
1485 
1486 	return 0;
1487 }
1488 
1489 #define ITERATIONS 3
1490 /*
1491  * Test to see the average table utilization (entries added/max entries)
1492  * before hitting a random entry that cannot be added
1493  */
1494 static int test_average_table_utilization(uint32_t ext_table)
1495 {
1496 	struct rte_hash *handle;
1497 	uint8_t simple_key[MAX_KEYSIZE];
1498 	unsigned i, j;
1499 	unsigned added_keys, average_keys_added = 0;
1500 	int ret;
1501 	unsigned int cnt;
1502 
1503 	printf("\n# Running test to determine average utilization"
1504 	       "\n  before adding elements begins to fail\n");
1505 	if (ext_table)
1506 		printf("ext table is enabled\n");
1507 	else
1508 		printf("ext table is disabled\n");
1509 
1510 	printf("Measuring performance, please wait");
1511 	fflush(stdout);
1512 	ut_params.entries = 1 << 16;
1513 	ut_params.name = "test_average_utilization";
1514 	ut_params.hash_func = rte_jhash;
1515 	if (ext_table)
1516 		ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1517 	else
1518 		ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1519 
1520 	handle = rte_hash_create(&ut_params);
1521 
1522 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1523 
1524 	for (j = 0; j < ITERATIONS; j++) {
1525 		ret = 0;
1526 		/* Add random entries until key cannot be added */
1527 		for (added_keys = 0; ret >= 0; added_keys++) {
1528 			for (i = 0; i < ut_params.key_len; i++)
1529 				simple_key[i] = rte_rand() % 255;
1530 			ret = rte_hash_add_key(handle, simple_key);
1531 			if (ret < 0)
1532 				break;
1533 		}
1534 
1535 		if (ret != -ENOSPC) {
1536 			printf("Unexpected error when adding keys\n");
1537 			rte_hash_free(handle);
1538 			return -1;
1539 		}
1540 
1541 		cnt = rte_hash_count(handle);
1542 		if (cnt != added_keys) {
1543 			printf("rte_hash_count returned wrong value %u, %u,"
1544 					"%u\n", j, added_keys, cnt);
1545 			rte_hash_free(handle);
1546 			return -1;
1547 		}
1548 		if (ext_table) {
1549 			if (cnt != ut_params.entries) {
1550 				printf("rte_hash_count returned wrong value "
1551 					"%u, %u, %u\n", j, added_keys, cnt);
1552 				rte_hash_free(handle);
1553 				return -1;
1554 			}
1555 		}
1556 
1557 		average_keys_added += added_keys;
1558 
1559 		/* Reset the table */
1560 		rte_hash_reset(handle);
1561 
1562 		/* Print a dot to show progress on operations */
1563 		printf(".");
1564 		fflush(stdout);
1565 	}
1566 
1567 	average_keys_added /= ITERATIONS;
1568 
1569 	printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
1570 		((double) average_keys_added / ut_params.entries * 100),
1571 		average_keys_added, ut_params.entries);
1572 	rte_hash_free(handle);
1573 
1574 	return 0;
1575 }
1576 
1577 #define NUM_ENTRIES 256
1578 static int test_hash_iteration(uint32_t ext_table)
1579 {
1580 	struct rte_hash *handle;
1581 	unsigned i;
1582 	uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE];
1583 	const void *next_key;
1584 	void *next_data;
1585 	void *data[NUM_ENTRIES];
1586 	unsigned added_keys;
1587 	uint32_t iter = 0;
1588 	int ret = 0;
1589 
1590 	ut_params.entries = NUM_ENTRIES;
1591 	ut_params.name = "test_hash_iteration";
1592 	ut_params.hash_func = rte_jhash;
1593 	ut_params.key_len = 16;
1594 	if (ext_table)
1595 		ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1596 	else
1597 		ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1598 
1599 	handle = rte_hash_create(&ut_params);
1600 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1601 
1602 	/* Add random entries until key cannot be added */
1603 	for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
1604 		data[added_keys] = (void *) ((uintptr_t) rte_rand());
1605 		for (i = 0; i < ut_params.key_len; i++)
1606 			keys[added_keys][i] = rte_rand() % 255;
1607 		ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]);
1608 		if (ret < 0) {
1609 			if (ext_table) {
1610 				printf("Insertion failed for ext table\n");
1611 				goto err;
1612 			}
1613 			break;
1614 		}
1615 	}
1616 
1617 	/* Iterate through the hash table */
1618 	while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
1619 		/* Search for the key in the list of keys added */
1620 		for (i = 0; i < NUM_ENTRIES; i++) {
1621 			if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
1622 				if (next_data != data[i]) {
1623 					printf("Data found in the hash table is"
1624 					       "not the data added with the key\n");
1625 					goto err;
1626 				}
1627 				added_keys--;
1628 				break;
1629 			}
1630 		}
1631 		if (i == NUM_ENTRIES) {
1632 			printf("Key found in the hash table was not added\n");
1633 			goto err;
1634 		}
1635 	}
1636 
1637 	/* Check if all keys have been iterated */
1638 	if (added_keys != 0) {
1639 		printf("There were still %u keys to iterate\n", added_keys);
1640 		goto err;
1641 	}
1642 
1643 	rte_hash_free(handle);
1644 	return 0;
1645 
1646 err:
1647 	rte_hash_free(handle);
1648 	return -1;
1649 }
1650 
1651 static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
1652 			0x04, 0x05, 0x06, 0x07,
1653 			0x08, 0x09, 0x0a, 0x0b,
1654 			0x0c, 0x0d, 0x0e, 0x0f};
1655 static struct rte_hash_parameters hash_params_ex = {
1656 	.name = NULL,
1657 	.entries = 64,
1658 	.key_len = 0,
1659 	.hash_func = NULL,
1660 	.hash_func_init_val = 0,
1661 	.socket_id = 0,
1662 };
1663 
1664 /*
1665  * Wrapper function around rte_jhash_32b.
1666  * It is required because rte_jhash_32b() accepts the length
1667  * as size of 4-byte units.
1668  */
1669 static inline uint32_t
1670 test_jhash_32b(const void *k, uint32_t length, uint32_t initval)
1671 {
1672 	return rte_jhash_32b(k, length >> 2, initval);
1673 }
1674 
1675 /*
1676  * add/delete key with jhash2
1677  */
1678 static int
1679 test_hash_add_delete_jhash2(void)
1680 {
1681 	int ret = -1;
1682 	struct rte_hash *handle;
1683 	int32_t pos1, pos2;
1684 
1685 	hash_params_ex.name = "hash_test_jhash2";
1686 	hash_params_ex.key_len = 4;
1687 	hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1688 
1689 	handle = rte_hash_create(&hash_params_ex);
1690 	if (handle == NULL) {
1691 		printf("test_hash_add_delete_jhash2 fail to create hash\n");
1692 		goto fail_jhash2;
1693 	}
1694 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1695 	if (pos1 < 0) {
1696 		printf("test_hash_add_delete_jhash2 fail to add hash key\n");
1697 		goto fail_jhash2;
1698 	}
1699 
1700 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1701 	if (pos2 < 0 || pos1 != pos2) {
1702 		printf("test_hash_add_delete_jhash2 delete different key from being added\n");
1703 		goto fail_jhash2;
1704 	}
1705 	ret = 0;
1706 
1707 fail_jhash2:
1708 	rte_hash_free(handle);
1709 
1710 	return ret;
1711 }
1712 
1713 /*
1714  * add/delete (2) key with jhash2
1715  */
1716 static int
1717 test_hash_add_delete_2_jhash2(void)
1718 {
1719 	int ret = -1;
1720 	struct rte_hash *handle;
1721 	int32_t pos1, pos2;
1722 
1723 	hash_params_ex.name = "hash_test_2_jhash2";
1724 	hash_params_ex.key_len = 8;
1725 	hash_params_ex.hash_func = (rte_hash_function)test_jhash_32b;
1726 
1727 	handle = rte_hash_create(&hash_params_ex);
1728 	if (handle == NULL)
1729 		goto fail_2_jhash2;
1730 
1731 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1732 	if (pos1 < 0)
1733 		goto fail_2_jhash2;
1734 
1735 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1736 	if (pos2 < 0 || pos1 != pos2)
1737 		goto fail_2_jhash2;
1738 
1739 	ret = 0;
1740 
1741 fail_2_jhash2:
1742 	rte_hash_free(handle);
1743 
1744 	return ret;
1745 }
1746 
1747 static uint32_t
1748 test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
1749 {
1750 	const uint32_t *k = key;
1751 
1752 	RTE_SET_USED(length);
1753 
1754 	return rte_jhash_1word(k[0], initval);
1755 }
1756 
1757 static uint32_t
1758 test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
1759 {
1760 	const uint32_t *k = key;
1761 
1762 	RTE_SET_USED(length);
1763 
1764 	return rte_jhash_2words(k[0], k[1], initval);
1765 }
1766 
1767 static uint32_t
1768 test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
1769 {
1770 	const uint32_t *k = key;
1771 
1772 	RTE_SET_USED(length);
1773 
1774 	return rte_jhash_3words(k[0], k[1], k[2], initval);
1775 }
1776 
1777 /*
1778  * add/delete key with jhash 1word
1779  */
1780 static int
1781 test_hash_add_delete_jhash_1word(void)
1782 {
1783 	int ret = -1;
1784 	struct rte_hash *handle;
1785 	int32_t pos1, pos2;
1786 
1787 	hash_params_ex.name = "hash_test_jhash_1word";
1788 	hash_params_ex.key_len = 4;
1789 	hash_params_ex.hash_func = test_hash_jhash_1word;
1790 
1791 	handle = rte_hash_create(&hash_params_ex);
1792 	if (handle == NULL)
1793 		goto fail_jhash_1word;
1794 
1795 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1796 	if (pos1 < 0)
1797 		goto fail_jhash_1word;
1798 
1799 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1800 	if (pos2 < 0 || pos1 != pos2)
1801 		goto fail_jhash_1word;
1802 
1803 	ret = 0;
1804 
1805 fail_jhash_1word:
1806 	rte_hash_free(handle);
1807 
1808 	return ret;
1809 }
1810 
1811 /*
1812  * add/delete key with jhash 2word
1813  */
1814 static int
1815 test_hash_add_delete_jhash_2word(void)
1816 {
1817 	int ret = -1;
1818 	struct rte_hash *handle;
1819 	int32_t pos1, pos2;
1820 
1821 	hash_params_ex.name = "hash_test_jhash_2word";
1822 	hash_params_ex.key_len = 8;
1823 	hash_params_ex.hash_func = test_hash_jhash_2word;
1824 
1825 	handle = rte_hash_create(&hash_params_ex);
1826 	if (handle == NULL)
1827 		goto fail_jhash_2word;
1828 
1829 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1830 	if (pos1 < 0)
1831 		goto fail_jhash_2word;
1832 
1833 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1834 	if (pos2 < 0 || pos1 != pos2)
1835 		goto fail_jhash_2word;
1836 
1837 	ret = 0;
1838 
1839 fail_jhash_2word:
1840 	rte_hash_free(handle);
1841 
1842 	return ret;
1843 }
1844 
1845 /*
1846  * add/delete key with jhash 3word
1847  */
1848 static int
1849 test_hash_add_delete_jhash_3word(void)
1850 {
1851 	int ret = -1;
1852 	struct rte_hash *handle;
1853 	int32_t pos1, pos2;
1854 
1855 	hash_params_ex.name = "hash_test_jhash_3word";
1856 	hash_params_ex.key_len = 12;
1857 	hash_params_ex.hash_func = test_hash_jhash_3word;
1858 
1859 	handle = rte_hash_create(&hash_params_ex);
1860 	if (handle == NULL)
1861 		goto fail_jhash_3word;
1862 
1863 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1864 	if (pos1 < 0)
1865 		goto fail_jhash_3word;
1866 
1867 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1868 	if (pos2 < 0 || pos1 != pos2)
1869 		goto fail_jhash_3word;
1870 
1871 	ret = 0;
1872 
1873 fail_jhash_3word:
1874 	rte_hash_free(handle);
1875 
1876 	return ret;
1877 }
1878 
1879 static struct rte_hash *g_handle;
1880 static struct rte_rcu_qsbr *g_qsv;
1881 static volatile uint8_t writer_done;
1882 struct flow_key g_rand_keys[9];
1883 
1884 /*
1885  * rte_hash_rcu_qsbr_add positive and negative tests.
1886  *  - Add RCU QSBR variable to Hash
1887  *  - Add another RCU QSBR variable to Hash
1888  *  - Check returns
1889  */
1890 static int
1891 test_hash_rcu_qsbr_add(void)
1892 {
1893 	size_t sz;
1894 	struct rte_rcu_qsbr *qsv2 = NULL;
1895 	int32_t status;
1896 	struct rte_hash_rcu_config rcu_cfg = {0};
1897 	struct rte_hash_parameters params;
1898 
1899 	printf("\n# Running RCU QSBR add tests\n");
1900 	memcpy(&params, &ut_params, sizeof(params));
1901 	params.name = "test_hash_rcu_qsbr_add";
1902 	params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
1903 				RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
1904 	g_handle = rte_hash_create(&params);
1905 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
1906 
1907 	/* Create RCU QSBR variable */
1908 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
1909 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
1910 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1911 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
1912 				 "RCU QSBR variable creation failed");
1913 
1914 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
1915 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
1916 				 "RCU QSBR variable initialization failed");
1917 
1918 	rcu_cfg.v = g_qsv;
1919 	/* Invalid QSBR mode */
1920 	rcu_cfg.mode = 0xff;
1921 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1922 	RETURN_IF_ERROR_RCU_QSBR(status == 0, "Invalid QSBR mode test failed");
1923 
1924 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
1925 	/* Attach RCU QSBR to hash table */
1926 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1927 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
1928 				 "Attach RCU QSBR to hash table failed");
1929 
1930 	/* Create and attach another RCU QSBR to hash table */
1931 	qsv2 = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
1932 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
1933 	RETURN_IF_ERROR_RCU_QSBR(qsv2 == NULL,
1934 				 "RCU QSBR variable creation failed");
1935 
1936 	rcu_cfg.v = qsv2;
1937 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
1938 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
1939 	rte_free(qsv2);
1940 	RETURN_IF_ERROR_RCU_QSBR(status == 0,
1941 			"Attach RCU QSBR to hash table succeeded where failure"
1942 			" is expected");
1943 
1944 	rte_hash_free(g_handle);
1945 	rte_free(g_qsv);
1946 
1947 	return 0;
1948 }
1949 
1950 /*
1951  * rte_hash_rcu_qsbr_add DQ mode functional test.
1952  * Reader and writer are in the same thread in this test.
1953  *  - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
1954  *  - Add RCU QSBR variable to hash
1955  *  - Add 8 hash entries and fill the bucket
1956  *  - If ext bkt is enabled, add 1 extra entry that is available in the ext bkt
1957  *  - Register a reader thread (not a real thread)
1958  *  - Reader lookup existing entry
1959  *  - Writer deletes the entry
1960  *  - Reader lookup the entry
1961  *  - Writer re-add the entry (no available free index)
1962  *  - Reader report quiescent state and unregister
1963  *  - Writer re-add the entry
1964  *  - Reader lookup the entry
1965  */
1966 static int
1967 test_hash_rcu_qsbr_dq_mode(uint8_t ext_bkt)
1968 {
1969 	uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
1970 
1971 	uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
1972 
1973 	if (ext_bkt)
1974 		hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1975 
1976 	struct rte_hash_parameters params_pseudo_hash = {
1977 		.name = "test_hash_rcu_qsbr_dq_mode",
1978 		.entries = total_entries,
1979 		.key_len = sizeof(struct flow_key),
1980 		.hash_func = pseudo_hash,
1981 		.hash_func_init_val = 0,
1982 		.socket_id = 0,
1983 		.extra_flag = hash_extra_flag,
1984 	};
1985 	int pos[total_entries];
1986 	int expected_pos[total_entries];
1987 	unsigned int i;
1988 	size_t sz;
1989 	int32_t status;
1990 	struct rte_hash_rcu_config rcu_cfg = {0};
1991 
1992 	g_qsv = NULL;
1993 	g_handle = NULL;
1994 
1995 	for (i = 0; i < total_entries; i++) {
1996 		g_rand_keys[i].port_dst = i;
1997 		g_rand_keys[i].port_src = i+1;
1998 	}
1999 
2000 	if (ext_bkt)
2001 		printf("\n# Running RCU QSBR DQ mode functional test with"
2002 		       " ext bkt\n");
2003 	else
2004 		printf("\n# Running RCU QSBR DQ mode functional test\n");
2005 
2006 	g_handle = rte_hash_create(&params_pseudo_hash);
2007 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2008 
2009 	/* Create RCU QSBR variable */
2010 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2011 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2012 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2013 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2014 				 "RCU QSBR variable creation failed");
2015 
2016 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2017 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
2018 				 "RCU QSBR variable initialization failed");
2019 
2020 	rcu_cfg.v = g_qsv;
2021 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2022 	/* Attach RCU QSBR to hash table */
2023 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2024 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
2025 				 "Attach RCU QSBR to hash table failed");
2026 
2027 	/* Fill bucket */
2028 	for (i = 0; i < total_entries; i++) {
2029 		pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
2030 		print_key_info("Add", &g_rand_keys[i], pos[i]);
2031 		RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
2032 					 "failed to add key (pos[%u]=%d)", i,
2033 					 pos[i]);
2034 		expected_pos[i] = pos[i];
2035 	}
2036 
2037 	/* Register pseudo reader */
2038 	status = rte_rcu_qsbr_thread_register(g_qsv, 0);
2039 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
2040 				 "RCU QSBR thread registration failed");
2041 	rte_rcu_qsbr_thread_online(g_qsv, 0);
2042 
2043 	/* Lookup */
2044 	pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2045 	print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2046 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2047 				 "failed to find correct key (pos[%u]=%d)", 0,
2048 				 pos[0]);
2049 
2050 	/* Writer update */
2051 	pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
2052 	print_key_info("Del", &g_rand_keys[0], pos[0]);
2053 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2054 				 "failed to del correct key (pos[%u]=%d)", 0,
2055 				 pos[0]);
2056 
2057 	/* Lookup */
2058 	pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2059 	print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2060 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOENT,
2061 				 "found deleted key (pos[%u]=%d)", 0, pos[0]);
2062 
2063 	/* Fill bucket */
2064 	pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2065 	print_key_info("Add", &g_rand_keys[0], pos[0]);
2066 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != -ENOSPC,
2067 				 "Added key successfully (pos[%u]=%d)", 0, pos[0]);
2068 
2069 	/* Reader quiescent */
2070 	rte_rcu_qsbr_quiescent(g_qsv, 0);
2071 
2072 	/* Fill bucket */
2073 	pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2074 	print_key_info("Add", &g_rand_keys[0], pos[0]);
2075 	RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2076 				 "failed to add key (pos[%u]=%d)", 0, pos[0]);
2077 	expected_pos[0] = pos[0];
2078 
2079 	rte_rcu_qsbr_thread_offline(g_qsv, 0);
2080 	(void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2081 
2082 	/* Lookup */
2083 	pos[0] = rte_hash_lookup(g_handle, &g_rand_keys[0]);
2084 	print_key_info("Lkp", &g_rand_keys[0], pos[0]);
2085 	RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2086 				 "failed to find correct key (pos[%u]=%d)", 0,
2087 				 pos[0]);
2088 
2089 	rte_hash_free(g_handle);
2090 	rte_free(g_qsv);
2091 	return 0;
2092 
2093 }
2094 
2095 /* Report quiescent state interval every 1024 lookups. Larger critical
2096  * sections in reader will result in writer polling multiple times.
2097  */
2098 #define QSBR_REPORTING_INTERVAL 1024
2099 #define WRITER_ITERATIONS	512
2100 
2101 /*
2102  * Reader thread using rte_hash data structure with RCU.
2103  */
2104 static int
2105 test_hash_rcu_qsbr_reader(void *arg)
2106 {
2107 	int i;
2108 
2109 	RTE_SET_USED(arg);
2110 	/* Register this thread to report quiescent state */
2111 	(void)rte_rcu_qsbr_thread_register(g_qsv, 0);
2112 	rte_rcu_qsbr_thread_online(g_qsv, 0);
2113 
2114 	do {
2115 		for (i = 0; i < QSBR_REPORTING_INTERVAL; i++)
2116 			rte_hash_lookup(g_handle, &g_rand_keys[0]);
2117 
2118 		/* Update quiescent state */
2119 		rte_rcu_qsbr_quiescent(g_qsv, 0);
2120 	} while (!writer_done);
2121 
2122 	rte_rcu_qsbr_thread_offline(g_qsv, 0);
2123 	(void)rte_rcu_qsbr_thread_unregister(g_qsv, 0);
2124 
2125 	return 0;
2126 }
2127 
2128 /*
2129  * rte_hash_rcu_qsbr_add sync mode functional test.
2130  * 1 Reader and 1 writer. They cannot be in the same thread in this test.
2131  *  - Create hash which supports maximum 8 (9 if ext bkt is enabled) entries
2132  *  - Add RCU QSBR variable to hash
2133  *  - Register a reader thread. Reader keeps looking up a specific key.
2134  *  - Writer keeps adding and deleting a specific key.
2135  */
2136 static int
2137 test_hash_rcu_qsbr_sync_mode(uint8_t ext_bkt)
2138 {
2139 	uint32_t total_entries = (ext_bkt == 0) ? 8 : 9;
2140 
2141 	uint8_t hash_extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2142 
2143 	if (ext_bkt)
2144 		hash_extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
2145 
2146 	struct rte_hash_parameters params_pseudo_hash = {
2147 		.name = "test_hash_rcu_qsbr_sync_mode",
2148 		.entries = total_entries,
2149 		.key_len = sizeof(struct flow_key),
2150 		.hash_func = pseudo_hash,
2151 		.hash_func_init_val = 0,
2152 		.socket_id = 0,
2153 		.extra_flag = hash_extra_flag,
2154 	};
2155 	int pos[total_entries];
2156 	int expected_pos[total_entries];
2157 	unsigned int i;
2158 	size_t sz;
2159 	int32_t status;
2160 	struct rte_hash_rcu_config rcu_cfg = {0};
2161 
2162 	g_qsv = NULL;
2163 	g_handle = NULL;
2164 
2165 	for (i = 0; i < total_entries; i++) {
2166 		g_rand_keys[i].port_dst = i;
2167 		g_rand_keys[i].port_src = i+1;
2168 	}
2169 
2170 	if (ext_bkt)
2171 		printf("\n# Running RCU QSBR sync mode functional test with"
2172 		       " ext bkt\n");
2173 	else
2174 		printf("\n# Running RCU QSBR sync mode functional test\n");
2175 
2176 	g_handle = rte_hash_create(&params_pseudo_hash);
2177 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2178 
2179 	/* Create RCU QSBR variable */
2180 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2181 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(NULL, sz,
2182 					RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2183 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL,
2184 				 "RCU QSBR variable creation failed");
2185 
2186 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2187 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
2188 				 "RCU QSBR variable initialization failed");
2189 
2190 	rcu_cfg.v = g_qsv;
2191 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_SYNC;
2192 	/* Attach RCU QSBR to hash table */
2193 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2194 	RETURN_IF_ERROR_RCU_QSBR(status != 0,
2195 				 "Attach RCU QSBR to hash table failed");
2196 
2197 	/* Launch reader thread */
2198 	rte_eal_remote_launch(test_hash_rcu_qsbr_reader, NULL,
2199 				rte_get_next_lcore(-1, 1, 0));
2200 
2201 	/* Fill bucket */
2202 	for (i = 0; i < total_entries; i++) {
2203 		pos[i] = rte_hash_add_key(g_handle, &g_rand_keys[i]);
2204 		print_key_info("Add", &g_rand_keys[i], pos[i]);
2205 		RETURN_IF_ERROR_RCU_QSBR(pos[i] < 0,
2206 				"failed to add key (pos[%u]=%d)", i, pos[i]);
2207 		expected_pos[i] = pos[i];
2208 	}
2209 	writer_done = 0;
2210 
2211 	/* Writer Update */
2212 	for (i = 0; i < WRITER_ITERATIONS; i++) {
2213 		expected_pos[0] = pos[0];
2214 		pos[0] = rte_hash_del_key(g_handle, &g_rand_keys[0]);
2215 		print_key_info("Del", &g_rand_keys[0], status);
2216 		RETURN_IF_ERROR_RCU_QSBR(pos[0] != expected_pos[0],
2217 					 "failed to del correct key (pos[%u]=%d)"
2218 					 , 0, pos[0]);
2219 
2220 		pos[0] = rte_hash_add_key(g_handle, &g_rand_keys[0]);
2221 		print_key_info("Add", &g_rand_keys[0], pos[0]);
2222 		RETURN_IF_ERROR_RCU_QSBR(pos[0] < 0,
2223 					 "failed to add key (pos[%u]=%d)", 0,
2224 					 pos[0]);
2225 	}
2226 
2227 	writer_done = 1;
2228 	/* Wait until reader exited. */
2229 	rte_eal_mp_wait_lcore();
2230 
2231 	rte_hash_free(g_handle);
2232 	rte_free(g_qsv);
2233 
2234 	return  0;
2235 
2236 }
2237 
2238 /*
2239  * rte_hash_rcu_qsbr_dq_reclaim unit test.
2240  */
2241 static int
2242 test_hash_rcu_qsbr_dq_reclaim(void)
2243 {
2244 	size_t sz;
2245 	int32_t status;
2246 	unsigned int total_entries = 8;
2247 	unsigned int freed, pending, available;
2248 	uint32_t reclaim_keys[8] = {10, 11, 12, 13, 14, 15, 16, 17};
2249 	struct rte_hash_rcu_config rcu_cfg = {0};
2250 	struct rte_hash_parameters hash_params = {
2251 			.name = "test_hash_rcu_qsbr_dq_reclaim",
2252 			.entries = total_entries,
2253 			.key_len = sizeof(uint32_t),
2254 			.hash_func = NULL,
2255 			.hash_func_init_val = 0,
2256 			.socket_id = 0,
2257 	};
2258 
2259 	hash_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
2260 
2261 	g_qsv = NULL;
2262 	g_handle = NULL;
2263 
2264 	printf("\n# Running RCU QSBR DQ mode, reclaim defer queue functional test\n");
2265 
2266 	g_handle = rte_hash_create(&hash_params);
2267 	RETURN_IF_ERROR_RCU_QSBR(g_handle == NULL, "Hash creation failed");
2268 
2269 	/* Create RCU QSBR variable */
2270 	sz = rte_rcu_qsbr_get_memsize(RTE_MAX_LCORE);
2271 	g_qsv = (struct rte_rcu_qsbr *)rte_zmalloc_socket(
2272 			NULL, sz, RTE_CACHE_LINE_SIZE, SOCKET_ID_ANY);
2273 	RETURN_IF_ERROR_RCU_QSBR(g_qsv == NULL, "RCU QSBR variable creation failed");
2274 
2275 	status = rte_rcu_qsbr_init(g_qsv, RTE_MAX_LCORE);
2276 	RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR variable initialization failed");
2277 
2278 	rcu_cfg.v = g_qsv;
2279 	rcu_cfg.dq_size = total_entries;
2280 	rcu_cfg.mode = RTE_HASH_QSBR_MODE_DQ;
2281 
2282 	/* Attach RCU QSBR to hash table */
2283 	status = rte_hash_rcu_qsbr_add(g_handle, &rcu_cfg);
2284 	RETURN_IF_ERROR_RCU_QSBR(status != 0, "Attach RCU QSBR to hash table failed");
2285 
2286 	/* Register pseudo reader */
2287 	status = rte_rcu_qsbr_thread_register(g_qsv, 0);
2288 	RETURN_IF_ERROR_RCU_QSBR(status != 0, "RCU QSBR thread registration failed");
2289 	rte_rcu_qsbr_thread_online(g_qsv, 0);
2290 
2291 	/* Fill half of the hash table */
2292 	for (size_t i = 0; i < total_entries / 2; i++)
2293 		status = rte_hash_add_key(g_handle, &reclaim_keys[i]);
2294 
2295 	/* Try to put these elements into the defer queue*/
2296 	for (size_t i = 0; i < total_entries / 2; i++)
2297 		rte_hash_del_key(g_handle, &reclaim_keys[i]);
2298 
2299 	/* Reader quiescent */
2300 	rte_rcu_qsbr_quiescent(g_qsv, 0);
2301 
2302 	status = rte_hash_add_key(g_handle, &reclaim_keys[0]);
2303 	RETURN_IF_ERROR_RCU_QSBR(status < 0, "failed to add key (pos[%u]=%d)", 0, status);
2304 
2305 	/* This should be (total_entries / 2) + 1 (last add) */
2306 	unsigned int hash_size = rte_hash_count(g_handle);
2307 
2308 	/* Freed size should be (total_entries / 2) */
2309 	rte_hash_rcu_qsbr_dq_reclaim(g_handle, &freed, &pending, &available);
2310 
2311 	rte_hash_free(g_handle);
2312 	rte_free(g_qsv);
2313 
2314 	if (hash_size != (total_entries / 2 + 1) || freed != (total_entries / 2)) {
2315 		printf("Failed to reclaim defer queue\n");
2316 		return -1;
2317 	}
2318 
2319 	return 0;
2320 }
2321 
2322 /*
2323  * Do all unit and performance tests.
2324  */
2325 static int
2326 test_hash(void)
2327 {
2328 	RTE_BUILD_BUG_ON(sizeof(struct flow_key) % sizeof(uint32_t) != 0);
2329 
2330 	if (test_add_delete() < 0)
2331 		return -1;
2332 	if (test_hash_add_delete_jhash2() < 0)
2333 		return -1;
2334 	if (test_hash_add_delete_2_jhash2() < 0)
2335 		return -1;
2336 	if (test_hash_add_delete_jhash_1word() < 0)
2337 		return -1;
2338 	if (test_hash_add_delete_jhash_2word() < 0)
2339 		return -1;
2340 	if (test_hash_add_delete_jhash_3word() < 0)
2341 		return -1;
2342 	if (test_hash_get_key_with_position() < 0)
2343 		return -1;
2344 	if (test_hash_find_existing() < 0)
2345 		return -1;
2346 	if (test_add_update_delete() < 0)
2347 		return -1;
2348 	if (test_add_update_delete_free() < 0)
2349 		return -1;
2350 	if (test_add_delete_free_lf() < 0)
2351 		return -1;
2352 	if (test_five_keys() < 0)
2353 		return -1;
2354 	if (test_full_bucket() < 0)
2355 		return -1;
2356 	if (test_extendable_bucket() < 0)
2357 		return -1;
2358 
2359 	if (test_fbk_hash_find_existing() < 0)
2360 		return -1;
2361 	if (fbk_hash_unit_test() < 0)
2362 		return -1;
2363 	if (test_hash_creation_with_bad_parameters() < 0)
2364 		return -1;
2365 	if (test_hash_creation_with_good_parameters() < 0)
2366 		return -1;
2367 
2368 	/* ext table disabled */
2369 	if (test_average_table_utilization(0) < 0)
2370 		return -1;
2371 	if (test_hash_iteration(0) < 0)
2372 		return -1;
2373 
2374 	/* ext table enabled */
2375 	if (test_average_table_utilization(1) < 0)
2376 		return -1;
2377 	if (test_hash_iteration(1) < 0)
2378 		return -1;
2379 
2380 	run_hash_func_tests();
2381 
2382 	if (test_crc32_hash_alg_equiv() < 0)
2383 		return -1;
2384 
2385 	if (test_hash_rcu_qsbr_add() < 0)
2386 		return -1;
2387 
2388 	if (test_hash_rcu_qsbr_dq_mode(0) < 0)
2389 		return -1;
2390 
2391 	if (test_hash_rcu_qsbr_dq_mode(1) < 0)
2392 		return -1;
2393 
2394 	if (test_hash_rcu_qsbr_sync_mode(0) < 0)
2395 		return -1;
2396 
2397 	if (test_hash_rcu_qsbr_sync_mode(1) < 0)
2398 		return -1;
2399 
2400 	if (test_hash_rcu_qsbr_dq_reclaim() < 0)
2401 		return -1;
2402 
2403 	return 0;
2404 }
2405 
2406 REGISTER_FAST_TEST(hash_autotest, true, true, test_hash);
2407