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