xref: /dpdk/app/test/test_hash.c (revision 2d0c29a37a9c080c1cccb1ad7941aba2ccf5437e)
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 /* 5-tuple key type */
64 struct flow_key {
65 	uint32_t ip_src;
66 	uint32_t ip_dst;
67 	uint16_t port_src;
68 	uint16_t port_dst;
69 	uint8_t proto;
70 } __attribute__((packed));
71 
72 int hash_logtype_test;
73 
74 /*
75  * Hash function that always returns the same value, to easily test what
76  * happens when a bucket is full.
77  */
78 static uint32_t pseudo_hash(__attribute__((unused)) const void *keys,
79 			    __attribute__((unused)) uint32_t key_len,
80 			    __attribute__((unused)) uint32_t init_val)
81 {
82 	return 3;
83 }
84 
85 RTE_INIT(test_hash_init_log)
86 {
87 	hash_logtype_test = rte_log_register("test.hash");
88 }
89 
90 /*
91  * Print out result of unit test hash operation.
92  */
93 static void print_key_info(const char *msg, const struct flow_key *key,
94 								int32_t pos)
95 {
96 	const uint8_t *p = (const uint8_t *)key;
97 	unsigned int i;
98 
99 	rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%s key:0x", msg);
100 	for (i = 0; i < sizeof(struct flow_key); i++)
101 		rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%02X", p[i]);
102 	rte_log(RTE_LOG_DEBUG, hash_logtype_test, " @ pos %d\n", pos);
103 }
104 
105 /* Keys used by unit test functions */
106 static struct flow_key keys[5] = { {
107 	.ip_src = IPv4(0x03, 0x02, 0x01, 0x00),
108 	.ip_dst = IPv4(0x07, 0x06, 0x05, 0x04),
109 	.port_src = 0x0908,
110 	.port_dst = 0x0b0a,
111 	.proto = 0x0c,
112 }, {
113 	.ip_src = IPv4(0x13, 0x12, 0x11, 0x10),
114 	.ip_dst = IPv4(0x17, 0x16, 0x15, 0x14),
115 	.port_src = 0x1918,
116 	.port_dst = 0x1b1a,
117 	.proto = 0x1c,
118 }, {
119 	.ip_src = IPv4(0x23, 0x22, 0x21, 0x20),
120 	.ip_dst = IPv4(0x27, 0x26, 0x25, 0x24),
121 	.port_src = 0x2928,
122 	.port_dst = 0x2b2a,
123 	.proto = 0x2c,
124 }, {
125 	.ip_src = IPv4(0x33, 0x32, 0x31, 0x30),
126 	.ip_dst = IPv4(0x37, 0x36, 0x35, 0x34),
127 	.port_src = 0x3938,
128 	.port_dst = 0x3b3a,
129 	.proto = 0x3c,
130 }, {
131 	.ip_src = IPv4(0x43, 0x42, 0x41, 0x40),
132 	.ip_dst = IPv4(0x47, 0x46, 0x45, 0x44),
133 	.port_src = 0x4948,
134 	.port_dst = 0x4b4a,
135 	.proto = 0x4c,
136 } };
137 
138 /* Parameters used for hash table in unit test functions. Name set later. */
139 static struct rte_hash_parameters ut_params = {
140 	.entries = 64,
141 	.key_len = sizeof(struct flow_key), /* 13 */
142 	.hash_func = rte_jhash,
143 	.hash_func_init_val = 0,
144 	.socket_id = 0,
145 };
146 
147 #define CRC32_ITERATIONS (1U << 10)
148 #define CRC32_DWORDS (1U << 6)
149 /*
150  * Test if all CRC32 implementations yield the same hash value
151  */
152 static int
153 test_crc32_hash_alg_equiv(void)
154 {
155 	uint32_t hash_val;
156 	uint32_t init_val;
157 	uint64_t data64[CRC32_DWORDS];
158 	unsigned i, j;
159 	size_t data_len;
160 
161 	printf("\n# CRC32 implementations equivalence test\n");
162 	for (i = 0; i < CRC32_ITERATIONS; i++) {
163 		/* Randomizing data_len of data set */
164 		data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
165 		init_val = (uint32_t) rte_rand();
166 
167 		/* Fill the data set */
168 		for (j = 0; j < CRC32_DWORDS; j++)
169 			data64[j] = rte_rand();
170 
171 		/* Calculate software CRC32 */
172 		rte_hash_crc_set_alg(CRC32_SW);
173 		hash_val = rte_hash_crc(data64, data_len, init_val);
174 
175 		/* Check against 4-byte-operand sse4.2 CRC32 if available */
176 		rte_hash_crc_set_alg(CRC32_SSE42);
177 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
178 			printf("Failed checking CRC32_SW against CRC32_SSE42\n");
179 			break;
180 		}
181 
182 		/* Check against 8-byte-operand sse4.2 CRC32 if available */
183 		rte_hash_crc_set_alg(CRC32_SSE42_x64);
184 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
185 			printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
186 			break;
187 		}
188 
189 		/* Check against 8-byte-operand ARM64 CRC32 if available */
190 		rte_hash_crc_set_alg(CRC32_ARM64);
191 		if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
192 			printf("Failed checking CRC32_SW against CRC32_ARM64\n");
193 			break;
194 		}
195 	}
196 
197 	/* Resetting to best available algorithm */
198 	rte_hash_crc_set_alg(CRC32_SSE42_x64);
199 
200 	if (i == CRC32_ITERATIONS)
201 		return 0;
202 
203 	printf("Failed test data (hex, %zu bytes total):\n", data_len);
204 	for (j = 0; j < data_len; j++)
205 		printf("%02X%c", ((uint8_t *)data64)[j],
206 				((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
207 
208 	return -1;
209 }
210 
211 /*
212  * Test a hash function.
213  */
214 static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
215 		uint32_t key_len)
216 {
217 	static uint8_t key[MAX_KEYSIZE];
218 	unsigned i;
219 
220 
221 	for (i = 0; i < key_len; i++)
222 		key[i] = (uint8_t) rte_rand();
223 
224 	/* just to be on the safe side */
225 	if (!f)
226 		return;
227 
228 	f(key, key_len, init_val);
229 }
230 
231 /*
232  * Test all hash functions.
233  */
234 static void run_hash_func_tests(void)
235 {
236 	unsigned i, j, k;
237 
238 	for (i = 0;
239 	     i < sizeof(hashtest_funcs) / sizeof(rte_hash_function);
240 	     i++) {
241 		for (j = 0;
242 		     j < sizeof(hashtest_initvals) / sizeof(uint32_t);
243 		     j++) {
244 			for (k = 0;
245 			     k < sizeof(hashtest_key_lens) / sizeof(uint32_t);
246 			     k++) {
247 				run_hash_func_test(hashtest_funcs[i],
248 						hashtest_initvals[j],
249 						hashtest_key_lens[k]);
250 			}
251 		}
252 	}
253 }
254 
255 /*
256  * Basic sequence of operations for a single key:
257  *	- add
258  *	- lookup (hit)
259  *	- delete
260  *	- lookup (miss)
261  *
262  * Repeat the test case when 'free on delete' is disabled.
263  *	- add
264  *	- lookup (hit)
265  *	- delete
266  *	- lookup (miss)
267  *	- free
268  */
269 static int test_add_delete(void)
270 {
271 	struct rte_hash *handle;
272 	/* test with standard add/lookup/delete functions */
273 	int pos0, expectedPos0;
274 
275 	ut_params.name = "test1";
276 	handle = rte_hash_create(&ut_params);
277 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
278 
279 	pos0 = rte_hash_add_key(handle, &keys[0]);
280 	print_key_info("Add", &keys[0], pos0);
281 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
282 	expectedPos0 = pos0;
283 
284 	pos0 = rte_hash_lookup(handle, &keys[0]);
285 	print_key_info("Lkp", &keys[0], pos0);
286 	RETURN_IF_ERROR(pos0 != expectedPos0,
287 			"failed to find key (pos0=%d)", pos0);
288 
289 	pos0 = rte_hash_del_key(handle, &keys[0]);
290 	print_key_info("Del", &keys[0], pos0);
291 	RETURN_IF_ERROR(pos0 != expectedPos0,
292 			"failed to delete key (pos0=%d)", pos0);
293 
294 	pos0 = rte_hash_lookup(handle, &keys[0]);
295 	print_key_info("Lkp", &keys[0], pos0);
296 	RETURN_IF_ERROR(pos0 != -ENOENT,
297 			"fail: found key after deleting! (pos0=%d)", pos0);
298 
299 	rte_hash_free(handle);
300 
301 	/* repeat test with precomputed hash functions */
302 	hash_sig_t hash_value;
303 	int pos1, expectedPos1, delPos1;
304 
305 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
306 	handle = rte_hash_create(&ut_params);
307 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
308 	ut_params.extra_flag = 0;
309 
310 	hash_value = rte_hash_hash(handle, &keys[0]);
311 	pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
312 	print_key_info("Add", &keys[0], pos1);
313 	RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
314 	expectedPos1 = pos1;
315 
316 	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
317 	print_key_info("Lkp", &keys[0], pos1);
318 	RETURN_IF_ERROR(pos1 != expectedPos1,
319 			"failed to find key (pos1=%d)", pos1);
320 
321 	pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
322 	print_key_info("Del", &keys[0], pos1);
323 	RETURN_IF_ERROR(pos1 != expectedPos1,
324 			"failed to delete key (pos1=%d)", pos1);
325 	delPos1 = pos1;
326 
327 	pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
328 	print_key_info("Lkp", &keys[0], pos1);
329 	RETURN_IF_ERROR(pos1 != -ENOENT,
330 			"fail: found key after deleting! (pos1=%d)", pos1);
331 
332 	pos1 = rte_hash_free_key_with_position(handle, delPos1);
333 	print_key_info("Free", &keys[0], delPos1);
334 	RETURN_IF_ERROR(pos1 != 0,
335 			"failed to free key (pos1=%d)", delPos1);
336 
337 	rte_hash_free(handle);
338 
339 	return 0;
340 }
341 
342 /*
343  * Sequence of operations for a single key:
344  *	- delete: miss
345  *	- add
346  *	- lookup: hit
347  *	- add: update
348  *	- lookup: hit (updated data)
349  *	- delete: hit
350  *	- delete: miss
351  *	- lookup: miss
352  */
353 static int test_add_update_delete(void)
354 {
355 	struct rte_hash *handle;
356 	int pos0, expectedPos0;
357 
358 	ut_params.name = "test2";
359 	handle = rte_hash_create(&ut_params);
360 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
361 
362 	pos0 = rte_hash_del_key(handle, &keys[0]);
363 	print_key_info("Del", &keys[0], pos0);
364 	RETURN_IF_ERROR(pos0 != -ENOENT,
365 			"fail: found non-existent key (pos0=%d)", pos0);
366 
367 	pos0 = rte_hash_add_key(handle, &keys[0]);
368 	print_key_info("Add", &keys[0], pos0);
369 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
370 	expectedPos0 = pos0;
371 
372 	pos0 = rte_hash_lookup(handle, &keys[0]);
373 	print_key_info("Lkp", &keys[0], pos0);
374 	RETURN_IF_ERROR(pos0 != expectedPos0,
375 			"failed to find key (pos0=%d)", pos0);
376 
377 	pos0 = rte_hash_add_key(handle, &keys[0]);
378 	print_key_info("Add", &keys[0], pos0);
379 	RETURN_IF_ERROR(pos0 != expectedPos0,
380 			"failed to re-add key (pos0=%d)", pos0);
381 
382 	pos0 = rte_hash_lookup(handle, &keys[0]);
383 	print_key_info("Lkp", &keys[0], pos0);
384 	RETURN_IF_ERROR(pos0 != expectedPos0,
385 			"failed to find key (pos0=%d)", pos0);
386 
387 	pos0 = rte_hash_del_key(handle, &keys[0]);
388 	print_key_info("Del", &keys[0], pos0);
389 	RETURN_IF_ERROR(pos0 != expectedPos0,
390 			"failed to delete key (pos0=%d)", pos0);
391 
392 	pos0 = rte_hash_del_key(handle, &keys[0]);
393 	print_key_info("Del", &keys[0], pos0);
394 	RETURN_IF_ERROR(pos0 != -ENOENT,
395 			"fail: deleted already deleted key (pos0=%d)", pos0);
396 
397 	pos0 = rte_hash_lookup(handle, &keys[0]);
398 	print_key_info("Lkp", &keys[0], pos0);
399 	RETURN_IF_ERROR(pos0 != -ENOENT,
400 			"fail: found key after deleting! (pos0=%d)", pos0);
401 
402 	rte_hash_free(handle);
403 	return 0;
404 }
405 
406 /*
407  * Sequence of operations for a single key with 'disable free on del' set:
408  *	- delete: miss
409  *	- add
410  *	- lookup: hit
411  *	- add: update
412  *	- lookup: hit (updated data)
413  *	- delete: hit
414  *	- delete: miss
415  *	- lookup: miss
416  *	- free: hit
417  *	- lookup: miss
418  */
419 static int test_add_update_delete_free(void)
420 {
421 	struct rte_hash *handle;
422 	int pos0, expectedPos0, delPos0, result;
423 
424 	ut_params.name = "test2";
425 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
426 	handle = rte_hash_create(&ut_params);
427 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
428 	ut_params.extra_flag = 0;
429 
430 	pos0 = rte_hash_del_key(handle, &keys[0]);
431 	print_key_info("Del", &keys[0], pos0);
432 	RETURN_IF_ERROR(pos0 != -ENOENT,
433 			"fail: found non-existent key (pos0=%d)", pos0);
434 
435 	pos0 = rte_hash_add_key(handle, &keys[0]);
436 	print_key_info("Add", &keys[0], pos0);
437 	RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
438 	expectedPos0 = pos0;
439 
440 	pos0 = rte_hash_lookup(handle, &keys[0]);
441 	print_key_info("Lkp", &keys[0], pos0);
442 	RETURN_IF_ERROR(pos0 != expectedPos0,
443 			"failed to find key (pos0=%d)", pos0);
444 
445 	pos0 = rte_hash_add_key(handle, &keys[0]);
446 	print_key_info("Add", &keys[0], pos0);
447 	RETURN_IF_ERROR(pos0 != expectedPos0,
448 			"failed to re-add key (pos0=%d)", pos0);
449 
450 	pos0 = rte_hash_lookup(handle, &keys[0]);
451 	print_key_info("Lkp", &keys[0], pos0);
452 	RETURN_IF_ERROR(pos0 != expectedPos0,
453 			"failed to find key (pos0=%d)", pos0);
454 
455 	delPos0 = rte_hash_del_key(handle, &keys[0]);
456 	print_key_info("Del", &keys[0], delPos0);
457 	RETURN_IF_ERROR(delPos0 != expectedPos0,
458 			"failed to delete key (pos0=%d)", delPos0);
459 
460 	pos0 = rte_hash_del_key(handle, &keys[0]);
461 	print_key_info("Del", &keys[0], pos0);
462 	RETURN_IF_ERROR(pos0 != -ENOENT,
463 			"fail: deleted already deleted key (pos0=%d)", pos0);
464 
465 	pos0 = rte_hash_lookup(handle, &keys[0]);
466 	print_key_info("Lkp", &keys[0], pos0);
467 	RETURN_IF_ERROR(pos0 != -ENOENT,
468 			"fail: found key after deleting! (pos0=%d)", pos0);
469 
470 	result = rte_hash_free_key_with_position(handle, delPos0);
471 	print_key_info("Free", &keys[0], delPos0);
472 	RETURN_IF_ERROR(result != 0,
473 			"failed to free key (pos1=%d)", delPos0);
474 
475 	pos0 = rte_hash_lookup(handle, &keys[0]);
476 	print_key_info("Lkp", &keys[0], pos0);
477 	RETURN_IF_ERROR(pos0 != -ENOENT,
478 			"fail: found key after deleting! (pos0=%d)", pos0);
479 
480 	rte_hash_free(handle);
481 	return 0;
482 }
483 
484 /*
485  * Sequence of operations for retrieving a key with its position
486  *
487  *  - create table
488  *  - add key
489  *  - get the key with its position: hit
490  *  - delete key
491  *  - try to get the deleted key: miss
492  *
493  * Repeat the test case when 'free on delete' is disabled.
494  *  - create table
495  *  - add key
496  *  - get the key with its position: hit
497  *  - delete key
498  *  - try to get the deleted key: hit
499  *  - free key
500  *  - try to get the deleted key: miss
501  *
502  */
503 static int test_hash_get_key_with_position(void)
504 {
505 	struct rte_hash *handle = NULL;
506 	int pos, expectedPos, delPos, result;
507 	void *key;
508 
509 	ut_params.name = "hash_get_key_w_pos";
510 	handle = rte_hash_create(&ut_params);
511 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
512 
513 	pos = rte_hash_add_key(handle, &keys[0]);
514 	print_key_info("Add", &keys[0], pos);
515 	RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
516 	expectedPos = pos;
517 
518 	result = rte_hash_get_key_with_position(handle, pos, &key);
519 	RETURN_IF_ERROR(result != 0, "error retrieving a key");
520 
521 	pos = rte_hash_del_key(handle, &keys[0]);
522 	print_key_info("Del", &keys[0], pos);
523 	RETURN_IF_ERROR(pos != expectedPos,
524 			"failed to delete key (pos0=%d)", pos);
525 
526 	result = rte_hash_get_key_with_position(handle, pos, &key);
527 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
528 
529 	rte_hash_free(handle);
530 
531 	ut_params.name = "hash_get_key_w_pos";
532 	ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
533 	handle = rte_hash_create(&ut_params);
534 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
535 	ut_params.extra_flag = 0;
536 
537 	pos = rte_hash_add_key(handle, &keys[0]);
538 	print_key_info("Add", &keys[0], pos);
539 	RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
540 	expectedPos = pos;
541 
542 	result = rte_hash_get_key_with_position(handle, pos, &key);
543 	RETURN_IF_ERROR(result != 0, "error retrieving a key");
544 
545 	delPos = rte_hash_del_key(handle, &keys[0]);
546 	print_key_info("Del", &keys[0], delPos);
547 	RETURN_IF_ERROR(delPos != expectedPos,
548 			"failed to delete key (pos0=%d)", delPos);
549 
550 	result = rte_hash_get_key_with_position(handle, delPos, &key);
551 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
552 
553 	result = rte_hash_free_key_with_position(handle, delPos);
554 	print_key_info("Free", &keys[0], delPos);
555 	RETURN_IF_ERROR(result != 0,
556 			"failed to free key (pos1=%d)", delPos);
557 
558 	result = rte_hash_get_key_with_position(handle, delPos, &key);
559 	RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
560 
561 	rte_hash_free(handle);
562 	return 0;
563 }
564 
565 /*
566  * Sequence of operations for find existing hash table
567  *
568  *  - create table
569  *  - find existing table: hit
570  *  - find non-existing table: miss
571  *
572  */
573 static int test_hash_find_existing(void)
574 {
575 	struct rte_hash *handle = NULL, *result = NULL;
576 
577 	/* Create hash table. */
578 	ut_params.name = "hash_find_existing";
579 	handle = rte_hash_create(&ut_params);
580 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
581 
582 	/* Try to find existing hash table */
583 	result = rte_hash_find_existing("hash_find_existing");
584 	RETURN_IF_ERROR(result != handle, "could not find existing hash table");
585 
586 	/* Try to find non-existing hash table */
587 	result = rte_hash_find_existing("hash_find_non_existing");
588 	RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
589 
590 	/* Cleanup. */
591 	rte_hash_free(handle);
592 
593 	return 0;
594 }
595 
596 /*
597  * Sequence of operations for 5 keys
598  *	- add keys
599  *	- lookup keys: hit
600  *	- add keys (update)
601  *	- lookup keys: hit (updated data)
602  *	- delete keys : hit
603  *	- lookup keys: miss
604  */
605 static int test_five_keys(void)
606 {
607 	struct rte_hash *handle;
608 	const void *key_array[5] = {0};
609 	int pos[5];
610 	int expected_pos[5];
611 	unsigned i;
612 	int ret;
613 
614 	ut_params.name = "test3";
615 	handle = rte_hash_create(&ut_params);
616 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
617 
618 	/* Add */
619 	for (i = 0; i < 5; i++) {
620 		pos[i] = rte_hash_add_key(handle, &keys[i]);
621 		print_key_info("Add", &keys[i], pos[i]);
622 		RETURN_IF_ERROR(pos[i] < 0,
623 				"failed to add key (pos[%u]=%d)", i, pos[i]);
624 		expected_pos[i] = pos[i];
625 	}
626 
627 	/* Lookup */
628 	for(i = 0; i < 5; i++)
629 		key_array[i] = &keys[i];
630 
631 	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
632 	if(ret == 0)
633 		for(i = 0; i < 5; i++) {
634 			print_key_info("Lkp", key_array[i], pos[i]);
635 			RETURN_IF_ERROR(pos[i] != expected_pos[i],
636 					"failed to find key (pos[%u]=%d)", i, pos[i]);
637 		}
638 
639 	/* Add - update */
640 	for (i = 0; i < 5; i++) {
641 		pos[i] = rte_hash_add_key(handle, &keys[i]);
642 		print_key_info("Add", &keys[i], pos[i]);
643 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
644 				"failed to add key (pos[%u]=%d)", i, pos[i]);
645 	}
646 
647 	/* Lookup */
648 	for (i = 0; i < 5; i++) {
649 		pos[i] = rte_hash_lookup(handle, &keys[i]);
650 		print_key_info("Lkp", &keys[i], pos[i]);
651 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
652 				"failed to find key (pos[%u]=%d)", i, pos[i]);
653 	}
654 
655 	/* Delete */
656 	for (i = 0; i < 5; i++) {
657 		pos[i] = rte_hash_del_key(handle, &keys[i]);
658 		print_key_info("Del", &keys[i], pos[i]);
659 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
660 				"failed to delete key (pos[%u]=%d)", i, pos[i]);
661 	}
662 
663 	/* Lookup */
664 	for (i = 0; i < 5; i++) {
665 		pos[i] = rte_hash_lookup(handle, &keys[i]);
666 		print_key_info("Lkp", &keys[i], pos[i]);
667 		RETURN_IF_ERROR(pos[i] != -ENOENT,
668 				"found non-existent key (pos[%u]=%d)", i, pos[i]);
669 	}
670 
671 	/* Lookup multi */
672 	ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
673 	if (ret == 0)
674 		for (i = 0; i < 5; i++) {
675 			print_key_info("Lkp", key_array[i], pos[i]);
676 			RETURN_IF_ERROR(pos[i] != -ENOENT,
677 					"found not-existent key (pos[%u]=%d)", i, pos[i]);
678 		}
679 
680 	rte_hash_free(handle);
681 
682 	return 0;
683 }
684 
685 /*
686  * Add keys to the same bucket until bucket full.
687  *	- add 5 keys to the same bucket (hash created with 4 keys per bucket):
688  *	  first 4 successful, 5th successful, pushing existing item in bucket
689  *	- lookup the 5 keys: 5 hits
690  *	- add the 5 keys again: 5 OK
691  *	- lookup the 5 keys: 5 hits (updated data)
692  *	- delete the 5 keys: 5 OK
693  *	- lookup the 5 keys: 5 misses
694  */
695 static int test_full_bucket(void)
696 {
697 	struct rte_hash_parameters params_pseudo_hash = {
698 		.name = "test4",
699 		.entries = 64,
700 		.key_len = sizeof(struct flow_key), /* 13 */
701 		.hash_func = pseudo_hash,
702 		.hash_func_init_val = 0,
703 		.socket_id = 0,
704 	};
705 	struct rte_hash *handle;
706 	int pos[5];
707 	int expected_pos[5];
708 	unsigned i;
709 
710 	handle = rte_hash_create(&params_pseudo_hash);
711 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
712 
713 	/* Fill bucket */
714 	for (i = 0; i < 4; i++) {
715 		pos[i] = rte_hash_add_key(handle, &keys[i]);
716 		print_key_info("Add", &keys[i], pos[i]);
717 		RETURN_IF_ERROR(pos[i] < 0,
718 			"failed to add key (pos[%u]=%d)", i, pos[i]);
719 		expected_pos[i] = pos[i];
720 	}
721 	/*
722 	 * This should work and will push one of the items
723 	 * in the bucket because it is full
724 	 */
725 	pos[4] = rte_hash_add_key(handle, &keys[4]);
726 	print_key_info("Add", &keys[4], pos[4]);
727 	RETURN_IF_ERROR(pos[4] < 0,
728 			"failed to add key (pos[4]=%d)", pos[4]);
729 	expected_pos[4] = pos[4];
730 
731 	/* Lookup */
732 	for (i = 0; i < 5; i++) {
733 		pos[i] = rte_hash_lookup(handle, &keys[i]);
734 		print_key_info("Lkp", &keys[i], pos[i]);
735 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
736 			"failed to find key (pos[%u]=%d)", i, pos[i]);
737 	}
738 
739 	/* Add - update */
740 	for (i = 0; i < 5; i++) {
741 		pos[i] = rte_hash_add_key(handle, &keys[i]);
742 		print_key_info("Add", &keys[i], pos[i]);
743 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
744 			"failed to add key (pos[%u]=%d)", i, pos[i]);
745 	}
746 
747 	/* Lookup */
748 	for (i = 0; i < 5; i++) {
749 		pos[i] = rte_hash_lookup(handle, &keys[i]);
750 		print_key_info("Lkp", &keys[i], pos[i]);
751 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
752 			"failed to find key (pos[%u]=%d)", i, pos[i]);
753 	}
754 
755 	/* Delete 1 key, check other keys are still found */
756 	pos[1] = rte_hash_del_key(handle, &keys[1]);
757 	print_key_info("Del", &keys[1], pos[1]);
758 	RETURN_IF_ERROR(pos[1] != expected_pos[1],
759 			"failed to delete key (pos[1]=%d)", pos[1]);
760 	pos[3] = rte_hash_lookup(handle, &keys[3]);
761 	print_key_info("Lkp", &keys[3], pos[3]);
762 	RETURN_IF_ERROR(pos[3] != expected_pos[3],
763 			"failed lookup after deleting key from same bucket "
764 			"(pos[3]=%d)", pos[3]);
765 
766 	/* Go back to previous state */
767 	pos[1] = rte_hash_add_key(handle, &keys[1]);
768 	print_key_info("Add", &keys[1], pos[1]);
769 	expected_pos[1] = pos[1];
770 	RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
771 
772 	/* Delete */
773 	for (i = 0; i < 5; i++) {
774 		pos[i] = rte_hash_del_key(handle, &keys[i]);
775 		print_key_info("Del", &keys[i], pos[i]);
776 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
777 			"failed to delete key (pos[%u]=%d)", i, pos[i]);
778 	}
779 
780 	/* Lookup */
781 	for (i = 0; i < 5; i++) {
782 		pos[i] = rte_hash_lookup(handle, &keys[i]);
783 		print_key_info("Lkp", &keys[i], pos[i]);
784 		RETURN_IF_ERROR(pos[i] != -ENOENT,
785 			"fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
786 	}
787 
788 	rte_hash_free(handle);
789 
790 	/* Cover the NULL case. */
791 	rte_hash_free(0);
792 	return 0;
793 }
794 
795 /*
796  * Similar to the test above (full bucket test), but for extendable buckets.
797  */
798 static int test_extendable_bucket(void)
799 {
800 	struct rte_hash_parameters params_pseudo_hash = {
801 		.name = "test5",
802 		.entries = 64,
803 		.key_len = sizeof(struct flow_key), /* 13 */
804 		.hash_func = pseudo_hash,
805 		.hash_func_init_val = 0,
806 		.socket_id = 0,
807 		.extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE
808 	};
809 	struct rte_hash *handle;
810 	int pos[64];
811 	int expected_pos[64];
812 	unsigned int i;
813 	struct flow_key rand_keys[64];
814 
815 	for (i = 0; i < 64; i++) {
816 		rand_keys[i].port_dst = i;
817 		rand_keys[i].port_src = i+1;
818 	}
819 
820 	handle = rte_hash_create(&params_pseudo_hash);
821 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
822 
823 	/* Fill bucket */
824 	for (i = 0; i < 64; i++) {
825 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
826 		print_key_info("Add", &rand_keys[i], pos[i]);
827 		RETURN_IF_ERROR(pos[i] < 0,
828 			"failed to add key (pos[%u]=%d)", i, pos[i]);
829 		expected_pos[i] = pos[i];
830 	}
831 
832 	/* Lookup */
833 	for (i = 0; i < 64; i++) {
834 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
835 		print_key_info("Lkp", &rand_keys[i], pos[i]);
836 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
837 			"failed to find key (pos[%u]=%d)", i, pos[i]);
838 	}
839 
840 	/* Add - update */
841 	for (i = 0; i < 64; i++) {
842 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
843 		print_key_info("Add", &rand_keys[i], pos[i]);
844 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
845 			"failed to add key (pos[%u]=%d)", i, pos[i]);
846 	}
847 
848 	/* Lookup */
849 	for (i = 0; i < 64; i++) {
850 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
851 		print_key_info("Lkp", &rand_keys[i], pos[i]);
852 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
853 			"failed to find key (pos[%u]=%d)", i, pos[i]);
854 	}
855 
856 	/* Delete 1 key, check other keys are still found */
857 	pos[35] = rte_hash_del_key(handle, &rand_keys[35]);
858 	print_key_info("Del", &rand_keys[35], pos[35]);
859 	RETURN_IF_ERROR(pos[35] != expected_pos[35],
860 			"failed to delete key (pos[1]=%d)", pos[35]);
861 	pos[20] = rte_hash_lookup(handle, &rand_keys[20]);
862 	print_key_info("Lkp", &rand_keys[20], pos[20]);
863 	RETURN_IF_ERROR(pos[20] != expected_pos[20],
864 			"failed lookup after deleting key from same bucket "
865 			"(pos[20]=%d)", pos[20]);
866 
867 	/* Go back to previous state */
868 	pos[35] = rte_hash_add_key(handle, &rand_keys[35]);
869 	print_key_info("Add", &rand_keys[35], pos[35]);
870 	expected_pos[35] = pos[35];
871 	RETURN_IF_ERROR(pos[35] < 0, "failed to add key (pos[1]=%d)", pos[35]);
872 
873 	/* Delete */
874 	for (i = 0; i < 64; i++) {
875 		pos[i] = rte_hash_del_key(handle, &rand_keys[i]);
876 		print_key_info("Del", &rand_keys[i], pos[i]);
877 		RETURN_IF_ERROR(pos[i] != expected_pos[i],
878 			"failed to delete key (pos[%u]=%d)", i, pos[i]);
879 	}
880 
881 	/* Lookup */
882 	for (i = 0; i < 64; i++) {
883 		pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
884 		print_key_info("Lkp", &rand_keys[i], pos[i]);
885 		RETURN_IF_ERROR(pos[i] != -ENOENT,
886 			"fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
887 	}
888 
889 	/* Add again */
890 	for (i = 0; i < 64; i++) {
891 		pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
892 		print_key_info("Add", &rand_keys[i], pos[i]);
893 		RETURN_IF_ERROR(pos[i] < 0,
894 			"failed to add key (pos[%u]=%d)", i, pos[i]);
895 		expected_pos[i] = pos[i];
896 	}
897 
898 	rte_hash_free(handle);
899 
900 	/* Cover the NULL case. */
901 	rte_hash_free(0);
902 	return 0;
903 }
904 
905 /******************************************************************************/
906 static int
907 fbk_hash_unit_test(void)
908 {
909 	struct rte_fbk_hash_params params = {
910 		.name = "fbk_hash_test",
911 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
912 		.entries_per_bucket = 4,
913 		.socket_id = 0,
914 	};
915 
916 	struct rte_fbk_hash_params invalid_params_1 = {
917 		.name = "invalid_1",
918 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
919 		.entries_per_bucket = 4,
920 		.socket_id = 0,
921 	};
922 
923 	struct rte_fbk_hash_params invalid_params_2 = {
924 		.name = "invalid_2",
925 		.entries = 4,
926 		.entries_per_bucket = 3,         /* Not power of 2 */
927 		.socket_id = 0,
928 	};
929 
930 	struct rte_fbk_hash_params invalid_params_3 = {
931 		.name = "invalid_3",
932 		.entries = 0,                    /* Entries is 0 */
933 		.entries_per_bucket = 4,
934 		.socket_id = 0,
935 	};
936 
937 	struct rte_fbk_hash_params invalid_params_4 = {
938 		.name = "invalid_4",
939 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
940 		.entries_per_bucket = 0,         /* Entries per bucket is 0 */
941 		.socket_id = 0,
942 	};
943 
944 	struct rte_fbk_hash_params invalid_params_5 = {
945 		.name = "invalid_5",
946 		.entries = 4,
947 		.entries_per_bucket = 8,         /* Entries per bucket > entries */
948 		.socket_id = 0,
949 	};
950 
951 	struct rte_fbk_hash_params invalid_params_6 = {
952 		.name = "invalid_6",
953 		.entries = RTE_FBK_HASH_ENTRIES_MAX * 2,   /* Entries > max allowed */
954 		.entries_per_bucket = 4,
955 		.socket_id = 0,
956 	};
957 
958 	struct rte_fbk_hash_params invalid_params_7 = {
959 		.name = "invalid_7",
960 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
961 		.entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2,	/* Entries > max allowed */
962 		.socket_id = 0,
963 	};
964 
965 	struct rte_fbk_hash_params invalid_params_8 = {
966 		.name = "invalid_7",
967 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
968 		.entries_per_bucket = 4,
969 		.socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
970 	};
971 
972 	/* try to create two hashes with identical names
973 	 * in this case, trying to create a second one will not
974 	 * fail but will simply return pointer to the existing
975 	 * hash with that name. sort of like a "find hash by name" :-)
976 	 */
977 	struct rte_fbk_hash_params invalid_params_same_name_1 = {
978 		.name = "same_name",				/* hash with identical name */
979 		.entries = 4,
980 		.entries_per_bucket = 2,
981 		.socket_id = 0,
982 	};
983 
984 	/* trying to create this hash should return a pointer to an existing hash */
985 	struct rte_fbk_hash_params invalid_params_same_name_2 = {
986 		.name = "same_name",				/* hash with identical name */
987 		.entries = RTE_FBK_HASH_ENTRIES_MAX,
988 		.entries_per_bucket = 4,
989 		.socket_id = 0,
990 	};
991 
992 	/* this is a sanity check for "same name" test
993 	 * creating this hash will check if we are actually able to create
994 	 * multiple hashes with different names (instead of having just one).
995 	 */
996 	struct rte_fbk_hash_params different_name = {
997 		.name = "different_name",			/* different name */
998 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
999 		.entries_per_bucket = 4,
1000 		.socket_id = 0,
1001 	};
1002 
1003 	struct rte_fbk_hash_params params_jhash = {
1004 		.name = "valid",
1005 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1006 		.entries_per_bucket = 4,
1007 		.socket_id = 0,
1008 		.hash_func = rte_jhash_1word,              /* Tests for different hash_func */
1009 		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1010 	};
1011 
1012 	struct rte_fbk_hash_params params_nohash = {
1013 		.name = "valid nohash",
1014 		.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1015 		.entries_per_bucket = 4,
1016 		.socket_id = 0,
1017 		.hash_func = NULL,                            /* Tests for null hash_func */
1018 		.init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1019 	};
1020 
1021 	struct rte_fbk_hash_table *handle, *tmp;
1022 	uint32_t keys[5] =
1023 		{0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
1024 	uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
1025 	int status;
1026 	unsigned i;
1027 	double used_entries;
1028 
1029 	/* Try creating hashes with invalid parameters */
1030 	printf("# Testing hash creation with invalid parameters "
1031 			"- expect error msgs\n");
1032 	handle = rte_fbk_hash_create(&invalid_params_1);
1033 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1034 
1035 	handle = rte_fbk_hash_create(&invalid_params_2);
1036 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1037 
1038 	handle = rte_fbk_hash_create(&invalid_params_3);
1039 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1040 
1041 	handle = rte_fbk_hash_create(&invalid_params_4);
1042 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1043 
1044 	handle = rte_fbk_hash_create(&invalid_params_5);
1045 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1046 
1047 	handle = rte_fbk_hash_create(&invalid_params_6);
1048 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1049 
1050 	handle = rte_fbk_hash_create(&invalid_params_7);
1051 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1052 
1053 	handle = rte_fbk_hash_create(&invalid_params_8);
1054 	RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1055 
1056 	handle = rte_fbk_hash_create(&invalid_params_same_name_1);
1057 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
1058 
1059 	tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
1060 	if (tmp != NULL)
1061 		rte_fbk_hash_free(tmp);
1062 	RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
1063 
1064 	/* we are not freeing  handle here because we need a hash list
1065 	 * to be not empty for the next test */
1066 
1067 	/* create a hash in non-empty list - good for coverage */
1068 	tmp = rte_fbk_hash_create(&different_name);
1069 	RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
1070 
1071 	/* free both hashes */
1072 	rte_fbk_hash_free(handle);
1073 	rte_fbk_hash_free(tmp);
1074 
1075 	/* Create empty jhash hash. */
1076 	handle = rte_fbk_hash_create(&params_jhash);
1077 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
1078 
1079 	/* Cleanup. */
1080 	rte_fbk_hash_free(handle);
1081 
1082 	/* Create empty jhash hash. */
1083 	handle = rte_fbk_hash_create(&params_nohash);
1084 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
1085 
1086 	/* Cleanup. */
1087 	rte_fbk_hash_free(handle);
1088 
1089 	/* Create empty hash. */
1090 	handle = rte_fbk_hash_create(&params);
1091 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1092 
1093 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1094 	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1095 				"load factor right after creation is not zero but it should be");
1096 	/* Add keys. */
1097 	for (i = 0; i < 5; i++) {
1098 		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1099 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1100 	}
1101 
1102 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1103 	RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
1104 				"load factor now is not as expected");
1105 	/* Find value of added keys. */
1106 	for (i = 0; i < 5; i++) {
1107 		status = rte_fbk_hash_lookup(handle, keys[i]);
1108 		RETURN_IF_ERROR_FBK(status != vals[i],
1109 				"fbk hash lookup failed");
1110 	}
1111 
1112 	/* Change value of added keys. */
1113 	for (i = 0; i < 5; i++) {
1114 		status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
1115 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
1116 	}
1117 
1118 	/* Find new values. */
1119 	for (i = 0; i < 5; i++) {
1120 		status = rte_fbk_hash_lookup(handle, keys[i]);
1121 		RETURN_IF_ERROR_FBK(status != vals[4-i],
1122 				"fbk hash lookup failed");
1123 	}
1124 
1125 	/* Delete keys individually. */
1126 	for (i = 0; i < 5; i++) {
1127 		status = rte_fbk_hash_delete_key(handle, keys[i]);
1128 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
1129 	}
1130 
1131 	used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1132 	RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1133 				"load factor right after deletion is not zero but it should be");
1134 	/* Lookup should now fail. */
1135 	for (i = 0; i < 5; i++) {
1136 		status = rte_fbk_hash_lookup(handle, keys[i]);
1137 		RETURN_IF_ERROR_FBK(status == 0,
1138 				"fbk hash lookup should have failed");
1139 	}
1140 
1141 	/* Add keys again. */
1142 	for (i = 0; i < 5; i++) {
1143 		status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1144 		RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1145 	}
1146 
1147 	/* Make sure they were added. */
1148 	for (i = 0; i < 5; i++) {
1149 		status = rte_fbk_hash_lookup(handle, keys[i]);
1150 		RETURN_IF_ERROR_FBK(status != vals[i],
1151 				"fbk hash lookup failed");
1152 	}
1153 
1154 	/* Clear all entries. */
1155 	rte_fbk_hash_clear_all(handle);
1156 
1157 	/* Lookup should fail. */
1158 	for (i = 0; i < 5; i++) {
1159 		status = rte_fbk_hash_lookup(handle, keys[i]);
1160 		RETURN_IF_ERROR_FBK(status == 0,
1161 				"fbk hash lookup should have failed");
1162 	}
1163 
1164 	/* coverage */
1165 
1166 	/* fill up the hash_table */
1167 	for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
1168 		rte_fbk_hash_add_key(handle, i, (uint16_t) i);
1169 
1170 	/* Find non-existent key in a full hashtable */
1171 	status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1172 	RETURN_IF_ERROR_FBK(status != -ENOENT,
1173 			"fbk hash lookup succeeded");
1174 
1175 	/* Delete non-existent key in a full hashtable */
1176 	status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1177 	RETURN_IF_ERROR_FBK(status != -ENOENT,
1178 			"fbk hash delete succeeded");
1179 
1180 	/* Delete one key from a full hashtable */
1181 	status = rte_fbk_hash_delete_key(handle, 1);
1182 	RETURN_IF_ERROR_FBK(status != 0,
1183 			"fbk hash delete failed");
1184 
1185 	/* Clear all entries. */
1186 	rte_fbk_hash_clear_all(handle);
1187 
1188 	/* Cleanup. */
1189 	rte_fbk_hash_free(handle);
1190 
1191 	/* Cover the NULL case. */
1192 	rte_fbk_hash_free(0);
1193 
1194 	return 0;
1195 }
1196 
1197 /*
1198  * Sequence of operations for find existing fbk hash table
1199  *
1200  *  - create table
1201  *  - find existing table: hit
1202  *  - find non-existing table: miss
1203  *
1204  */
1205 static int test_fbk_hash_find_existing(void)
1206 {
1207 	struct rte_fbk_hash_params params = {
1208 			.name = "fbk_hash_find_existing",
1209 			.entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1210 			.entries_per_bucket = 4,
1211 			.socket_id = 0,
1212 	};
1213 	struct rte_fbk_hash_table *handle = NULL, *result = NULL;
1214 
1215 	/* Create hash table. */
1216 	handle = rte_fbk_hash_create(&params);
1217 	RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1218 
1219 	/* Try to find existing fbk hash table */
1220 	result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
1221 	RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
1222 
1223 	/* Try to find non-existing fbk hash table */
1224 	result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
1225 	RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
1226 
1227 	/* Cleanup. */
1228 	rte_fbk_hash_free(handle);
1229 
1230 	return 0;
1231 }
1232 
1233 #define BUCKET_ENTRIES 4
1234 /*
1235  * Do tests for hash creation with bad parameters.
1236  */
1237 static int test_hash_creation_with_bad_parameters(void)
1238 {
1239 	struct rte_hash *handle, *tmp;
1240 	struct rte_hash_parameters params;
1241 
1242 	handle = rte_hash_create(NULL);
1243 	if (handle != NULL) {
1244 		rte_hash_free(handle);
1245 		printf("Impossible creating hash successfully without any parameter\n");
1246 		return -1;
1247 	}
1248 
1249 	memcpy(&params, &ut_params, sizeof(params));
1250 	params.name = "creation_with_bad_parameters_0";
1251 	params.entries = RTE_HASH_ENTRIES_MAX + 1;
1252 	handle = rte_hash_create(&params);
1253 	if (handle != NULL) {
1254 		rte_hash_free(handle);
1255 		printf("Impossible creating hash successfully with entries in parameter exceeded\n");
1256 		return -1;
1257 	}
1258 
1259 	memcpy(&params, &ut_params, sizeof(params));
1260 	params.name = "creation_with_bad_parameters_2";
1261 	params.entries = BUCKET_ENTRIES - 1;
1262 	handle = rte_hash_create(&params);
1263 	if (handle != NULL) {
1264 		rte_hash_free(handle);
1265 		printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n");
1266 		return -1;
1267 	}
1268 
1269 	memcpy(&params, &ut_params, sizeof(params));
1270 	params.name = "creation_with_bad_parameters_3";
1271 	params.key_len = 0;
1272 	handle = rte_hash_create(&params);
1273 	if (handle != NULL) {
1274 		rte_hash_free(handle);
1275 		printf("Impossible creating hash successfully if key_len in parameter is zero\n");
1276 		return -1;
1277 	}
1278 
1279 	memcpy(&params, &ut_params, sizeof(params));
1280 	params.name = "creation_with_bad_parameters_4";
1281 	params.socket_id = RTE_MAX_NUMA_NODES + 1;
1282 	handle = rte_hash_create(&params);
1283 	if (handle != NULL) {
1284 		rte_hash_free(handle);
1285 		printf("Impossible creating hash successfully with invalid socket\n");
1286 		return -1;
1287 	}
1288 
1289 	/* test with same name should fail */
1290 	memcpy(&params, &ut_params, sizeof(params));
1291 	params.name = "same_name";
1292 	handle = rte_hash_create(&params);
1293 	if (handle == NULL) {
1294 		printf("Cannot create first hash table with 'same_name'\n");
1295 		return -1;
1296 	}
1297 	tmp = rte_hash_create(&params);
1298 	if (tmp != NULL) {
1299 		printf("Creation of hash table with same name should fail\n");
1300 		rte_hash_free(handle);
1301 		rte_hash_free(tmp);
1302 		return -1;
1303 	}
1304 	rte_hash_free(handle);
1305 
1306 	printf("# Test successful. No more errors expected\n");
1307 
1308 	return 0;
1309 }
1310 
1311 /*
1312  * Do tests for hash creation with parameters that look incorrect
1313  * but are actually valid.
1314  */
1315 static int
1316 test_hash_creation_with_good_parameters(void)
1317 {
1318 	struct rte_hash *handle;
1319 	struct rte_hash_parameters params;
1320 
1321 	/* create with null hash function - should choose DEFAULT_HASH_FUNC */
1322 	memcpy(&params, &ut_params, sizeof(params));
1323 	params.name = "name";
1324 	params.hash_func = NULL;
1325 	handle = rte_hash_create(&params);
1326 	if (handle == NULL) {
1327 		printf("Creating hash with null hash_func failed\n");
1328 		return -1;
1329 	}
1330 
1331 	rte_hash_free(handle);
1332 
1333 	return 0;
1334 }
1335 
1336 #define ITERATIONS 3
1337 /*
1338  * Test to see the average table utilization (entries added/max entries)
1339  * before hitting a random entry that cannot be added
1340  */
1341 static int test_average_table_utilization(uint32_t ext_table)
1342 {
1343 	struct rte_hash *handle;
1344 	uint8_t simple_key[MAX_KEYSIZE];
1345 	unsigned i, j;
1346 	unsigned added_keys, average_keys_added = 0;
1347 	int ret;
1348 	unsigned int cnt;
1349 
1350 	printf("\n# Running test to determine average utilization"
1351 	       "\n  before adding elements begins to fail\n");
1352 	if (ext_table)
1353 		printf("ext table is enabled\n");
1354 	else
1355 		printf("ext table is disabled\n");
1356 
1357 	printf("Measuring performance, please wait");
1358 	fflush(stdout);
1359 	ut_params.entries = 1 << 16;
1360 	ut_params.name = "test_average_utilization";
1361 	ut_params.hash_func = rte_jhash;
1362 	if (ext_table)
1363 		ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1364 	else
1365 		ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1366 
1367 	handle = rte_hash_create(&ut_params);
1368 
1369 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1370 
1371 	for (j = 0; j < ITERATIONS; j++) {
1372 		ret = 0;
1373 		/* Add random entries until key cannot be added */
1374 		for (added_keys = 0; ret >= 0; added_keys++) {
1375 			for (i = 0; i < ut_params.key_len; i++)
1376 				simple_key[i] = rte_rand() % 255;
1377 			ret = rte_hash_add_key(handle, simple_key);
1378 			if (ret < 0)
1379 				break;
1380 		}
1381 
1382 		if (ret != -ENOSPC) {
1383 			printf("Unexpected error when adding keys\n");
1384 			rte_hash_free(handle);
1385 			return -1;
1386 		}
1387 
1388 		cnt = rte_hash_count(handle);
1389 		if (cnt != added_keys) {
1390 			printf("rte_hash_count returned wrong value %u, %u,"
1391 					"%u\n", j, added_keys, cnt);
1392 			rte_hash_free(handle);
1393 			return -1;
1394 		}
1395 		if (ext_table) {
1396 			if (cnt != ut_params.entries) {
1397 				printf("rte_hash_count returned wrong value "
1398 					"%u, %u, %u\n", j, added_keys, cnt);
1399 				rte_hash_free(handle);
1400 				return -1;
1401 			}
1402 		}
1403 
1404 		average_keys_added += added_keys;
1405 
1406 		/* Reset the table */
1407 		rte_hash_reset(handle);
1408 
1409 		/* Print a dot to show progress on operations */
1410 		printf(".");
1411 		fflush(stdout);
1412 	}
1413 
1414 	average_keys_added /= ITERATIONS;
1415 
1416 	printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
1417 		((double) average_keys_added / ut_params.entries * 100),
1418 		average_keys_added, ut_params.entries);
1419 	rte_hash_free(handle);
1420 
1421 	return 0;
1422 }
1423 
1424 #define NUM_ENTRIES 256
1425 static int test_hash_iteration(uint32_t ext_table)
1426 {
1427 	struct rte_hash *handle;
1428 	unsigned i;
1429 	uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE];
1430 	const void *next_key;
1431 	void *next_data;
1432 	void *data[NUM_ENTRIES];
1433 	unsigned added_keys;
1434 	uint32_t iter = 0;
1435 	int ret = 0;
1436 
1437 	ut_params.entries = NUM_ENTRIES;
1438 	ut_params.name = "test_hash_iteration";
1439 	ut_params.hash_func = rte_jhash;
1440 	ut_params.key_len = 16;
1441 	if (ext_table)
1442 		ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1443 	else
1444 		ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1445 
1446 	handle = rte_hash_create(&ut_params);
1447 	RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1448 
1449 	/* Add random entries until key cannot be added */
1450 	for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
1451 		data[added_keys] = (void *) ((uintptr_t) rte_rand());
1452 		for (i = 0; i < ut_params.key_len; i++)
1453 			keys[added_keys][i] = rte_rand() % 255;
1454 		ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]);
1455 		if (ret < 0) {
1456 			if (ext_table) {
1457 				printf("Insertion failed for ext table\n");
1458 				goto err;
1459 			}
1460 			break;
1461 		}
1462 	}
1463 
1464 	/* Iterate through the hash table */
1465 	while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
1466 		/* Search for the key in the list of keys added */
1467 		for (i = 0; i < NUM_ENTRIES; i++) {
1468 			if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
1469 				if (next_data != data[i]) {
1470 					printf("Data found in the hash table is"
1471 					       "not the data added with the key\n");
1472 					goto err;
1473 				}
1474 				added_keys--;
1475 				break;
1476 			}
1477 		}
1478 		if (i == NUM_ENTRIES) {
1479 			printf("Key found in the hash table was not added\n");
1480 			goto err;
1481 		}
1482 	}
1483 
1484 	/* Check if all keys have been iterated */
1485 	if (added_keys != 0) {
1486 		printf("There were still %u keys to iterate\n", added_keys);
1487 		goto err;
1488 	}
1489 
1490 	rte_hash_free(handle);
1491 	return 0;
1492 
1493 err:
1494 	rte_hash_free(handle);
1495 	return -1;
1496 }
1497 
1498 static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
1499 			0x04, 0x05, 0x06, 0x07,
1500 			0x08, 0x09, 0x0a, 0x0b,
1501 			0x0c, 0x0d, 0x0e, 0x0f};
1502 static struct rte_hash_parameters hash_params_ex = {
1503 	.name = NULL,
1504 	.entries = 64,
1505 	.key_len = 0,
1506 	.hash_func = NULL,
1507 	.hash_func_init_val = 0,
1508 	.socket_id = 0,
1509 };
1510 
1511 /*
1512  * add/delete key with jhash2
1513  */
1514 static int
1515 test_hash_add_delete_jhash2(void)
1516 {
1517 	int ret = -1;
1518 	struct rte_hash *handle;
1519 	int32_t pos1, pos2;
1520 
1521 	hash_params_ex.name = "hash_test_jhash2";
1522 	hash_params_ex.key_len = 4;
1523 	hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b;
1524 
1525 	handle = rte_hash_create(&hash_params_ex);
1526 	if (handle == NULL) {
1527 		printf("test_hash_add_delete_jhash2 fail to create hash\n");
1528 		goto fail_jhash2;
1529 	}
1530 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1531 	if (pos1 < 0) {
1532 		printf("test_hash_add_delete_jhash2 fail to add hash key\n");
1533 		goto fail_jhash2;
1534 	}
1535 
1536 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1537 	if (pos2 < 0 || pos1 != pos2) {
1538 		printf("test_hash_add_delete_jhash2 delete different key from being added\n");
1539 		goto fail_jhash2;
1540 	}
1541 	ret = 0;
1542 
1543 fail_jhash2:
1544 	if (handle != NULL)
1545 		rte_hash_free(handle);
1546 
1547 	return ret;
1548 }
1549 
1550 /*
1551  * add/delete (2) key with jhash2
1552  */
1553 static int
1554 test_hash_add_delete_2_jhash2(void)
1555 {
1556 	int ret = -1;
1557 	struct rte_hash *handle;
1558 	int32_t pos1, pos2;
1559 
1560 	hash_params_ex.name = "hash_test_2_jhash2";
1561 	hash_params_ex.key_len = 8;
1562 	hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b;
1563 
1564 	handle = rte_hash_create(&hash_params_ex);
1565 	if (handle == NULL)
1566 		goto fail_2_jhash2;
1567 
1568 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1569 	if (pos1 < 0)
1570 		goto fail_2_jhash2;
1571 
1572 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1573 	if (pos2 < 0 || pos1 != pos2)
1574 		goto fail_2_jhash2;
1575 
1576 	ret = 0;
1577 
1578 fail_2_jhash2:
1579 	if (handle != NULL)
1580 		rte_hash_free(handle);
1581 
1582 	return ret;
1583 }
1584 
1585 static uint32_t
1586 test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
1587 {
1588 	const uint32_t *k = key;
1589 
1590 	RTE_SET_USED(length);
1591 
1592 	return rte_jhash_1word(k[0], initval);
1593 }
1594 
1595 static uint32_t
1596 test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
1597 {
1598 	const uint32_t *k = key;
1599 
1600 	RTE_SET_USED(length);
1601 
1602 	return rte_jhash_2words(k[0], k[1], initval);
1603 }
1604 
1605 static uint32_t
1606 test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
1607 {
1608 	const uint32_t *k = key;
1609 
1610 	RTE_SET_USED(length);
1611 
1612 	return rte_jhash_3words(k[0], k[1], k[2], initval);
1613 }
1614 
1615 /*
1616  * add/delete key with jhash 1word
1617  */
1618 static int
1619 test_hash_add_delete_jhash_1word(void)
1620 {
1621 	int ret = -1;
1622 	struct rte_hash *handle;
1623 	int32_t pos1, pos2;
1624 
1625 	hash_params_ex.name = "hash_test_jhash_1word";
1626 	hash_params_ex.key_len = 4;
1627 	hash_params_ex.hash_func = test_hash_jhash_1word;
1628 
1629 	handle = rte_hash_create(&hash_params_ex);
1630 	if (handle == NULL)
1631 		goto fail_jhash_1word;
1632 
1633 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1634 	if (pos1 < 0)
1635 		goto fail_jhash_1word;
1636 
1637 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1638 	if (pos2 < 0 || pos1 != pos2)
1639 		goto fail_jhash_1word;
1640 
1641 	ret = 0;
1642 
1643 fail_jhash_1word:
1644 	if (handle != NULL)
1645 		rte_hash_free(handle);
1646 
1647 	return ret;
1648 }
1649 
1650 /*
1651  * add/delete key with jhash 2word
1652  */
1653 static int
1654 test_hash_add_delete_jhash_2word(void)
1655 {
1656 	int ret = -1;
1657 	struct rte_hash *handle;
1658 	int32_t pos1, pos2;
1659 
1660 	hash_params_ex.name = "hash_test_jhash_2word";
1661 	hash_params_ex.key_len = 8;
1662 	hash_params_ex.hash_func = test_hash_jhash_2word;
1663 
1664 	handle = rte_hash_create(&hash_params_ex);
1665 	if (handle == NULL)
1666 		goto fail_jhash_2word;
1667 
1668 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1669 	if (pos1 < 0)
1670 		goto fail_jhash_2word;
1671 
1672 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1673 	if (pos2 < 0 || pos1 != pos2)
1674 		goto fail_jhash_2word;
1675 
1676 	ret = 0;
1677 
1678 fail_jhash_2word:
1679 	if (handle != NULL)
1680 		rte_hash_free(handle);
1681 
1682 	return ret;
1683 }
1684 
1685 /*
1686  * add/delete key with jhash 3word
1687  */
1688 static int
1689 test_hash_add_delete_jhash_3word(void)
1690 {
1691 	int ret = -1;
1692 	struct rte_hash *handle;
1693 	int32_t pos1, pos2;
1694 
1695 	hash_params_ex.name = "hash_test_jhash_3word";
1696 	hash_params_ex.key_len = 12;
1697 	hash_params_ex.hash_func = test_hash_jhash_3word;
1698 
1699 	handle = rte_hash_create(&hash_params_ex);
1700 	if (handle == NULL)
1701 		goto fail_jhash_3word;
1702 
1703 	pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1704 	if (pos1 < 0)
1705 		goto fail_jhash_3word;
1706 
1707 	pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1708 	if (pos2 < 0 || pos1 != pos2)
1709 		goto fail_jhash_3word;
1710 
1711 	ret = 0;
1712 
1713 fail_jhash_3word:
1714 	if (handle != NULL)
1715 		rte_hash_free(handle);
1716 
1717 	return ret;
1718 }
1719 
1720 /*
1721  * Do all unit and performance tests.
1722  */
1723 static int
1724 test_hash(void)
1725 {
1726 	if (test_add_delete() < 0)
1727 		return -1;
1728 	if (test_hash_add_delete_jhash2() < 0)
1729 		return -1;
1730 	if (test_hash_add_delete_2_jhash2() < 0)
1731 		return -1;
1732 	if (test_hash_add_delete_jhash_1word() < 0)
1733 		return -1;
1734 	if (test_hash_add_delete_jhash_2word() < 0)
1735 		return -1;
1736 	if (test_hash_add_delete_jhash_3word() < 0)
1737 		return -1;
1738 	if (test_hash_get_key_with_position() < 0)
1739 		return -1;
1740 	if (test_hash_find_existing() < 0)
1741 		return -1;
1742 	if (test_add_update_delete() < 0)
1743 		return -1;
1744 	if (test_add_update_delete_free() < 0)
1745 		return -1;
1746 	if (test_five_keys() < 0)
1747 		return -1;
1748 	if (test_full_bucket() < 0)
1749 		return -1;
1750 	if (test_extendable_bucket() < 0)
1751 		return -1;
1752 
1753 	if (test_fbk_hash_find_existing() < 0)
1754 		return -1;
1755 	if (fbk_hash_unit_test() < 0)
1756 		return -1;
1757 	if (test_hash_creation_with_bad_parameters() < 0)
1758 		return -1;
1759 	if (test_hash_creation_with_good_parameters() < 0)
1760 		return -1;
1761 
1762 	/* ext table disabled */
1763 	if (test_average_table_utilization(0) < 0)
1764 		return -1;
1765 	if (test_hash_iteration(0) < 0)
1766 		return -1;
1767 
1768 	/* ext table enabled */
1769 	if (test_average_table_utilization(1) < 0)
1770 		return -1;
1771 	if (test_hash_iteration(1) < 0)
1772 		return -1;
1773 
1774 	run_hash_func_tests();
1775 
1776 	if (test_crc32_hash_alg_equiv() < 0)
1777 		return -1;
1778 
1779 	return 0;
1780 }
1781 
1782 REGISTER_TEST_COMMAND(hash_autotest, test_hash);
1783