c489b8b50fbbab0cc91fb8a8b80d37b29e48d492
[dpdk.git] / app / test / test_hash.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <stdio.h>
35 #include <stdint.h>
36 #include <string.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <errno.h>
40 #include <sys/queue.h>
41
42 #include <rte_common.h>
43 #include <rte_malloc.h>
44 #include <rte_cycles.h>
45 #include <rte_random.h>
46 #include <rte_memory.h>
47 #include <rte_memzone.h>
48 #include <rte_tailq.h>
49 #include <rte_eal.h>
50 #include <rte_ip.h>
51 #include <rte_string_fns.h>
52
53 #include "test.h"
54
55 #include <rte_hash.h>
56 #include <rte_fbk_hash.h>
57 #include <rte_jhash.h>
58 #include <rte_hash_crc.h>
59
60 /*******************************************************************************
61  * Hash function performance test configuration section. Each performance test
62  * will be performed HASHTEST_ITERATIONS times.
63  *
64  * The five arrays below control what tests are performed. Every combination
65  * from the array entries is tested.
66  */
67 static rte_hash_function hashtest_funcs[] = {rte_jhash, rte_hash_crc};
68 static uint32_t hashtest_initvals[] = {0};
69 static uint32_t hashtest_key_lens[] = {0, 2, 4, 5, 6, 7, 8, 10, 11, 15, 16, 21, 31, 32, 33, 63, 64};
70 /******************************************************************************/
71 #define LOCAL_FBK_HASH_ENTRIES_MAX (1 << 15)
72
73 /*
74  * Check condition and return an error if true. Assumes that "handle" is the
75  * name of the hash structure pointer to be freed.
76  */
77 #define RETURN_IF_ERROR(cond, str, ...) do {                            \
78         if (cond) {                                                     \
79                 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
80                 if (handle) rte_hash_free(handle);                      \
81                 return -1;                                              \
82         }                                                               \
83 } while(0)
84
85 #define RETURN_IF_ERROR_FBK(cond, str, ...) do {                                \
86         if (cond) {                                                     \
87                 printf("ERROR line %d: " str "\n", __LINE__, ##__VA_ARGS__); \
88                 if (handle) rte_fbk_hash_free(handle);                  \
89                 return -1;                                              \
90         }                                                               \
91 } while(0)
92
93 /* 5-tuple key type */
94 struct flow_key {
95         uint32_t ip_src;
96         uint32_t ip_dst;
97         uint16_t port_src;
98         uint16_t port_dst;
99         uint8_t proto;
100 } __attribute__((packed));
101
102 /*
103  * Hash function that always returns the same value, to easily test what
104  * happens when a bucket is full.
105  */
106 static uint32_t pseudo_hash(__attribute__((unused)) const void *keys,
107                             __attribute__((unused)) uint32_t key_len,
108                             __attribute__((unused)) uint32_t init_val)
109 {
110         return 3;
111 }
112
113 /*
114  * Print out result of unit test hash operation.
115  */
116 #if defined(UNIT_TEST_HASH_VERBOSE)
117 static void print_key_info(const char *msg, const struct flow_key *key,
118                                                                 int32_t pos)
119 {
120         uint8_t *p = (uint8_t *)key;
121         unsigned i;
122
123         printf("%s key:0x", msg);
124         for (i = 0; i < sizeof(struct flow_key); i++) {
125                 printf("%02X", p[i]);
126         }
127         printf(" @ pos %d\n", pos);
128 }
129 #else
130 static void print_key_info(__attribute__((unused)) const char *msg,
131                 __attribute__((unused)) const struct flow_key *key,
132                 __attribute__((unused)) int32_t pos)
133 {
134 }
135 #endif
136
137 /* Keys used by unit test functions */
138 static struct flow_key keys[5] = { {
139         .ip_src = IPv4(0x03, 0x02, 0x01, 0x00),
140         .ip_dst = IPv4(0x07, 0x06, 0x05, 0x04),
141         .port_src = 0x0908,
142         .port_dst = 0x0b0a,
143         .proto = 0x0c,
144 }, {
145         .ip_src = IPv4(0x13, 0x12, 0x11, 0x10),
146         .ip_dst = IPv4(0x17, 0x16, 0x15, 0x14),
147         .port_src = 0x1918,
148         .port_dst = 0x1b1a,
149         .proto = 0x1c,
150 }, {
151         .ip_src = IPv4(0x23, 0x22, 0x21, 0x20),
152         .ip_dst = IPv4(0x27, 0x26, 0x25, 0x24),
153         .port_src = 0x2928,
154         .port_dst = 0x2b2a,
155         .proto = 0x2c,
156 }, {
157         .ip_src = IPv4(0x33, 0x32, 0x31, 0x30),
158         .ip_dst = IPv4(0x37, 0x36, 0x35, 0x34),
159         .port_src = 0x3938,
160         .port_dst = 0x3b3a,
161         .proto = 0x3c,
162 }, {
163         .ip_src = IPv4(0x43, 0x42, 0x41, 0x40),
164         .ip_dst = IPv4(0x47, 0x46, 0x45, 0x44),
165         .port_src = 0x4948,
166         .port_dst = 0x4b4a,
167         .proto = 0x4c,
168 } };
169
170 /* Parameters used for hash table in unit test functions. Name set later. */
171 static struct rte_hash_parameters ut_params = {
172         .entries = 64,
173         .bucket_entries = 4,
174         .key_len = sizeof(struct flow_key), /* 13 */
175         .hash_func = rte_jhash,
176         .hash_func_init_val = 0,
177         .socket_id = 0,
178 };
179
180 #define CRC32_ITERATIONS (1U << 20)
181 #define CRC32_DWORDS (1U << 6)
182 /*
183  * Test if all CRC32 implementations yield the same hash value
184  */
185 static int
186 test_crc32_hash_alg_equiv(void)
187 {
188         uint32_t hash_val;
189         uint32_t init_val;
190         uint64_t data64[CRC32_DWORDS];
191         unsigned i, j;
192         size_t data_len;
193
194         printf("# CRC32 implementations equivalence test\n");
195         for (i = 0; i < CRC32_ITERATIONS; i++) {
196                 /* Randomizing data_len of data set */
197                 data_len = (size_t) ((rte_rand() % sizeof(data64)) + 1);
198                 init_val = (uint32_t) rte_rand();
199
200                 /* Fill the data set */
201                 for (j = 0; j < CRC32_DWORDS; j++)
202                         data64[j] = rte_rand();
203
204                 /* Calculate software CRC32 */
205                 rte_hash_crc_set_alg(CRC32_SW);
206                 hash_val = rte_hash_crc(data64, data_len, init_val);
207
208                 /* Check against 4-byte-operand sse4.2 CRC32 if available */
209                 rte_hash_crc_set_alg(CRC32_SSE42);
210                 if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
211                         printf("Failed checking CRC32_SW against CRC32_SSE42\n");
212                         break;
213                 }
214
215                 /* Check against 8-byte-operand sse4.2 CRC32 if available */
216                 rte_hash_crc_set_alg(CRC32_SSE42_x64);
217                 if (hash_val != rte_hash_crc(data64, data_len, init_val)) {
218                         printf("Failed checking CRC32_SW against CRC32_SSE42_x64\n");
219                         break;
220                 }
221         }
222
223         /* Resetting to best available algorithm */
224         rte_hash_crc_set_alg(CRC32_SSE42_x64);
225
226         if (i == CRC32_ITERATIONS)
227                 return 0;
228
229         printf("Failed test data (hex, %zu bytes total):\n", data_len);
230         for (j = 0; j < data_len; j++)
231                 printf("%02X%c", ((uint8_t *)data64)[j],
232                                 ((j+1) % 16 == 0 || j == data_len - 1) ? '\n' : ' ');
233
234         return -1;
235 }
236
237 /*
238  * Test a hash function.
239  */
240 static void run_hash_func_test(rte_hash_function f, uint32_t init_val,
241                 uint32_t key_len)
242 {
243         static uint8_t key[RTE_HASH_KEY_LENGTH_MAX];
244         unsigned i;
245
246
247         for (i = 0; i < key_len; i++)
248                 key[i] = (uint8_t) rte_rand();
249
250         /* just to be on the safe side */
251         if (!f)
252                 return;
253
254         f(key, key_len, init_val);
255 }
256
257 /*
258  * Test all hash functions.
259  */
260 static void run_hash_func_tests(void)
261 {
262         unsigned i, j, k;
263
264         for (i = 0;
265              i < sizeof(hashtest_funcs) / sizeof(rte_hash_function);
266              i++) {
267                 for (j = 0;
268                      j < sizeof(hashtest_initvals) / sizeof(uint32_t);
269                      j++) {
270                         for (k = 0;
271                              k < sizeof(hashtest_key_lens) / sizeof(uint32_t);
272                              k++) {
273                                 run_hash_func_test(hashtest_funcs[i],
274                                                 hashtest_initvals[j],
275                                                 hashtest_key_lens[k]);
276                         }
277                 }
278         }
279 }
280
281 /*
282  * Basic sequence of operations for a single key:
283  *      - add
284  *      - lookup (hit)
285  *      - delete
286  *      - lookup (miss)
287  */
288 static int test_add_delete(void)
289 {
290         struct rte_hash *handle;
291         /* test with standard add/lookup/delete functions */
292         int pos0, expectedPos0;
293
294         ut_params.name = "test1";
295         handle = rte_hash_create(&ut_params);
296         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
297
298         pos0 = rte_hash_add_key(handle, &keys[0]);
299         print_key_info("Add", &keys[0], pos0);
300         RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
301         expectedPos0 = pos0;
302
303         pos0 = rte_hash_lookup(handle, &keys[0]);
304         print_key_info("Lkp", &keys[0], pos0);
305         RETURN_IF_ERROR(pos0 != expectedPos0,
306                         "failed to find key (pos0=%d)", pos0);
307
308         pos0 = rte_hash_del_key(handle, &keys[0]);
309         print_key_info("Del", &keys[0], pos0);
310         RETURN_IF_ERROR(pos0 != expectedPos0,
311                         "failed to delete key (pos0=%d)", pos0);
312
313         pos0 = rte_hash_lookup(handle, &keys[0]);
314         print_key_info("Lkp", &keys[0], pos0);
315         RETURN_IF_ERROR(pos0 != -ENOENT,
316                         "fail: found key after deleting! (pos0=%d)", pos0);
317
318         rte_hash_free(handle);
319
320         /* repeat test with precomputed hash functions */
321         hash_sig_t hash_value;
322         int pos1, expectedPos1;
323
324         handle = rte_hash_create(&ut_params);
325         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
326
327         hash_value = rte_hash_hash(handle, &keys[0]);
328         pos1 = rte_hash_add_key_with_hash(handle, &keys[0], hash_value);
329         print_key_info("Add", &keys[0], pos1);
330         RETURN_IF_ERROR(pos1 < 0, "failed to add key (pos1=%d)", pos1);
331         expectedPos1 = pos1;
332
333         pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
334         print_key_info("Lkp", &keys[0], pos1);
335         RETURN_IF_ERROR(pos1 != expectedPos1,
336                         "failed to find key (pos1=%d)", pos1);
337
338         pos1 = rte_hash_del_key_with_hash(handle, &keys[0], hash_value);
339         print_key_info("Del", &keys[0], pos1);
340         RETURN_IF_ERROR(pos1 != expectedPos1,
341                         "failed to delete key (pos1=%d)", pos1);
342
343         pos1 = rte_hash_lookup_with_hash(handle, &keys[0], hash_value);
344         print_key_info("Lkp", &keys[0], pos1);
345         RETURN_IF_ERROR(pos1 != -ENOENT,
346                         "fail: found key after deleting! (pos1=%d)", pos1);
347
348         rte_hash_free(handle);
349
350         return 0;
351 }
352
353 /*
354  * Sequence of operations for a single key:
355  *      - delete: miss
356  *      - add
357  *      - lookup: hit
358  *      - add: update
359  *      - lookup: hit (updated data)
360  *      - delete: hit
361  *      - delete: miss
362  *      - lookup: miss
363  */
364 static int test_add_update_delete(void)
365 {
366         struct rte_hash *handle;
367         int pos0, expectedPos0;
368
369         ut_params.name = "test2";
370         handle = rte_hash_create(&ut_params);
371         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
372
373         pos0 = rte_hash_del_key(handle, &keys[0]);
374         print_key_info("Del", &keys[0], pos0);
375         RETURN_IF_ERROR(pos0 != -ENOENT,
376                         "fail: found non-existent key (pos0=%d)", pos0);
377
378         pos0 = rte_hash_add_key(handle, &keys[0]);
379         print_key_info("Add", &keys[0], pos0);
380         RETURN_IF_ERROR(pos0 < 0, "failed to add key (pos0=%d)", pos0);
381         expectedPos0 = pos0;
382
383         pos0 = rte_hash_lookup(handle, &keys[0]);
384         print_key_info("Lkp", &keys[0], pos0);
385         RETURN_IF_ERROR(pos0 != expectedPos0,
386                         "failed to find key (pos0=%d)", pos0);
387
388         pos0 = rte_hash_add_key(handle, &keys[0]);
389         print_key_info("Add", &keys[0], pos0);
390         RETURN_IF_ERROR(pos0 != expectedPos0,
391                         "failed to re-add key (pos0=%d)", pos0);
392
393         pos0 = rte_hash_lookup(handle, &keys[0]);
394         print_key_info("Lkp", &keys[0], pos0);
395         RETURN_IF_ERROR(pos0 != expectedPos0,
396                         "failed to find key (pos0=%d)", pos0);
397
398         pos0 = rte_hash_del_key(handle, &keys[0]);
399         print_key_info("Del", &keys[0], pos0);
400         RETURN_IF_ERROR(pos0 != expectedPos0,
401                         "failed to delete key (pos0=%d)", pos0);
402
403         pos0 = rte_hash_del_key(handle, &keys[0]);
404         print_key_info("Del", &keys[0], pos0);
405         RETURN_IF_ERROR(pos0 != -ENOENT,
406                         "fail: deleted already deleted key (pos0=%d)", pos0);
407
408         pos0 = rte_hash_lookup(handle, &keys[0]);
409         print_key_info("Lkp", &keys[0], pos0);
410         RETURN_IF_ERROR(pos0 != -ENOENT,
411                         "fail: found key after deleting! (pos0=%d)", pos0);
412
413         rte_hash_free(handle);
414         return 0;
415 }
416
417 /*
418  * Sequence of operations for find existing hash table
419  *
420  *  - create table
421  *  - find existing table: hit
422  *  - find non-existing table: miss
423  *
424  */
425 static int test_hash_find_existing(void)
426 {
427         struct rte_hash *handle = NULL, *result = NULL;
428
429         /* Create hash table. */
430         ut_params.name = "hash_find_existing";
431         handle = rte_hash_create(&ut_params);
432         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
433
434         /* Try to find existing hash table */
435         result = rte_hash_find_existing("hash_find_existing");
436         RETURN_IF_ERROR(result != handle, "could not find existing hash table");
437
438         /* Try to find non-existing hash table */
439         result = rte_hash_find_existing("hash_find_non_existing");
440         RETURN_IF_ERROR(!(result == NULL), "found table that shouldn't exist");
441
442         /* Cleanup. */
443         rte_hash_free(handle);
444
445         return 0;
446 }
447
448 /*
449  * Sequence of operations for 5 keys
450  *      - add keys
451  *      - lookup keys: hit
452  *      - add keys (update)
453  *      - lookup keys: hit (updated data)
454  *      - delete keys : hit
455  *      - lookup keys: miss
456  */
457 static int test_five_keys(void)
458 {
459         struct rte_hash *handle;
460         const void *key_array[5] = {0};
461         int pos[5];
462         int expected_pos[5];
463         unsigned i;
464         int ret;
465
466         ut_params.name = "test3";
467         handle = rte_hash_create(&ut_params);
468         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
469
470         /* Add */
471         for (i = 0; i < 5; i++) {
472                 pos[i] = rte_hash_add_key(handle, &keys[i]);
473                 print_key_info("Add", &keys[i], pos[i]);
474                 RETURN_IF_ERROR(pos[i] < 0,
475                                 "failed to add key (pos[%u]=%d)", i, pos[i]);
476                 expected_pos[i] = pos[i];
477         }
478
479         /* Lookup */
480         for(i = 0; i < 5; i++)
481                 key_array[i] = &keys[i];
482
483         ret = rte_hash_lookup_multi(handle, &key_array[0], 5, (int32_t *)pos);
484         if(ret == 0)
485                 for(i = 0; i < 5; i++) {
486                         print_key_info("Lkp", key_array[i], pos[i]);
487                         RETURN_IF_ERROR(pos[i] != expected_pos[i],
488                                         "failed to find key (pos[%u]=%d)", i, pos[i]);
489                 }
490
491         /* Add - update */
492         for (i = 0; i < 5; i++) {
493                 pos[i] = rte_hash_add_key(handle, &keys[i]);
494                 print_key_info("Add", &keys[i], pos[i]);
495                 RETURN_IF_ERROR(pos[i] != expected_pos[i],
496                                 "failed to add key (pos[%u]=%d)", i, pos[i]);
497         }
498
499         /* Lookup */
500         for (i = 0; i < 5; i++) {
501                 pos[i] = rte_hash_lookup(handle, &keys[i]);
502                 print_key_info("Lkp", &keys[i], pos[i]);
503                 RETURN_IF_ERROR(pos[i] != expected_pos[i],
504                                 "failed to find key (pos[%u]=%d)", i, pos[i]);
505         }
506
507         /* Delete */
508         for (i = 0; i < 5; i++) {
509                 pos[i] = rte_hash_del_key(handle, &keys[i]);
510                 print_key_info("Del", &keys[i], pos[i]);
511                 RETURN_IF_ERROR(pos[i] != expected_pos[i],
512                                 "failed to delete key (pos[%u]=%d)", i, pos[i]);
513         }
514
515         /* Lookup */
516         for (i = 0; i < 5; i++) {
517                 pos[i] = rte_hash_lookup(handle, &keys[i]);
518                 print_key_info("Lkp", &keys[i], pos[i]);
519                 RETURN_IF_ERROR(pos[i] != -ENOENT,
520                                 "failed to find key (pos[%u]=%d)", i, pos[i]);
521         }
522
523         rte_hash_free(handle);
524
525         return 0;
526 }
527
528 /*
529  * Add keys to the same bucket until bucket full.
530  *      - add 5 keys to the same bucket (hash created with 4 keys per bucket):
531  *        first 4 successful, 5th unsuccessful
532  *      - lookup the 5 keys: 4 hits, 1 miss
533  *      - add the 5 keys again: 4 OK, one error as bucket is full
534  *      - lookup the 5 keys: 4 hits (updated data), 1 miss
535  *      - delete the 5 keys: 5 OK (even if the 5th is not in the table)
536  *      - lookup the 5 keys: 5 misses
537  *      - add the 5th key: OK
538  *      - lookup the 5th key: hit
539  */
540 static int test_full_bucket(void)
541 {
542         struct rte_hash_parameters params_pseudo_hash = {
543                 .name = "test4",
544                 .entries = 64,
545                 .bucket_entries = 4,
546                 .key_len = sizeof(struct flow_key), /* 13 */
547                 .hash_func = pseudo_hash,
548                 .hash_func_init_val = 0,
549                 .socket_id = 0,
550         };
551         struct rte_hash *handle;
552         int pos[5];
553         int expected_pos[5];
554         unsigned i;
555
556         handle = rte_hash_create(&params_pseudo_hash);
557         RETURN_IF_ERROR(handle == NULL, "hash creation failed");
558
559         /* Fill bucket*/
560         for (i = 0; i < 4; i++) {
561                 pos[i] = rte_hash_add_key(handle, &keys[i]);
562                 print_key_info("Add", &keys[i], pos[i]);
563                 RETURN_IF_ERROR(pos[i] < 0,
564                         "failed to add key (pos[%u]=%d)", i, pos[i]);
565                 expected_pos[i] = pos[i];
566         }
567         /* This shouldn't work because the bucket is full */
568         pos[4] = rte_hash_add_key(handle, &keys[4]);
569         print_key_info("Add", &keys[4], pos[4]);
570         RETURN_IF_ERROR(pos[4] != -ENOSPC,
571                         "fail: added key to full bucket (pos[4]=%d)", pos[4]);
572
573         /* Lookup */
574         for (i = 0; i < 4; i++) {
575                 pos[i] = rte_hash_lookup(handle, &keys[i]);
576                 print_key_info("Lkp", &keys[i], pos[i]);
577                 RETURN_IF_ERROR(pos[i] != expected_pos[i],
578                         "failed to find key (pos[%u]=%d)", i, pos[i]);
579         }
580         pos[4] = rte_hash_lookup(handle, &keys[4]);
581         print_key_info("Lkp", &keys[4], pos[4]);
582         RETURN_IF_ERROR(pos[4] != -ENOENT,
583                         "fail: found non-existent key (pos[4]=%d)", pos[4]);
584
585         /* Add - update */
586         for (i = 0; i < 4; i++) {
587                 pos[i] = rte_hash_add_key(handle, &keys[i]);
588                 print_key_info("Add", &keys[i], pos[i]);
589                 RETURN_IF_ERROR(pos[i] != expected_pos[i],
590                         "failed to add key (pos[%u]=%d)", i, pos[i]);
591         }
592         pos[4] = rte_hash_add_key(handle, &keys[4]);
593         print_key_info("Add", &keys[4], pos[4]);
594         RETURN_IF_ERROR(pos[4] != -ENOSPC,
595                         "fail: added key to full bucket (pos[4]=%d)", pos[4]);
596
597         /* Lookup */
598         for (i = 0; i < 4; i++) {
599                 pos[i] = rte_hash_lookup(handle, &keys[i]);
600                 print_key_info("Lkp", &keys[i], pos[i]);
601                 RETURN_IF_ERROR(pos[i] != expected_pos[i],
602                         "failed to find key (pos[%u]=%d)", i, pos[i]);
603         }
604         pos[4] = rte_hash_lookup(handle, &keys[4]);
605         print_key_info("Lkp", &keys[4], pos[4]);
606         RETURN_IF_ERROR(pos[4] != -ENOENT,
607                         "fail: found non-existent key (pos[4]=%d)", pos[4]);
608
609         /* Delete 1 key, check other keys are still found */
610         pos[1] = rte_hash_del_key(handle, &keys[1]);
611         print_key_info("Del", &keys[1], pos[1]);
612         RETURN_IF_ERROR(pos[1] != expected_pos[1],
613                         "failed to delete key (pos[1]=%d)", pos[1]);
614         pos[3] = rte_hash_lookup(handle, &keys[3]);
615         print_key_info("Lkp", &keys[3], pos[3]);
616         RETURN_IF_ERROR(pos[3] != expected_pos[3],
617                         "failed lookup after deleting key from same bucket "
618                         "(pos[3]=%d)", pos[3]);
619
620         /* Go back to previous state */
621         pos[1] = rte_hash_add_key(handle, &keys[1]);
622         print_key_info("Add", &keys[1], pos[1]);
623         expected_pos[1] = pos[1];
624         RETURN_IF_ERROR(pos[1] < 0, "failed to add key (pos[1]=%d)", pos[1]);
625
626         /* Delete */
627         for (i = 0; i < 4; i++) {
628                 pos[i] = rte_hash_del_key(handle, &keys[i]);
629                 print_key_info("Del", &keys[i], pos[i]);
630                 RETURN_IF_ERROR(pos[i] != expected_pos[i],
631                         "failed to delete key (pos[%u]=%d)", i, pos[i]);
632         }
633         pos[4] = rte_hash_del_key(handle, &keys[4]);
634         print_key_info("Del", &keys[4], pos[4]);
635         RETURN_IF_ERROR(pos[4] != -ENOENT,
636                         "fail: deleted non-existent key (pos[4]=%d)", pos[4]);
637
638         /* Lookup */
639         for (i = 0; i < 4; i++) {
640                 pos[i] = rte_hash_lookup(handle, &keys[i]);
641                 print_key_info("Lkp", &keys[i], pos[i]);
642                 RETURN_IF_ERROR(pos[i] != -ENOENT,
643                         "fail: found non-existent key (pos[%u]=%d)", i, pos[i]);
644         }
645
646         /* Add and lookup the 5th key */
647         pos[4] = rte_hash_add_key(handle, &keys[4]);
648         print_key_info("Add", &keys[4], pos[4]);
649         RETURN_IF_ERROR(pos[4] < 0, "failed to add key (pos[4]=%d)", pos[4]);
650         expected_pos[4] = pos[4];
651         pos[4] = rte_hash_lookup(handle, &keys[4]);
652         print_key_info("Lkp", &keys[4], pos[4]);
653         RETURN_IF_ERROR(pos[4] != expected_pos[4],
654                         "failed to find key (pos[4]=%d)", pos[4]);
655
656         rte_hash_free(handle);
657
658         /* Cover the NULL case. */
659         rte_hash_free(0);
660         return 0;
661 }
662
663 /******************************************************************************/
664 static int
665 fbk_hash_unit_test(void)
666 {
667         struct rte_fbk_hash_params params = {
668                 .name = "fbk_hash_test",
669                 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
670                 .entries_per_bucket = 4,
671                 .socket_id = 0,
672         };
673
674         struct rte_fbk_hash_params invalid_params_1 = {
675                 .name = "invalid_1",
676                 .entries = LOCAL_FBK_HASH_ENTRIES_MAX + 1, /* Not power of 2 */
677                 .entries_per_bucket = 4,
678                 .socket_id = 0,
679         };
680
681         struct rte_fbk_hash_params invalid_params_2 = {
682                 .name = "invalid_2",
683                 .entries = 4,
684                 .entries_per_bucket = 3,         /* Not power of 2 */
685                 .socket_id = 0,
686         };
687
688         struct rte_fbk_hash_params invalid_params_3 = {
689                 .name = "invalid_3",
690                 .entries = 0,                    /* Entries is 0 */
691                 .entries_per_bucket = 4,
692                 .socket_id = 0,
693         };
694
695         struct rte_fbk_hash_params invalid_params_4 = {
696                 .name = "invalid_4",
697                 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
698                 .entries_per_bucket = 0,         /* Entries per bucket is 0 */
699                 .socket_id = 0,
700         };
701
702         struct rte_fbk_hash_params invalid_params_5 = {
703                 .name = "invalid_5",
704                 .entries = 4,
705                 .entries_per_bucket = 8,         /* Entries per bucket > entries */
706                 .socket_id = 0,
707         };
708
709         struct rte_fbk_hash_params invalid_params_6 = {
710                 .name = "invalid_6",
711                 .entries = RTE_FBK_HASH_ENTRIES_MAX * 2,   /* Entries > max allowed */
712                 .entries_per_bucket = 4,
713                 .socket_id = 0,
714         };
715
716         struct rte_fbk_hash_params invalid_params_7 = {
717                 .name = "invalid_7",
718                 .entries = RTE_FBK_HASH_ENTRIES_MAX,
719                 .entries_per_bucket = RTE_FBK_HASH_ENTRIES_PER_BUCKET_MAX * 2,  /* Entries > max allowed */
720                 .socket_id = 0,
721         };
722
723         struct rte_fbk_hash_params invalid_params_8 = {
724                 .name = "invalid_7",
725                 .entries = RTE_FBK_HASH_ENTRIES_MAX,
726                 .entries_per_bucket = 4,
727                 .socket_id = RTE_MAX_NUMA_NODES + 1, /* invalid socket */
728         };
729
730         /* try to create two hashes with identical names
731          * in this case, trying to create a second one will not
732          * fail but will simply return pointer to the existing
733          * hash with that name. sort of like a "find hash by name" :-)
734          */
735         struct rte_fbk_hash_params invalid_params_same_name_1 = {
736                 .name = "same_name",                            /* hash with identical name */
737                 .entries = 4,
738                 .entries_per_bucket = 2,
739                 .socket_id = 0,
740         };
741
742         /* trying to create this hash should return a pointer to an existing hash */
743         struct rte_fbk_hash_params invalid_params_same_name_2 = {
744                 .name = "same_name",                            /* hash with identical name */
745                 .entries = RTE_FBK_HASH_ENTRIES_MAX,
746                 .entries_per_bucket = 4,
747                 .socket_id = 0,
748         };
749
750         /* this is a sanity check for "same name" test
751          * creating this hash will check if we are actually able to create
752          * multiple hashes with different names (instead of having just one).
753          */
754         struct rte_fbk_hash_params different_name = {
755                 .name = "different_name",                       /* different name */
756                 .entries = RTE_FBK_HASH_ENTRIES_MAX,
757                 .entries_per_bucket = 4,
758                 .socket_id = 0,
759         };
760
761         struct rte_fbk_hash_params params_jhash = {
762                 .name = "valid",
763                 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
764                 .entries_per_bucket = 4,
765                 .socket_id = 0,
766                 .hash_func = rte_jhash_1word,              /* Tests for different hash_func */
767                 .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
768         };
769
770         struct rte_fbk_hash_params params_nohash = {
771                 .name = "valid nohash",
772                 .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
773                 .entries_per_bucket = 4,
774                 .socket_id = 0,
775                 .hash_func = NULL,                            /* Tests for null hash_func */
776                 .init_val = RTE_FBK_HASH_INIT_VAL_DEFAULT,
777         };
778
779         struct rte_fbk_hash_table *handle, *tmp;
780         uint32_t keys[5] =
781                 {0xc6e18639, 0xe67c201c, 0xd4c8cffd, 0x44728691, 0xd5430fa9};
782         uint16_t vals[5] = {28108, 5699, 38490, 2166, 61571};
783         int status;
784         unsigned i;
785         double used_entries;
786
787         /* Try creating hashes with invalid parameters */
788         printf("# Testing hash creation with invalid parameters "
789                         "- expert error msgs\n");
790         handle = rte_fbk_hash_create(&invalid_params_1);
791         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
792
793         handle = rte_fbk_hash_create(&invalid_params_2);
794         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
795
796         handle = rte_fbk_hash_create(&invalid_params_3);
797         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
798
799         handle = rte_fbk_hash_create(&invalid_params_4);
800         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
801
802         handle = rte_fbk_hash_create(&invalid_params_5);
803         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
804
805         handle = rte_fbk_hash_create(&invalid_params_6);
806         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
807
808         handle = rte_fbk_hash_create(&invalid_params_7);
809         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
810
811         handle = rte_fbk_hash_create(&invalid_params_8);
812         RETURN_IF_ERROR_FBK(handle != NULL, "fbk hash creation should have failed");
813
814         handle = rte_fbk_hash_create(&invalid_params_same_name_1);
815         RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation should have succeeded");
816
817         tmp = rte_fbk_hash_create(&invalid_params_same_name_2);
818         RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
819         if (tmp != handle) {
820                         printf("ERROR line %d: hashes should have been the same\n", __LINE__);
821                         rte_fbk_hash_free(handle);
822                         rte_fbk_hash_free(tmp);
823                         return -1;
824         }
825
826         /* we are not freeing tmp or handle here because we need a hash list
827          * to be not empty for the next test */
828
829         /* create a hash in non-empty list - good for coverage */
830         tmp = rte_fbk_hash_create(&different_name);
831         RETURN_IF_ERROR_FBK(tmp == NULL, "fbk hash creation should have succeeded");
832
833         /* free both hashes */
834         rte_fbk_hash_free(handle);
835         rte_fbk_hash_free(tmp);
836
837         /* Create empty jhash hash. */
838         handle = rte_fbk_hash_create(&params_jhash);
839         RETURN_IF_ERROR_FBK(handle == NULL, "fbk jhash hash creation failed");
840
841         /* Cleanup. */
842         rte_fbk_hash_free(handle);
843
844         /* Create empty jhash hash. */
845         handle = rte_fbk_hash_create(&params_nohash);
846         RETURN_IF_ERROR_FBK(handle == NULL, "fbk nohash hash creation failed");
847
848         /* Cleanup. */
849         rte_fbk_hash_free(handle);
850
851         /* Create empty hash. */
852         handle = rte_fbk_hash_create(&params);
853         RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
854
855         used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
856         RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
857                                 "load factor right after creation is not zero but it should be");
858         /* Add keys. */
859         for (i = 0; i < 5; i++) {
860                 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
861                 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
862         }
863
864         used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
865         RETURN_IF_ERROR_FBK((unsigned)used_entries != (unsigned)((((double)5)/LOCAL_FBK_HASH_ENTRIES_MAX)*LOCAL_FBK_HASH_ENTRIES_MAX), \
866                                 "load factor now is not as expected");
867         /* Find value of added keys. */
868         for (i = 0; i < 5; i++) {
869                 status = rte_fbk_hash_lookup(handle, keys[i]);
870                 RETURN_IF_ERROR_FBK(status != vals[i],
871                                 "fbk hash lookup failed");
872         }
873
874         /* Change value of added keys. */
875         for (i = 0; i < 5; i++) {
876                 status = rte_fbk_hash_add_key(handle, keys[i], vals[4 - i]);
877                 RETURN_IF_ERROR_FBK(status != 0, "fbk hash update failed");
878         }
879
880         /* Find new values. */
881         for (i = 0; i < 5; i++) {
882                 status = rte_fbk_hash_lookup(handle, keys[i]);
883                 RETURN_IF_ERROR_FBK(status != vals[4-i],
884                                 "fbk hash lookup failed");
885         }
886
887         /* Delete keys individually. */
888         for (i = 0; i < 5; i++) {
889                 status = rte_fbk_hash_delete_key(handle, keys[i]);
890                 RETURN_IF_ERROR_FBK(status != 0, "fbk hash delete failed");
891         }
892
893         used_entries = rte_fbk_hash_get_load_factor(handle) * LOCAL_FBK_HASH_ENTRIES_MAX;
894         RETURN_IF_ERROR_FBK((unsigned)used_entries != 0, \
895                                 "load factor right after deletion is not zero but it should be");
896         /* Lookup should now fail. */
897         for (i = 0; i < 5; i++) {
898                 status = rte_fbk_hash_lookup(handle, keys[i]);
899                 RETURN_IF_ERROR_FBK(status == 0,
900                                 "fbk hash lookup should have failed");
901         }
902
903         /* Add keys again. */
904         for (i = 0; i < 5; i++) {
905                 status = rte_fbk_hash_add_key(handle, keys[i], vals[i]);
906                 RETURN_IF_ERROR_FBK(status != 0, "fbk hash add failed");
907         }
908
909         /* Make sure they were added. */
910         for (i = 0; i < 5; i++) {
911                 status = rte_fbk_hash_lookup(handle, keys[i]);
912                 RETURN_IF_ERROR_FBK(status != vals[i],
913                                 "fbk hash lookup failed");
914         }
915
916         /* Clear all entries. */
917         rte_fbk_hash_clear_all(handle);
918
919         /* Lookup should fail. */
920         for (i = 0; i < 5; i++) {
921                 status = rte_fbk_hash_lookup(handle, keys[i]);
922                 RETURN_IF_ERROR_FBK(status == 0,
923                                 "fbk hash lookup should have failed");
924         }
925
926         /* coverage */
927
928         /* fill up the hash_table */
929         for (i = 0; i < RTE_FBK_HASH_ENTRIES_MAX + 1; i++)
930                 rte_fbk_hash_add_key(handle, i, (uint16_t) i);
931
932         /* Find non-existent key in a full hashtable */
933         status = rte_fbk_hash_lookup(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
934         RETURN_IF_ERROR_FBK(status != -ENOENT,
935                         "fbk hash lookup succeeded");
936
937         /* Delete non-existent key in a full hashtable */
938         status = rte_fbk_hash_delete_key(handle, RTE_FBK_HASH_ENTRIES_MAX + 1);
939         RETURN_IF_ERROR_FBK(status != -ENOENT,
940                         "fbk hash delete succeeded");
941
942         /* Delete one key from a full hashtable */
943         status = rte_fbk_hash_delete_key(handle, 1);
944         RETURN_IF_ERROR_FBK(status != 0,
945                         "fbk hash delete failed");
946
947         /* Clear all entries. */
948         rte_fbk_hash_clear_all(handle);
949
950         /* Cleanup. */
951         rte_fbk_hash_free(handle);
952
953         /* Cover the NULL case. */
954         rte_fbk_hash_free(0);
955
956         return 0;
957 }
958
959 /*
960  * Sequence of operations for find existing fbk hash table
961  *
962  *  - create table
963  *  - find existing table: hit
964  *  - find non-existing table: miss
965  *
966  */
967 static int test_fbk_hash_find_existing(void)
968 {
969         struct rte_fbk_hash_params params = {
970                         .name = "fbk_hash_find_existing",
971                         .entries = LOCAL_FBK_HASH_ENTRIES_MAX,
972                         .entries_per_bucket = 4,
973                         .socket_id = 0,
974         };
975         struct rte_fbk_hash_table *handle = NULL, *result = NULL;
976
977         /* Create hash table. */
978         handle = rte_fbk_hash_create(&params);
979         RETURN_IF_ERROR_FBK(handle == NULL, "fbk hash creation failed");
980
981         /* Try to find existing fbk hash table */
982         result = rte_fbk_hash_find_existing("fbk_hash_find_existing");
983         RETURN_IF_ERROR_FBK(result != handle, "could not find existing fbk hash table");
984
985         /* Try to find non-existing fbk hash table */
986         result = rte_fbk_hash_find_existing("fbk_hash_find_non_existing");
987         RETURN_IF_ERROR_FBK(!(result == NULL), "found fbk table that shouldn't exist");
988
989         /* Cleanup. */
990         rte_fbk_hash_free(handle);
991
992         return 0;
993 }
994
995 /*
996  * Do tests for hash creation with bad parameters.
997  */
998 static int test_hash_creation_with_bad_parameters(void)
999 {
1000         struct rte_hash *handle;
1001         struct rte_hash_parameters params;
1002
1003         handle = rte_hash_create(NULL);
1004         if (handle != NULL) {
1005                 rte_hash_free(handle);
1006                 printf("Impossible creating hash sucessfully without any parameter\n");
1007                 return -1;
1008         }
1009
1010         memcpy(&params, &ut_params, sizeof(params));
1011         params.name = "creation_with_bad_parameters_0";
1012         params.entries = RTE_HASH_ENTRIES_MAX + 1;
1013         handle = rte_hash_create(&params);
1014         if (handle != NULL) {
1015                 rte_hash_free(handle);
1016                 printf("Impossible creating hash sucessfully with entries in parameter exceeded\n");
1017                 return -1;
1018         }
1019
1020         memcpy(&params, &ut_params, sizeof(params));
1021         params.name = "creation_with_bad_parameters_1";
1022         params.bucket_entries = RTE_HASH_BUCKET_ENTRIES_MAX + 1;
1023         handle = rte_hash_create(&params);
1024         if (handle != NULL) {
1025                 rte_hash_free(handle);
1026                 printf("Impossible creating hash sucessfully with bucket_entries in parameter exceeded\n");
1027                 return -1;
1028         }
1029
1030         memcpy(&params, &ut_params, sizeof(params));
1031         params.name = "creation_with_bad_parameters_2";
1032         params.entries = params.bucket_entries - 1;
1033         handle = rte_hash_create(&params);
1034         if (handle != NULL) {
1035                 rte_hash_free(handle);
1036                 printf("Impossible creating hash sucessfully if entries less than bucket_entries in parameter\n");
1037                 return -1;
1038         }
1039
1040         memcpy(&params, &ut_params, sizeof(params));
1041         params.name = "creation_with_bad_parameters_3";
1042         params.entries = params.entries - 1;
1043         handle = rte_hash_create(&params);
1044         if (handle != NULL) {
1045                 rte_hash_free(handle);
1046                 printf("Impossible creating hash sucessfully if entries in parameter is not power of 2\n");
1047                 return -1;
1048         }
1049
1050         memcpy(&params, &ut_params, sizeof(params));
1051         params.name = "creation_with_bad_parameters_4";
1052         params.bucket_entries = params.bucket_entries - 1;
1053         handle = rte_hash_create(&params);
1054         if (handle != NULL) {
1055                 rte_hash_free(handle);
1056                 printf("Impossible creating hash sucessfully if bucket_entries in parameter is not power of 2\n");
1057                 return -1;
1058         }
1059
1060         memcpy(&params, &ut_params, sizeof(params));
1061         params.name = "creation_with_bad_parameters_5";
1062         params.key_len = 0;
1063         handle = rte_hash_create(&params);
1064         if (handle != NULL) {
1065                 rte_hash_free(handle);
1066                 printf("Impossible creating hash sucessfully if key_len in parameter is zero\n");
1067                 return -1;
1068         }
1069
1070         memcpy(&params, &ut_params, sizeof(params));
1071         params.name = "creation_with_bad_parameters_6";
1072         params.key_len = RTE_HASH_KEY_LENGTH_MAX + 1;
1073         handle = rte_hash_create(&params);
1074         if (handle != NULL) {
1075                 rte_hash_free(handle);
1076                 printf("Impossible creating hash sucessfully if key_len is greater than the maximum\n");
1077                 return -1;
1078         }
1079
1080         memcpy(&params, &ut_params, sizeof(params));
1081         params.name = "creation_with_bad_parameters_7";
1082         params.socket_id = RTE_MAX_NUMA_NODES + 1;
1083         handle = rte_hash_create(&params);
1084         if (handle != NULL) {
1085                 rte_hash_free(handle);
1086                 printf("Impossible creating hash sucessfully with invalid socket\n");
1087                 return -1;
1088         }
1089
1090         rte_hash_free(handle);
1091
1092         return 0;
1093 }
1094
1095 /*
1096  * Do tests for hash creation with parameters that look incorrect
1097  * but are actually valid.
1098  */
1099 static int
1100 test_hash_creation_with_good_parameters(void)
1101 {
1102         struct rte_hash *handle, *tmp;
1103         struct rte_hash_parameters params;
1104
1105         /* create with null hash function - should choose DEFAULT_HASH_FUNC */
1106         memcpy(&params, &ut_params, sizeof(params));
1107         params.name = "same_name";
1108         params.hash_func = NULL;
1109         handle = rte_hash_create(&params);
1110         if (handle == NULL) {
1111                 printf("Creating hash with null hash_func failed\n");
1112                 return -1;
1113         }
1114         if (handle->hash_func == NULL) {
1115                 printf("Hash function should have been DEFAULT_HASH_FUNC\n");
1116                 return -1;
1117         }
1118
1119         /* this test is trying to create a hash with the same name as previous one.
1120          * this should return a pointer to the hash we previously created.
1121          * the previous hash isn't freed exactly for the purpose of it being in
1122          * the hash list.
1123          */
1124         memcpy(&params, &ut_params, sizeof(params));
1125         params.name = "same_name";
1126         tmp = rte_hash_create(&params);
1127
1128         /* check if the returned handle is actually equal to the previous hash */
1129         if (handle != tmp) {
1130                 rte_hash_free(handle);
1131                 rte_hash_free(tmp);
1132                 printf("Creating hash with existing name was successful\n");
1133                 return -1;
1134         }
1135
1136         /* try creating hash when there already are hashes in the list.
1137          * the previous hash is not freed to have a non-empty hash list.
1138          * the other hash that's in the list is still pointed to by "handle" var.
1139          */
1140         memcpy(&params, &ut_params, sizeof(params));
1141         params.name = "different_name";
1142         tmp = rte_hash_create(&params);
1143         if (tmp == NULL) {
1144                 rte_hash_free(handle);
1145                 printf("Creating hash with valid parameters failed\n");
1146                 return -1;
1147         }
1148
1149         rte_hash_free(tmp);
1150         rte_hash_free(handle);
1151
1152         return 0;
1153 }
1154
1155 static uint8_t key[16] = {0x00, 0x01, 0x02, 0x03,
1156                         0x04, 0x05, 0x06, 0x07,
1157                         0x08, 0x09, 0x0a, 0x0b,
1158                         0x0c, 0x0d, 0x0e, 0x0f};
1159 static struct rte_hash_parameters hash_params_ex = {
1160         .name = NULL,
1161         .entries = 64,
1162         .bucket_entries = 4,
1163         .key_len = 0,
1164         .hash_func = NULL,
1165         .hash_func_init_val = 0,
1166         .socket_id = 0,
1167 };
1168
1169 /*
1170  * add/delete key with jhash2
1171  */
1172 static int
1173 test_hash_add_delete_jhash2(void)
1174 {
1175         int ret = -1;
1176         struct rte_hash *handle;
1177         int32_t pos1, pos2;
1178
1179         hash_params_ex.name = "hash_test_jhash2";
1180         hash_params_ex.key_len = 4;
1181         hash_params_ex.hash_func = (rte_hash_function)rte_jhash2;
1182
1183         handle = rte_hash_create(&hash_params_ex);
1184         if (handle == NULL) {
1185                 printf("test_hash_add_delete_jhash2 fail to create hash\n");
1186                 goto fail_jhash2;
1187         }
1188         pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1189         if (pos1 < 0) {
1190                 printf("test_hash_add_delete_jhash2 fail to add hash key\n");
1191                 goto fail_jhash2;
1192         }
1193
1194         pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1195         if (pos2 < 0 || pos1 != pos2) {
1196                 printf("test_hash_add_delete_jhash2 delete different key from being added\n");
1197                 goto fail_jhash2;
1198         }
1199         ret = 0;
1200
1201 fail_jhash2:
1202         if (handle != NULL)
1203                 rte_hash_free(handle);
1204
1205         return ret;
1206 }
1207
1208 /*
1209  * add/delete (2) key with jhash2
1210  */
1211 static int
1212 test_hash_add_delete_2_jhash2(void)
1213 {
1214         int ret = -1;
1215         struct rte_hash *handle;
1216         int32_t pos1, pos2;
1217
1218         hash_params_ex.name = "hash_test_2_jhash2";
1219         hash_params_ex.key_len = 8;
1220         hash_params_ex.hash_func = (rte_hash_function)rte_jhash2;
1221
1222         handle = rte_hash_create(&hash_params_ex);
1223         if (handle == NULL)
1224                 goto fail_2_jhash2;
1225
1226         pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1227         if (pos1 < 0)
1228                 goto fail_2_jhash2;
1229
1230         pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1231         if (pos2 < 0 || pos1 != pos2)
1232                 goto fail_2_jhash2;
1233
1234         ret = 0;
1235
1236 fail_2_jhash2:
1237         if (handle != NULL)
1238                 rte_hash_free(handle);
1239
1240         return ret;
1241 }
1242
1243 static uint32_t
1244 test_hash_jhash_1word(const void *key, uint32_t length, uint32_t initval)
1245 {
1246         const uint32_t *k = key;
1247
1248         RTE_SET_USED(length);
1249
1250         return rte_jhash_1word(k[0], initval);
1251 }
1252
1253 static uint32_t
1254 test_hash_jhash_2word(const void *key, uint32_t length, uint32_t initval)
1255 {
1256         const uint32_t *k = key;
1257
1258         RTE_SET_USED(length);
1259
1260         return rte_jhash_2words(k[0], k[1], initval);
1261 }
1262
1263 static uint32_t
1264 test_hash_jhash_3word(const void *key, uint32_t length, uint32_t initval)
1265 {
1266         const uint32_t *k = key;
1267
1268         RTE_SET_USED(length);
1269
1270         return rte_jhash_3words(k[0], k[1], k[2], initval);
1271 }
1272
1273 /*
1274  * add/delete key with jhash 1word
1275  */
1276 static int
1277 test_hash_add_delete_jhash_1word(void)
1278 {
1279         int ret = -1;
1280         struct rte_hash *handle;
1281         int32_t pos1, pos2;
1282
1283         hash_params_ex.name = "hash_test_jhash_1word";
1284         hash_params_ex.key_len = 4;
1285         hash_params_ex.hash_func = test_hash_jhash_1word;
1286
1287         handle = rte_hash_create(&hash_params_ex);
1288         if (handle == NULL)
1289                 goto fail_jhash_1word;
1290
1291         pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1292         if (pos1 < 0)
1293                 goto fail_jhash_1word;
1294
1295         pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1296         if (pos2 < 0 || pos1 != pos2)
1297                 goto fail_jhash_1word;
1298
1299         ret = 0;
1300
1301 fail_jhash_1word:
1302         if (handle != NULL)
1303                 rte_hash_free(handle);
1304
1305         return ret;
1306 }
1307
1308 /*
1309  * add/delete key with jhash 2word
1310  */
1311 static int
1312 test_hash_add_delete_jhash_2word(void)
1313 {
1314         int ret = -1;
1315         struct rte_hash *handle;
1316         int32_t pos1, pos2;
1317
1318         hash_params_ex.name = "hash_test_jhash_2word";
1319         hash_params_ex.key_len = 8;
1320         hash_params_ex.hash_func = test_hash_jhash_2word;
1321
1322         handle = rte_hash_create(&hash_params_ex);
1323         if (handle == NULL)
1324                 goto fail_jhash_2word;
1325
1326         pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1327         if (pos1 < 0)
1328                 goto fail_jhash_2word;
1329
1330         pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1331         if (pos2 < 0 || pos1 != pos2)
1332                 goto fail_jhash_2word;
1333
1334         ret = 0;
1335
1336 fail_jhash_2word:
1337         if (handle != NULL)
1338                 rte_hash_free(handle);
1339
1340         return ret;
1341 }
1342
1343 /*
1344  * add/delete key with jhash 3word
1345  */
1346 static int
1347 test_hash_add_delete_jhash_3word(void)
1348 {
1349         int ret = -1;
1350         struct rte_hash *handle;
1351         int32_t pos1, pos2;
1352
1353         hash_params_ex.name = "hash_test_jhash_3word";
1354         hash_params_ex.key_len = 12;
1355         hash_params_ex.hash_func = test_hash_jhash_3word;
1356
1357         handle = rte_hash_create(&hash_params_ex);
1358         if (handle == NULL)
1359                 goto fail_jhash_3word;
1360
1361         pos1 = rte_hash_add_key(handle, (void *)&key[0]);
1362         if (pos1 < 0)
1363                 goto fail_jhash_3word;
1364
1365         pos2 = rte_hash_del_key(handle, (void *)&key[0]);
1366         if (pos2 < 0 || pos1 != pos2)
1367                 goto fail_jhash_3word;
1368
1369         ret = 0;
1370
1371 fail_jhash_3word:
1372         if (handle != NULL)
1373                 rte_hash_free(handle);
1374
1375         return ret;
1376 }
1377
1378 /*
1379  * Do all unit and performance tests.
1380  */
1381 static int
1382 test_hash(void)
1383 {
1384         if (test_add_delete() < 0)
1385                 return -1;
1386         if (test_hash_add_delete_jhash2() < 0)
1387                 return -1;
1388         if (test_hash_add_delete_2_jhash2() < 0)
1389                 return -1;
1390         if (test_hash_add_delete_jhash_1word() < 0)
1391                 return -1;
1392         if (test_hash_add_delete_jhash_2word() < 0)
1393                 return -1;
1394         if (test_hash_add_delete_jhash_3word() < 0)
1395                 return -1;
1396         if (test_hash_find_existing() < 0)
1397                 return -1;
1398         if (test_add_update_delete() < 0)
1399                 return -1;
1400         if (test_five_keys() < 0)
1401                 return -1;
1402         if (test_full_bucket() < 0)
1403                 return -1;
1404
1405         if (test_fbk_hash_find_existing() < 0)
1406                 return -1;
1407         if (fbk_hash_unit_test() < 0)
1408                 return -1;
1409         if (test_hash_creation_with_bad_parameters() < 0)
1410                 return -1;
1411         if (test_hash_creation_with_good_parameters() < 0)
1412                 return -1;
1413
1414         run_hash_func_tests();
1415
1416         if (test_crc32_hash_alg_equiv() < 0)
1417                 return -1;
1418
1419         return 0;
1420 }
1421
1422 static struct test_command hash_cmd = {
1423         .command = "hash_autotest",
1424         .callback = test_hash,
1425 };
1426 REGISTER_TEST_COMMAND(hash_cmd);