1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2015 Intel Corporation
11 #include <sys/queue.h>
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>
20 #include <rte_string_fns.h>
25 #include <rte_fbk_hash.h>
26 #include <rte_jhash.h>
27 #include <rte_hash_crc.h>
29 /*******************************************************************************
30 * Hash function performance test configuration section. Each performance test
31 * will be performed HASHTEST_ITERATIONS times.
33 * The five arrays below control what tests are performed. Every combination
34 * from the array entries is tested.
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)
44 * Check condition and return an error if true. Assumes that "handle" is the
45 * name of the hash structure pointer to be freed.
47 #define RETURN_IF_ERROR(cond, str, ...) do { \
49 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
50 if (handle) rte_hash_free(handle); \
55 #define RETURN_IF_ERROR_FBK(cond, str, ...) do { \
57 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
58 if (handle) rte_fbk_hash_free(handle); \
63 /* 5-tuple key type */
73 * Hash function that always returns the same value, to easily test what
74 * happens when a bucket is full.
76 static uint32_t pseudo_hash(__rte_unused const void *keys,
77 __rte_unused uint32_t key_len,
78 __rte_unused uint32_t init_val)
83 RTE_LOG_REGISTER(hash_logtype_test, test.hash, INFO);
86 * Print out result of unit test hash operation.
88 static void print_key_info(const char *msg, const struct flow_key *key,
91 const uint8_t *p = (const uint8_t *)key;
94 rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%s key:0x", msg);
95 for (i = 0; i < sizeof(struct flow_key); i++)
96 rte_log(RTE_LOG_DEBUG, hash_logtype_test, "%02X", p[i]);
97 rte_log(RTE_LOG_DEBUG, hash_logtype_test, " @ pos %d\n", pos);
100 /* Keys used by unit test functions */
101 static struct flow_key keys[5] = { {
102 .ip_src = RTE_IPV4(0x03, 0x02, 0x01, 0x00),
103 .ip_dst = RTE_IPV4(0x07, 0x06, 0x05, 0x04),
108 .ip_src = RTE_IPV4(0x13, 0x12, 0x11, 0x10),
109 .ip_dst = RTE_IPV4(0x17, 0x16, 0x15, 0x14),
114 .ip_src = RTE_IPV4(0x23, 0x22, 0x21, 0x20),
115 .ip_dst = RTE_IPV4(0x27, 0x26, 0x25, 0x24),
120 .ip_src = RTE_IPV4(0x33, 0x32, 0x31, 0x30),
121 .ip_dst = RTE_IPV4(0x37, 0x36, 0x35, 0x34),
126 .ip_src = RTE_IPV4(0x43, 0x42, 0x41, 0x40),
127 .ip_dst = RTE_IPV4(0x47, 0x46, 0x45, 0x44),
133 /* Parameters used for hash table in unit test functions. Name set later. */
134 static struct rte_hash_parameters ut_params = {
136 .key_len = sizeof(struct flow_key), /* 13 */
137 .hash_func = rte_jhash,
138 .hash_func_init_val = 0,
142 #define CRC32_ITERATIONS (1U << 10)
143 #define CRC32_DWORDS (1U << 6)
145 * Test if all CRC32 implementations yield the same hash value
148 test_crc32_hash_alg_equiv(void)
152 uint64_t data64[CRC32_DWORDS];
156 printf("\n# CRC32 implementations equivalence test\n");
157 for (i = 0; i < CRC32_ITERATIONS; i++) {
158 /* Randomizing data_len of data set */
159 data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
160 init_val = (uint32_t) rte_rand();
162 /* Fill the data set */
163 for (j = 0; j < CRC32_DWORDS; j++)
164 data64[j] = rte_rand();
166 /* Calculate software CRC32 */
167 rte_hash_crc_set_alg(CRC32_SW);
168 hash_val = rte_hash_crc(data64, data_len, init_val);
170 /* Check against 4-byte-operand sse4.2 CRC32 if available */
171 rte_hash_crc_set_alg(CRC32_SSE42);
172 if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
173 printf("Failed checking CRC32_SW against CRC32_SSE42\n");
177 /* Check against 8-byte-operand sse4.2 CRC32 if available */
178 rte_hash_crc_set_alg(CRC32_SSE42_x64);
179 if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
180 printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
184 /* Check against 8-byte-operand ARM64 CRC32 if available */
185 rte_hash_crc_set_alg(CRC32_ARM64);
186 if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
187 printf("Failed checking CRC32_SW against CRC32_ARM64\n");
192 /* Resetting to best available algorithm */
193 rte_hash_crc_set_alg(CRC32_SSE42_x64);
195 if (i == CRC32_ITERATIONS)
198 printf("Failed test data (hex, %zu bytes total):\n", data_len);
199 for (j = 0; j < data_len; j++)
200 printf("%02X%c", ((uint8_t *)data64)[j],
201 ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
207 * Test a hash function.
209 static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
212 static uint8_t key[MAX_KEYSIZE];
216 for (i = 0; i < key_len; i++)
217 key[i] = (uint8_t) rte_rand();
219 /* just to be on the safe side */
223 f(key, key_len, init_val);
227 * Test all hash functions.
229 static void run_hash_func_tests(void)
233 for (i = 0; i < RTE_DIM(hashtest_funcs); i++) {
234 for (j = 0; j < RTE_DIM(hashtest_initvals); j++) {
235 for (k = 0; k < RTE_DIM(hashtest_key_lens); k++) {
236 run_hash_func_test(hashtest_funcs[i],
237 hashtest_initvals[j],
238 hashtest_key_lens[k]);
245 * Basic sequence of operations for a single key:
251 * Repeat the test case when 'free on delete' is disabled.
258 static int test_add_delete(void)
260 struct rte_hash *handle;
261 /* test with standard add/lookup/delete functions */
262 int pos0, expectedPos0;
264 ut_params.name = "test1";
265 handle = rte_hash_create(&ut_params);
266 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
268 pos0 = rte_hash_add_key(handle, &keys[0]);
269 print_key_info("Add", &keys[0], pos0);
270 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
273 pos0 = rte_hash_lookup(handle, &keys[0]);
274 print_key_info("Lkp", &keys[0], pos0);
275 RETURN_IF_ERROR(pos0 != expectedPos0,
276 "failed to find key (pos0=%d)", pos0);
278 pos0 = rte_hash_del_key(handle, &keys[0]);
279 print_key_info("Del", &keys[0], pos0);
280 RETURN_IF_ERROR(pos0 != expectedPos0,
281 "failed to delete key (pos0=%d)", pos0);
283 pos0 = rte_hash_lookup(handle, &keys[0]);
284 print_key_info("Lkp", &keys[0], pos0);
285 RETURN_IF_ERROR(pos0 != -ENOENT,
286 "fail: found key after deleting! (pos0=%d)", pos0);
288 rte_hash_free(handle);
290 /* repeat test with precomputed hash functions */
291 hash_sig_t hash_value;
292 int pos1, expectedPos1, delPos1;
294 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
295 handle = rte_hash_create(&ut_params);
296 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
297 ut_params.extra_flag = 0;
299 hash_value = rte_hash_hash(handle, &keys[0]);
300 pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
301 print_key_info("Add", &keys[0], pos1);
302 RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
305 pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
306 print_key_info("Lkp", &keys[0], pos1);
307 RETURN_IF_ERROR(pos1 != expectedPos1,
308 "failed to find key (pos1=%d)", pos1);
310 pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
311 print_key_info("Del", &keys[0], pos1);
312 RETURN_IF_ERROR(pos1 != expectedPos1,
313 "failed to delete key (pos1=%d)", pos1);
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 != -ENOENT,
319 "fail: found key after deleting! (pos1=%d)", pos1);
321 pos1 = rte_hash_free_key_with_position(handle, delPos1);
322 print_key_info("Free", &keys[0], delPos1);
323 RETURN_IF_ERROR(pos1 != 0,
324 "failed to free key (pos1=%d)", delPos1);
326 rte_hash_free(handle);
332 * Sequence of operations for a single key:
337 * - lookup: hit (updated data)
342 static int test_add_update_delete(void)
344 struct rte_hash *handle;
345 int pos0, expectedPos0;
347 ut_params.name = "test2";
348 handle = rte_hash_create(&ut_params);
349 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
351 pos0 = rte_hash_del_key(handle, &keys[0]);
352 print_key_info("Del", &keys[0], pos0);
353 RETURN_IF_ERROR(pos0 != -ENOENT,
354 "fail: found non-existent key (pos0=%d)", pos0);
356 pos0 = rte_hash_add_key(handle, &keys[0]);
357 print_key_info("Add", &keys[0], pos0);
358 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
361 pos0 = rte_hash_lookup(handle, &keys[0]);
362 print_key_info("Lkp", &keys[0], pos0);
363 RETURN_IF_ERROR(pos0 != expectedPos0,
364 "failed to find key (pos0=%d)", pos0);
366 pos0 = rte_hash_add_key(handle, &keys[0]);
367 print_key_info("Add", &keys[0], pos0);
368 RETURN_IF_ERROR(pos0 != expectedPos0,
369 "failed to re-add key (pos0=%d)", pos0);
371 pos0 = rte_hash_lookup(handle, &keys[0]);
372 print_key_info("Lkp", &keys[0], pos0);
373 RETURN_IF_ERROR(pos0 != expectedPos0,
374 "failed to find key (pos0=%d)", pos0);
376 pos0 = rte_hash_del_key(handle, &keys[0]);
377 print_key_info("Del", &keys[0], pos0);
378 RETURN_IF_ERROR(pos0 != expectedPos0,
379 "failed to delete key (pos0=%d)", pos0);
381 pos0 = rte_hash_del_key(handle, &keys[0]);
382 print_key_info("Del", &keys[0], pos0);
383 RETURN_IF_ERROR(pos0 != -ENOENT,
384 "fail: deleted already deleted key (pos0=%d)", pos0);
386 pos0 = rte_hash_lookup(handle, &keys[0]);
387 print_key_info("Lkp", &keys[0], pos0);
388 RETURN_IF_ERROR(pos0 != -ENOENT,
389 "fail: found key after deleting! (pos0=%d)", pos0);
391 rte_hash_free(handle);
396 * Sequence of operations for a single key with 'disable free on del' set:
401 * - lookup: hit (updated data)
408 static int test_add_update_delete_free(void)
410 struct rte_hash *handle;
411 int pos0, expectedPos0, delPos0, result;
413 ut_params.name = "test2";
414 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
415 handle = rte_hash_create(&ut_params);
416 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
417 ut_params.extra_flag = 0;
419 pos0 = rte_hash_del_key(handle, &keys[0]);
420 print_key_info("Del", &keys[0], pos0);
421 RETURN_IF_ERROR(pos0 != -ENOENT,
422 "fail: found non-existent key (pos0=%d)", pos0);
424 pos0 = rte_hash_add_key(handle, &keys[0]);
425 print_key_info("Add", &keys[0], pos0);
426 RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
429 pos0 = rte_hash_lookup(handle, &keys[0]);
430 print_key_info("Lkp", &keys[0], pos0);
431 RETURN_IF_ERROR(pos0 != expectedPos0,
432 "failed to find key (pos0=%d)", pos0);
434 pos0 = rte_hash_add_key(handle, &keys[0]);
435 print_key_info("Add", &keys[0], pos0);
436 RETURN_IF_ERROR(pos0 != expectedPos0,
437 "failed to re-add key (pos0=%d)", pos0);
439 pos0 = rte_hash_lookup(handle, &keys[0]);
440 print_key_info("Lkp", &keys[0], pos0);
441 RETURN_IF_ERROR(pos0 != expectedPos0,
442 "failed to find key (pos0=%d)", pos0);
444 delPos0 = rte_hash_del_key(handle, &keys[0]);
445 print_key_info("Del", &keys[0], delPos0);
446 RETURN_IF_ERROR(delPos0 != expectedPos0,
447 "failed to delete key (pos0=%d)", delPos0);
449 pos0 = rte_hash_del_key(handle, &keys[0]);
450 print_key_info("Del", &keys[0], pos0);
451 RETURN_IF_ERROR(pos0 != -ENOENT,
452 "fail: deleted already deleted key (pos0=%d)", pos0);
454 pos0 = rte_hash_lookup(handle, &keys[0]);
455 print_key_info("Lkp", &keys[0], pos0);
456 RETURN_IF_ERROR(pos0 != -ENOENT,
457 "fail: found key after deleting! (pos0=%d)", pos0);
459 result = rte_hash_free_key_with_position(handle, delPos0);
460 print_key_info("Free", &keys[0], delPos0);
461 RETURN_IF_ERROR(result != 0,
462 "failed to free key (pos1=%d)", delPos0);
464 pos0 = rte_hash_lookup(handle, &keys[0]);
465 print_key_info("Lkp", &keys[0], pos0);
466 RETURN_IF_ERROR(pos0 != -ENOENT,
467 "fail: found key after deleting! (pos0=%d)", pos0);
469 rte_hash_free(handle);
474 * Sequence of operations for a single key with 'rw concurrency lock free' set:
478 * Repeat the test case when 'multi writer add' is enabled.
483 static int test_add_delete_free_lf(void)
485 /* Should match the #define LCORE_CACHE_SIZE value in rte_cuckoo_hash.h */
486 #define LCORE_CACHE_SIZE 64
487 struct rte_hash *handle;
488 hash_sig_t hash_value;
489 int pos, expectedPos, delPos;
493 extra_flag = ut_params.extra_flag;
494 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF;
495 handle = rte_hash_create(&ut_params);
496 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
497 ut_params.extra_flag = extra_flag;
500 * The number of iterations is at least the same as the number of slots
501 * rte_hash allocates internally. This is to reveal potential issues of
502 * not freeing keys successfully.
504 for (i = 0; i < ut_params.entries + 1; i++) {
505 hash_value = rte_hash_hash(handle, &keys[0]);
506 pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
507 print_key_info("Add", &keys[0], pos);
508 RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
511 pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
512 print_key_info("Del", &keys[0], pos);
513 RETURN_IF_ERROR(pos != expectedPos,
514 "failed to delete key (pos=%d)", pos);
517 pos = rte_hash_free_key_with_position(handle, delPos);
518 print_key_info("Free", &keys[0], delPos);
519 RETURN_IF_ERROR(pos != 0,
520 "failed to free key (pos=%d)", delPos);
523 rte_hash_free(handle);
525 extra_flag = ut_params.extra_flag;
526 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF |
527 RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD;
528 handle = rte_hash_create(&ut_params);
529 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
530 ut_params.extra_flag = extra_flag;
532 ip_src = keys[0].ip_src;
534 * The number of iterations is at least the same as the number of slots
535 * rte_hash allocates internally. This is to reveal potential issues of
536 * not freeing keys successfully.
538 for (i = 0; i < ut_params.entries + (RTE_MAX_LCORE - 1) *
539 (LCORE_CACHE_SIZE - 1) + 1; i++) {
541 hash_value = rte_hash_hash(handle, &keys[0]);
542 pos = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
543 print_key_info("Add", &keys[0], pos);
544 RETURN_IF_ERROR(pos < 0, "failed to add key (pos=%d)", pos);
547 pos = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
548 print_key_info("Del", &keys[0], pos);
549 RETURN_IF_ERROR(pos != expectedPos,
550 "failed to delete key (pos=%d)", pos);
553 pos = rte_hash_free_key_with_position(handle, delPos);
554 print_key_info("Free", &keys[0], delPos);
555 RETURN_IF_ERROR(pos != 0,
556 "failed to free key (pos=%d)", delPos);
558 keys[0].ip_src = ip_src;
560 rte_hash_free(handle);
566 * Sequence of operations for retrieving a key with its position
570 * - get the key with its position: hit
572 * - try to get the deleted key: miss
574 * Repeat the test case when 'free on delete' is disabled.
577 * - get the key with its position: hit
579 * - try to get the deleted key: hit
581 * - try to get the deleted key: miss
584 static int test_hash_get_key_with_position(void)
586 struct rte_hash *handle = NULL;
587 int pos, expectedPos, delPos, result;
590 ut_params.name = "hash_get_key_w_pos";
591 handle = rte_hash_create(&ut_params);
592 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
594 pos = rte_hash_add_key(handle, &keys[0]);
595 print_key_info("Add", &keys[0], pos);
596 RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
599 result = rte_hash_get_key_with_position(handle, pos, &key);
600 RETURN_IF_ERROR(result != 0, "error retrieving a key");
602 pos = rte_hash_del_key(handle, &keys[0]);
603 print_key_info("Del", &keys[0], pos);
604 RETURN_IF_ERROR(pos != expectedPos,
605 "failed to delete key (pos0=%d)", pos);
607 result = rte_hash_get_key_with_position(handle, pos, &key);
608 RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
610 rte_hash_free(handle);
612 ut_params.name = "hash_get_key_w_pos";
613 ut_params.extra_flag = RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL;
614 handle = rte_hash_create(&ut_params);
615 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
616 ut_params.extra_flag = 0;
618 pos = rte_hash_add_key(handle, &keys[0]);
619 print_key_info("Add", &keys[0], pos);
620 RETURN_IF_ERROR(pos < 0, "failed to add key (pos0=%d)", pos);
623 result = rte_hash_get_key_with_position(handle, pos, &key);
624 RETURN_IF_ERROR(result != 0, "error retrieving a key");
626 delPos = rte_hash_del_key(handle, &keys[0]);
627 print_key_info("Del", &keys[0], delPos);
628 RETURN_IF_ERROR(delPos != expectedPos,
629 "failed to delete key (pos0=%d)", delPos);
631 result = rte_hash_get_key_with_position(handle, delPos, &key);
632 RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
634 result = rte_hash_free_key_with_position(handle, delPos);
635 print_key_info("Free", &keys[0], delPos);
636 RETURN_IF_ERROR(result != 0,
637 "failed to free key (pos1=%d)", delPos);
639 result = rte_hash_get_key_with_position(handle, delPos, &key);
640 RETURN_IF_ERROR(result != -ENOENT, "non valid key retrieved");
642 rte_hash_free(handle);
647 * Sequence of operations for find existing hash table
650 * - find existing table: hit
651 * - find non-existing table: miss
654 static int test_hash_find_existing(void)
656 struct rte_hash *handle = NULL, *result = NULL;
658 /* Create hash table. */
659 ut_params.name = "hash_find_existing";
660 handle = rte_hash_create(&ut_params);
661 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
663 /* Try to find existing hash table */
664 result = rte_hash_find_existing("hash_find_existing");
665 RETURN_IF_ERROR(result != handle, "could not find existing hash table");
667 /* Try to find non-existing hash table */
668 result = rte_hash_find_existing("hash_find_non_existing");
669 RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
672 rte_hash_free(handle);
678 * Sequence of operations for 5 keys
681 * - add keys (update)
682 * - lookup keys: hit (updated data)
683 * - delete keys : hit
684 * - lookup keys: miss
686 static int test_five_keys(void)
688 struct rte_hash *handle;
689 const void *key_array[5] = {0};
695 ut_params.name = "test3";
696 handle = rte_hash_create(&ut_params);
697 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
700 for (i = 0; i < 5; i++) {
701 pos[i] = rte_hash_add_key(handle, &keys[i]);
702 print_key_info("Add", &keys[i], pos[i]);
703 RETURN_IF_ERROR(pos[i] < 0,
704 "failed to add key (pos[%u]=%d)", i, pos[i]);
705 expected_pos[i] = pos[i];
709 for(i = 0; i < 5; i++)
710 key_array[i] = &keys[i];
712 ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
714 for(i = 0; i < 5; i++) {
715 print_key_info("Lkp", key_array[i], pos[i]);
716 RETURN_IF_ERROR(pos[i] != expected_pos[i],
717 "failed to find key (pos[%u]=%d)", i, pos[i]);
721 for (i = 0; i < 5; i++) {
722 pos[i] = rte_hash_add_key(handle, &keys[i]);
723 print_key_info("Add", &keys[i], pos[i]);
724 RETURN_IF_ERROR(pos[i] != expected_pos[i],
725 "failed to add key (pos[%u]=%d)", i, pos[i]);
729 for (i = 0; i < 5; i++) {
730 pos[i] = rte_hash_lookup(handle, &keys[i]);
731 print_key_info("Lkp", &keys[i], pos[i]);
732 RETURN_IF_ERROR(pos[i] != expected_pos[i],
733 "failed to find key (pos[%u]=%d)", i, pos[i]);
737 for (i = 0; i < 5; i++) {
738 pos[i] = rte_hash_del_key(handle, &keys[i]);
739 print_key_info("Del", &keys[i], pos[i]);
740 RETURN_IF_ERROR(pos[i] != expected_pos[i],
741 "failed to delete key (pos[%u]=%d)", i, pos[i]);
745 for (i = 0; i < 5; i++) {
746 pos[i] = rte_hash_lookup(handle, &keys[i]);
747 print_key_info("Lkp", &keys[i], pos[i]);
748 RETURN_IF_ERROR(pos[i] != -ENOENT,
749 "found non-existent key (pos[%u]=%d)", i, pos[i]);
753 ret = rte_hash_lookup_bulk(handle, &key_array[0], 5, (int32_t *)pos);
755 for (i = 0; i < 5; i++) {
756 print_key_info("Lkp", key_array[i], pos[i]);
757 RETURN_IF_ERROR(pos[i] != -ENOENT,
758 "found not-existent key (pos[%u]=%d)", i, pos[i]);
761 rte_hash_free(handle);
767 * Add keys to the same bucket until bucket full.
768 * - add 5 keys to the same bucket (hash created with 4 keys per bucket):
769 * first 4 successful, 5th successful, pushing existing item in bucket
770 * - lookup the 5 keys: 5 hits
771 * - add the 5 keys again: 5 OK
772 * - lookup the 5 keys: 5 hits (updated data)
773 * - delete the 5 keys: 5 OK
774 * - lookup the 5 keys: 5 misses
776 static int test_full_bucket(void)
778 struct rte_hash_parameters params_pseudo_hash = {
781 .key_len = sizeof(struct flow_key), /* 13 */
782 .hash_func = pseudo_hash,
783 .hash_func_init_val = 0,
786 struct rte_hash *handle;
791 handle = rte_hash_create(¶ms_pseudo_hash);
792 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
795 for (i = 0; i < 4; i++) {
796 pos[i] = rte_hash_add_key(handle, &keys[i]);
797 print_key_info("Add", &keys[i], pos[i]);
798 RETURN_IF_ERROR(pos[i] < 0,
799 "failed to add key (pos[%u]=%d)", i, pos[i]);
800 expected_pos[i] = pos[i];
803 * This should work and will push one of the items
804 * in the bucket because it is full
806 pos[4] = rte_hash_add_key(handle, &keys[4]);
807 print_key_info("Add", &keys[4], pos[4]);
808 RETURN_IF_ERROR(pos[4] < 0,
809 "failed to add key (pos[4]=%d)", pos[4]);
810 expected_pos[4] = pos[4];
813 for (i = 0; i < 5; i++) {
814 pos[i] = rte_hash_lookup(handle, &keys[i]);
815 print_key_info("Lkp", &keys[i], pos[i]);
816 RETURN_IF_ERROR(pos[i] != expected_pos[i],
817 "failed to find key (pos[%u]=%d)", i, pos[i]);
821 for (i = 0; i < 5; i++) {
822 pos[i] = rte_hash_add_key(handle, &keys[i]);
823 print_key_info("Add", &keys[i], pos[i]);
824 RETURN_IF_ERROR(pos[i] != expected_pos[i],
825 "failed to add key (pos[%u]=%d)", i, pos[i]);
829 for (i = 0; i < 5; i++) {
830 pos[i] = rte_hash_lookup(handle, &keys[i]);
831 print_key_info("Lkp", &keys[i], pos[i]);
832 RETURN_IF_ERROR(pos[i] != expected_pos[i],
833 "failed to find key (pos[%u]=%d)", i, pos[i]);
836 /* Delete 1 key, check other keys are still found */
837 pos[1] = rte_hash_del_key(handle, &keys[1]);
838 print_key_info("Del", &keys[1], pos[1]);
839 RETURN_IF_ERROR(pos[1] != expected_pos[1],
840 "failed to delete key (pos[1]=%d)", pos[1]);
841 pos[3] = rte_hash_lookup(handle, &keys[3]);
842 print_key_info("Lkp", &keys[3], pos[3]);
843 RETURN_IF_ERROR(pos[3] != expected_pos[3],
844 "failed lookup after deleting key from same bucket "
845 "(pos[3]=%d)", pos[3]);
847 /* Go back to previous state */
848 pos[1] = rte_hash_add_key(handle, &keys[1]);
849 print_key_info("Add", &keys[1], pos[1]);
850 expected_pos[1] = pos[1];
851 RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
854 for (i = 0; i < 5; i++) {
855 pos[i] = rte_hash_del_key(handle, &keys[i]);
856 print_key_info("Del", &keys[i], pos[i]);
857 RETURN_IF_ERROR(pos[i] != expected_pos[i],
858 "failed to delete key (pos[%u]=%d)", i, pos[i]);
862 for (i = 0; i < 5; i++) {
863 pos[i] = rte_hash_lookup(handle, &keys[i]);
864 print_key_info("Lkp", &keys[i], pos[i]);
865 RETURN_IF_ERROR(pos[i] != -ENOENT,
866 "fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
869 rte_hash_free(handle);
871 /* Cover the NULL case. */
877 * Similar to the test above (full bucket test), but for extendable buckets.
879 static int test_extendable_bucket(void)
881 struct rte_hash_parameters params_pseudo_hash = {
884 .key_len = sizeof(struct flow_key), /* 13 */
885 .hash_func = pseudo_hash,
886 .hash_func_init_val = 0,
888 .extra_flag = RTE_HASH_EXTRA_FLAGS_EXT_TABLE
890 struct rte_hash *handle;
892 int expected_pos[64];
894 struct flow_key rand_keys[64];
896 for (i = 0; i < 64; i++) {
897 rand_keys[i].port_dst = i;
898 rand_keys[i].port_src = i+1;
901 handle = rte_hash_create(¶ms_pseudo_hash);
902 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
905 for (i = 0; i < 64; i++) {
906 pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
907 print_key_info("Add", &rand_keys[i], pos[i]);
908 RETURN_IF_ERROR(pos[i] < 0,
909 "failed to add key (pos[%u]=%d)", i, pos[i]);
910 expected_pos[i] = pos[i];
914 for (i = 0; i < 64; i++) {
915 pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
916 print_key_info("Lkp", &rand_keys[i], pos[i]);
917 RETURN_IF_ERROR(pos[i] != expected_pos[i],
918 "failed to find key (pos[%u]=%d)", i, pos[i]);
922 for (i = 0; i < 64; i++) {
923 pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
924 print_key_info("Add", &rand_keys[i], pos[i]);
925 RETURN_IF_ERROR(pos[i] != expected_pos[i],
926 "failed to add key (pos[%u]=%d)", i, pos[i]);
930 for (i = 0; i < 64; i++) {
931 pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
932 print_key_info("Lkp", &rand_keys[i], pos[i]);
933 RETURN_IF_ERROR(pos[i] != expected_pos[i],
934 "failed to find key (pos[%u]=%d)", i, pos[i]);
937 /* Delete 1 key, check other keys are still found */
938 pos[35] = rte_hash_del_key(handle, &rand_keys[35]);
939 print_key_info("Del", &rand_keys[35], pos[35]);
940 RETURN_IF_ERROR(pos[35] != expected_pos[35],
941 "failed to delete key (pos[1]=%d)", pos[35]);
942 pos[20] = rte_hash_lookup(handle, &rand_keys[20]);
943 print_key_info("Lkp", &rand_keys[20], pos[20]);
944 RETURN_IF_ERROR(pos[20] != expected_pos[20],
945 "failed lookup after deleting key from same bucket "
946 "(pos[20]=%d)", pos[20]);
948 /* Go back to previous state */
949 pos[35] = rte_hash_add_key(handle, &rand_keys[35]);
950 print_key_info("Add", &rand_keys[35], pos[35]);
951 expected_pos[35] = pos[35];
952 RETURN_IF_ERROR(pos[35] < 0, "failed to add key (pos[1]=%d)", pos[35]);
955 for (i = 0; i < 64; i++) {
956 pos[i] = rte_hash_del_key(handle, &rand_keys[i]);
957 print_key_info("Del", &rand_keys[i], pos[i]);
958 RETURN_IF_ERROR(pos[i] != expected_pos[i],
959 "failed to delete key (pos[%u]=%d)", i, pos[i]);
963 for (i = 0; i < 64; i++) {
964 pos[i] = rte_hash_lookup(handle, &rand_keys[i]);
965 print_key_info("Lkp", &rand_keys[i], pos[i]);
966 RETURN_IF_ERROR(pos[i] != -ENOENT,
967 "fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
971 for (i = 0; i < 64; i++) {
972 pos[i] = rte_hash_add_key(handle, &rand_keys[i]);
973 print_key_info("Add", &rand_keys[i], pos[i]);
974 RETURN_IF_ERROR(pos[i] < 0,
975 "failed to add key (pos[%u]=%d)", i, pos[i]);
976 expected_pos[i] = pos[i];
979 rte_hash_free(handle);
981 /* Cover the NULL case. */
986 /******************************************************************************/
988 fbk_hash_unit_test(void)
990 struct rte_fbk_hash_params params = {
991 .name = "fbk_hash_test",
992 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
993 .entries_per_bucket = 4,
997 struct rte_fbk_hash_params invalid_params_1 = {
999 .entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
1000 .entries_per_bucket = 4,
1004 struct rte_fbk_hash_params invalid_params_2 = {
1005 .name = "invalid_2",
1007 .entries_per_bucket = 3, /* Not power of 2 */
1011 struct rte_fbk_hash_params invalid_params_3 = {
1012 .name = "invalid_3",
1013 .entries = 0, /* Entries is 0 */
1014 .entries_per_bucket = 4,
1018 struct rte_fbk_hash_params invalid_params_4 = {
1019 .name = "invalid_4",
1020 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1021 .entries_per_bucket = 0, /* Entries per bucket is 0 */
1025 struct rte_fbk_hash_params invalid_params_5 = {
1026 .name = "invalid_5",
1028 .entries_per_bucket = 8, /* Entries per bucket > entries */
1032 struct rte_fbk_hash_params invalid_params_6 = {
1033 .name = "invalid_6",
1034 .entries = RTE_FBK_HASH_ENTRIES_MAX * 2, /* Entries > max allowed */
1035 .entries_per_bucket = 4,
1039 struct rte_fbk_hash_params invalid_params_7 = {
1040 .name = "invalid_7",
1041 .entries = RTE_FBK_HASH_ENTRIES_MAX,
1042 .entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2, /* Entries > max allowed */
1046 struct rte_fbk_hash_params invalid_params_8 = {
1047 .name = "invalid_7",
1048 .entries = RTE_FBK_HASH_ENTRIES_MAX,
1049 .entries_per_bucket = 4,
1050 .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
1053 /* try to create two hashes with identical names
1054 * in this case, trying to create a second one will not
1055 * fail but will simply return pointer to the existing
1056 * hash with that name. sort of like a "find hash by name" :-)
1058 struct rte_fbk_hash_params invalid_params_same_name_1 = {
1059 .name = "same_name", /* hash with identical name */
1061 .entries_per_bucket = 2,
1065 /* trying to create this hash should return a pointer to an existing hash */
1066 struct rte_fbk_hash_params invalid_params_same_name_2 = {
1067 .name = "same_name", /* hash with identical name */
1068 .entries = RTE_FBK_HASH_ENTRIES_MAX,
1069 .entries_per_bucket = 4,
1073 /* this is a sanity check for "same name" test
1074 * creating this hash will check if we are actually able to create
1075 * multiple hashes with different names (instead of having just one).
1077 struct rte_fbk_hash_params different_name = {
1078 .name = "different_name", /* different name */
1079 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1080 .entries_per_bucket = 4,
1084 struct rte_fbk_hash_params params_jhash = {
1086 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1087 .entries_per_bucket = 4,
1089 .hash_func = rte_jhash_1word, /* Tests for different hash_func */
1090 .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1093 struct rte_fbk_hash_params params_nohash = {
1094 .name = "valid nohash",
1095 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1096 .entries_per_bucket = 4,
1098 .hash_func = NULL, /* Tests for null hash_func */
1099 .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
1102 struct rte_fbk_hash_table *handle, *tmp;
1104 {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
1105 uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
1108 double used_entries;
1110 /* Try creating hashes with invalid parameters */
1111 printf("# Testing hash creation with invalid parameters "
1112 "- expect error msgs\n");
1113 handle = rte_fbk_hash_create(&invalid_params_1);
1114 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1116 handle = rte_fbk_hash_create(&invalid_params_2);
1117 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1119 handle = rte_fbk_hash_create(&invalid_params_3);
1120 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1122 handle = rte_fbk_hash_create(&invalid_params_4);
1123 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1125 handle = rte_fbk_hash_create(&invalid_params_5);
1126 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1128 handle = rte_fbk_hash_create(&invalid_params_6);
1129 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1131 handle = rte_fbk_hash_create(&invalid_params_7);
1132 RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
1134 if (rte_eal_has_hugepages()) {
1135 handle = rte_fbk_hash_create(&invalid_params_8);
1136 RETURN_IF_ERROR_FBK(handle != NULL,
1137 "fbk hash creation should have failed");
1140 handle = rte_fbk_hash_create(&invalid_params_same_name_1);
1141 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
1143 tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
1145 rte_fbk_hash_free(tmp);
1146 RETURN_IF_ERROR_FBK(tmp != NULL, "fbk hash creation should have failed");
1148 /* we are not freeing handle here because we need a hash list
1149 * to be not empty for the next test */
1151 /* create a hash in non-empty list - good for coverage */
1152 tmp = rte_fbk_hash_create(&different_name);
1153 RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
1155 /* free both hashes */
1156 rte_fbk_hash_free(handle);
1157 rte_fbk_hash_free(tmp);
1159 /* Create empty jhash hash. */
1160 handle = rte_fbk_hash_create(¶ms_jhash);
1161 RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
1164 rte_fbk_hash_free(handle);
1166 /* Create empty jhash hash. */
1167 handle = rte_fbk_hash_create(¶ms_nohash);
1168 RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
1171 rte_fbk_hash_free(handle);
1173 /* Create empty hash. */
1174 handle = rte_fbk_hash_create(¶ms);
1175 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1177 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1178 RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1179 "load factor right after creation is not zero but it should be");
1181 for (i = 0; i < 5; i++) {
1182 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1183 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1186 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1187 RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
1188 "load factor now is not as expected");
1189 /* Find value of added keys. */
1190 for (i = 0; i < 5; i++) {
1191 status = rte_fbk_hash_lookup(handle, keys[i]);
1192 RETURN_IF_ERROR_FBK(status != vals[i],
1193 "fbk hash lookup failed");
1196 /* Change value of added keys. */
1197 for (i = 0; i < 5; i++) {
1198 status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
1199 RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
1202 /* Find new values. */
1203 for (i = 0; i < 5; i++) {
1204 status = rte_fbk_hash_lookup(handle, keys[i]);
1205 RETURN_IF_ERROR_FBK(status != vals[4-i],
1206 "fbk hash lookup failed");
1209 /* Delete keys individually. */
1210 for (i = 0; i < 5; i++) {
1211 status = rte_fbk_hash_delete_key(handle, keys[i]);
1212 RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
1215 used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
1216 RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
1217 "load factor right after deletion is not zero but it should be");
1218 /* Lookup should now fail. */
1219 for (i = 0; i < 5; i++) {
1220 status = rte_fbk_hash_lookup(handle, keys[i]);
1221 RETURN_IF_ERROR_FBK(status == 0,
1222 "fbk hash lookup should have failed");
1225 /* Add keys again. */
1226 for (i = 0; i < 5; i++) {
1227 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
1228 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
1231 /* Make sure they were added. */
1232 for (i = 0; i < 5; i++) {
1233 status = rte_fbk_hash_lookup(handle, keys[i]);
1234 RETURN_IF_ERROR_FBK(status != vals[i],
1235 "fbk hash lookup failed");
1238 /* Clear all entries. */
1239 rte_fbk_hash_clear_all(handle);
1241 /* Lookup should fail. */
1242 for (i = 0; i < 5; i++) {
1243 status = rte_fbk_hash_lookup(handle, keys[i]);
1244 RETURN_IF_ERROR_FBK(status == 0,
1245 "fbk hash lookup should have failed");
1250 /* fill up the hash_table */
1251 for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
1252 rte_fbk_hash_add_key(handle, i, (uint16_t) i);
1254 /* Find non-existent key in a full hashtable */
1255 status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1256 RETURN_IF_ERROR_FBK(status != -ENOENT,
1257 "fbk hash lookup succeeded");
1259 /* Delete non-existent key in a full hashtable */
1260 status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
1261 RETURN_IF_ERROR_FBK(status != -ENOENT,
1262 "fbk hash delete succeeded");
1264 /* Delete one key from a full hashtable */
1265 status = rte_fbk_hash_delete_key(handle, 1);
1266 RETURN_IF_ERROR_FBK(status != 0,
1267 "fbk hash delete failed");
1269 /* Clear all entries. */
1270 rte_fbk_hash_clear_all(handle);
1273 rte_fbk_hash_free(handle);
1275 /* Cover the NULL case. */
1276 rte_fbk_hash_free(0);
1282 * Sequence of operations for find existing fbk hash table
1285 * - find existing table: hit
1286 * - find non-existing table: miss
1289 static int test_fbk_hash_find_existing(void)
1291 struct rte_fbk_hash_params params = {
1292 .name = "fbk_hash_find_existing",
1293 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
1294 .entries_per_bucket = 4,
1297 struct rte_fbk_hash_table *handle = NULL, *result = NULL;
1299 /* Create hash table. */
1300 handle = rte_fbk_hash_create(¶ms);
1301 RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
1303 /* Try to find existing fbk hash table */
1304 result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
1305 RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
1307 /* Try to find non-existing fbk hash table */
1308 result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
1309 RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
1312 rte_fbk_hash_free(handle);
1317 #define BUCKET_ENTRIES 4
1319 * Do tests for hash creation with bad parameters.
1321 static int test_hash_creation_with_bad_parameters(void)
1323 struct rte_hash *handle, *tmp;
1324 struct rte_hash_parameters params;
1326 handle = rte_hash_create(NULL);
1327 if (handle != NULL) {
1328 rte_hash_free(handle);
1329 printf("Impossible creating hash successfully without any parameter\n");
1333 memcpy(¶ms, &ut_params, sizeof(params));
1334 params.name = "creation_with_bad_parameters_0";
1335 params.entries = RTE_HASH_ENTRIES_MAX + 1;
1336 handle = rte_hash_create(¶ms);
1337 if (handle != NULL) {
1338 rte_hash_free(handle);
1339 printf("Impossible creating hash successfully with entries in parameter exceeded\n");
1343 memcpy(¶ms, &ut_params, sizeof(params));
1344 params.name = "creation_with_bad_parameters_2";
1345 params.entries = BUCKET_ENTRIES - 1;
1346 handle = rte_hash_create(¶ms);
1347 if (handle != NULL) {
1348 rte_hash_free(handle);
1349 printf("Impossible creating hash successfully if entries less than bucket_entries in parameter\n");
1353 memcpy(¶ms, &ut_params, sizeof(params));
1354 params.name = "creation_with_bad_parameters_3";
1356 handle = rte_hash_create(¶ms);
1357 if (handle != NULL) {
1358 rte_hash_free(handle);
1359 printf("Impossible creating hash successfully if key_len in parameter is zero\n");
1363 memcpy(¶ms, &ut_params, sizeof(params));
1364 params.name = "creation_with_bad_parameters_4";
1365 params.socket_id = RTE_MAX_NUMA_NODES + 1;
1366 handle = rte_hash_create(¶ms);
1367 if (handle != NULL) {
1368 rte_hash_free(handle);
1369 printf("Impossible creating hash successfully with invalid socket\n");
1373 /* test with same name should fail */
1374 memcpy(¶ms, &ut_params, sizeof(params));
1375 params.name = "same_name";
1376 handle = rte_hash_create(¶ms);
1377 if (handle == NULL) {
1378 printf("Cannot create first hash table with 'same_name'\n");
1381 tmp = rte_hash_create(¶ms);
1383 printf("Creation of hash table with same name should fail\n");
1384 rte_hash_free(handle);
1388 rte_hash_free(handle);
1390 printf("# Test successful. No more errors expected\n");
1396 * Do tests for hash creation with parameters that look incorrect
1397 * but are actually valid.
1400 test_hash_creation_with_good_parameters(void)
1402 struct rte_hash *handle;
1403 struct rte_hash_parameters params;
1405 /* create with null hash function - should choose DEFAULT_HASH_FUNC */
1406 memcpy(¶ms, &ut_params, sizeof(params));
1407 params.name = "name";
1408 params.hash_func = NULL;
1409 handle = rte_hash_create(¶ms);
1410 if (handle == NULL) {
1411 printf("Creating hash with null hash_func failed\n");
1415 rte_hash_free(handle);
1420 #define ITERATIONS 3
1422 * Test to see the average table utilization (entries added/max entries)
1423 * before hitting a random entry that cannot be added
1425 static int test_average_table_utilization(uint32_t ext_table)
1427 struct rte_hash *handle;
1428 uint8_t simple_key[MAX_KEYSIZE];
1430 unsigned added_keys, average_keys_added = 0;
1434 printf("\n# Running test to determine average utilization"
1435 "\n before adding elements begins to fail\n");
1437 printf("ext table is enabled\n");
1439 printf("ext table is disabled\n");
1441 printf("Measuring performance, please wait");
1443 ut_params.entries = 1 << 16;
1444 ut_params.name = "test_average_utilization";
1445 ut_params.hash_func = rte_jhash;
1447 ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1449 ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1451 handle = rte_hash_create(&ut_params);
1453 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1455 for (j = 0; j < ITERATIONS; j++) {
1457 /* Add random entries until key cannot be added */
1458 for (added_keys = 0; ret >= 0; added_keys++) {
1459 for (i = 0; i < ut_params.key_len; i++)
1460 simple_key[i] = rte_rand() % 255;
1461 ret = rte_hash_add_key(handle, simple_key);
1466 if (ret != -ENOSPC) {
1467 printf("Unexpected error when adding keys\n");
1468 rte_hash_free(handle);
1472 cnt = rte_hash_count(handle);
1473 if (cnt != added_keys) {
1474 printf("rte_hash_count returned wrong value %u, %u,"
1475 "%u\n", j, added_keys, cnt);
1476 rte_hash_free(handle);
1480 if (cnt != ut_params.entries) {
1481 printf("rte_hash_count returned wrong value "
1482 "%u, %u, %u\n", j, added_keys, cnt);
1483 rte_hash_free(handle);
1488 average_keys_added += added_keys;
1490 /* Reset the table */
1491 rte_hash_reset(handle);
1493 /* Print a dot to show progress on operations */
1498 average_keys_added /= ITERATIONS;
1500 printf("\nAverage table utilization = %.2f%% (%u/%u)\n",
1501 ((double) average_keys_added / ut_params.entries * 100),
1502 average_keys_added, ut_params.entries);
1503 rte_hash_free(handle);
1508 #define NUM_ENTRIES 256
1509 static int test_hash_iteration(uint32_t ext_table)
1511 struct rte_hash *handle;
1513 uint8_t keys[NUM_ENTRIES][MAX_KEYSIZE];
1514 const void *next_key;
1516 void *data[NUM_ENTRIES];
1517 unsigned added_keys;
1521 ut_params.entries = NUM_ENTRIES;
1522 ut_params.name = "test_hash_iteration";
1523 ut_params.hash_func = rte_jhash;
1524 ut_params.key_len = 16;
1526 ut_params.extra_flag |= RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1528 ut_params.extra_flag &= ~RTE_HASH_EXTRA_FLAGS_EXT_TABLE;
1530 handle = rte_hash_create(&ut_params);
1531 RETURN_IF_ERROR(handle == NULL, "hash creation failed");
1533 /* Add random entries until key cannot be added */
1534 for (added_keys = 0; added_keys < NUM_ENTRIES; added_keys++) {
1535 data[added_keys] = (void *) ((uintptr_t) rte_rand());
1536 for (i = 0; i < ut_params.key_len; i++)
1537 keys[added_keys][i] = rte_rand() % 255;
1538 ret = rte_hash_add_key_data(handle, keys[added_keys], data[added_keys]);
1541 printf("Insertion failed for ext table\n");
1548 /* Iterate through the hash table */
1549 while (rte_hash_iterate(handle, &next_key, &next_data, &iter) >= 0) {
1550 /* Search for the key in the list of keys added */
1551 for (i = 0; i < NUM_ENTRIES; i++) {
1552 if (memcmp(next_key, keys[i], ut_params.key_len) == 0) {
1553 if (next_data != data[i]) {
1554 printf("Data found in the hash table is"
1555 "not the data added with the key\n");
1562 if (i == NUM_ENTRIES) {
1563 printf("Key found in the hash table was not added\n");
1568 /* Check if all keys have been iterated */
1569 if (added_keys != 0) {
1570 printf("There were still %u keys to iterate\n", added_keys);
1574 rte_hash_free(handle);
1578 rte_hash_free(handle);
1582 static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
1583 0x04, 0x05, 0x06, 0x07,
1584 0x08, 0x09, 0x0a, 0x0b,
1585 0x0c, 0x0d, 0x0e, 0x0f};
1586 static struct rte_hash_parameters hash_params_ex = {
1591 .hash_func_init_val = 0,
1596 * add/delete key with jhash2
1599 test_hash_add_delete_jhash2(void)
1602 struct rte_hash *handle;
1605 hash_params_ex.name = "hash_test_jhash2";
1606 hash_params_ex.key_len = 4;
1607 hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b;
1609 handle = rte_hash_create(&hash_params_ex);
1610 if (handle == NULL) {
1611 printf("test_hash_add_delete_jhash2 fail to create hash\n");
1614 pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1616 printf("test_hash_add_delete_jhash2 fail to add hash key\n");
1620 pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1621 if (pos2 < 0 || pos1 != pos2) {
1622 printf("test_hash_add_delete_jhash2 delete different key from being added\n");
1629 rte_hash_free(handle);
1635 * add/delete (2) key with jhash2
1638 test_hash_add_delete_2_jhash2(void)
1641 struct rte_hash *handle;
1644 hash_params_ex.name = "hash_test_2_jhash2";
1645 hash_params_ex.key_len = 8;
1646 hash_params_ex.hash_func = (rte_hash_function)rte_jhash_32b;
1648 handle = rte_hash_create(&hash_params_ex);
1652 pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1656 pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1657 if (pos2 < 0 || pos1 != pos2)
1664 rte_hash_free(handle);
1670 test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
1672 const uint32_t *k = key;
1674 RTE_SET_USED(length);
1676 return rte_jhash_1word(k[0], initval);
1680 test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
1682 const uint32_t *k = key;
1684 RTE_SET_USED(length);
1686 return rte_jhash_2words(k[0], k[1], initval);
1690 test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
1692 const uint32_t *k = key;
1694 RTE_SET_USED(length);
1696 return rte_jhash_3words(k[0], k[1], k[2], initval);
1700 * add/delete key with jhash 1word
1703 test_hash_add_delete_jhash_1word(void)
1706 struct rte_hash *handle;
1709 hash_params_ex.name = "hash_test_jhash_1word";
1710 hash_params_ex.key_len = 4;
1711 hash_params_ex.hash_func = test_hash_jhash_1word;
1713 handle = rte_hash_create(&hash_params_ex);
1715 goto fail_jhash_1word;
1717 pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1719 goto fail_jhash_1word;
1721 pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1722 if (pos2 < 0 || pos1 != pos2)
1723 goto fail_jhash_1word;
1729 rte_hash_free(handle);
1735 * add/delete key with jhash 2word
1738 test_hash_add_delete_jhash_2word(void)
1741 struct rte_hash *handle;
1744 hash_params_ex.name = "hash_test_jhash_2word";
1745 hash_params_ex.key_len = 8;
1746 hash_params_ex.hash_func = test_hash_jhash_2word;
1748 handle = rte_hash_create(&hash_params_ex);
1750 goto fail_jhash_2word;
1752 pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1754 goto fail_jhash_2word;
1756 pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1757 if (pos2 < 0 || pos1 != pos2)
1758 goto fail_jhash_2word;
1764 rte_hash_free(handle);
1770 * add/delete key with jhash 3word
1773 test_hash_add_delete_jhash_3word(void)
1776 struct rte_hash *handle;
1779 hash_params_ex.name = "hash_test_jhash_3word";
1780 hash_params_ex.key_len = 12;
1781 hash_params_ex.hash_func = test_hash_jhash_3word;
1783 handle = rte_hash_create(&hash_params_ex);
1785 goto fail_jhash_3word;
1787 pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1789 goto fail_jhash_3word;
1791 pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1792 if (pos2 < 0 || pos1 != pos2)
1793 goto fail_jhash_3word;
1799 rte_hash_free(handle);
1805 * Do all unit and performance tests.
1810 if (test_add_delete() < 0)
1812 if (test_hash_add_delete_jhash2() < 0)
1814 if (test_hash_add_delete_2_jhash2() < 0)
1816 if (test_hash_add_delete_jhash_1word() < 0)
1818 if (test_hash_add_delete_jhash_2word() < 0)
1820 if (test_hash_add_delete_jhash_3word() < 0)
1822 if (test_hash_get_key_with_position() < 0)
1824 if (test_hash_find_existing() < 0)
1826 if (test_add_update_delete() < 0)
1828 if (test_add_update_delete_free() < 0)
1830 if (test_add_delete_free_lf() < 0)
1832 if (test_five_keys() < 0)
1834 if (test_full_bucket() < 0)
1836 if (test_extendable_bucket() < 0)
1839 if (test_fbk_hash_find_existing() < 0)
1841 if (fbk_hash_unit_test() < 0)
1843 if (test_hash_creation_with_bad_parameters() < 0)
1845 if (test_hash_creation_with_good_parameters() < 0)
1848 /* ext table disabled */
1849 if (test_average_table_utilization(0) < 0)
1851 if (test_hash_iteration(0) < 0)
1854 /* ext table enabled */
1855 if (test_average_table_utilization(1) < 0)
1857 if (test_hash_iteration(1) < 0)
1860 run_hash_func_tests();
1862 if (test_crc32_hash_alg_equiv() < 0)
1868 REGISTER_TEST_COMMAND(hash_autotest, test_hash);