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