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