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