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