New upstream version 17.11-rc3
[deb_dpdk.git] / test / test / test_table_tables.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2016 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <string.h>
35 #include <rte_byteorder.h>
36 #include <rte_table_lpm_ipv6.h>
37 #include <rte_lru.h>
38 #include <rte_cycles.h>
39 #include "test_table_tables.h"
40 #include "test_table.h"
41
42 table_test table_tests[] = {
43         test_table_stub,
44         test_table_array,
45         test_table_lpm,
46         test_table_lpm_ipv6,
47         test_table_hash_lru,
48         test_table_hash_ext,
49         test_table_hash_cuckoo,
50 };
51
52 #define PREPARE_PACKET(mbuf, value) do {                                \
53         uint32_t *k32, *signature;                                      \
54         uint8_t *key;                                                   \
55         mbuf = rte_pktmbuf_alloc(pool);                                 \
56         signature = RTE_MBUF_METADATA_UINT32_PTR(mbuf,                  \
57                         APP_METADATA_OFFSET(0));                        \
58         key = RTE_MBUF_METADATA_UINT8_PTR(mbuf,                 \
59                         APP_METADATA_OFFSET(32));                       \
60         memset(key, 0, 32);                                             \
61         k32 = (uint32_t *) key;                                         \
62         k32[0] = (value);                                               \
63         *signature = pipeline_test_hash(key, NULL, 0, 0);                       \
64 } while (0)
65
66 unsigned n_table_tests = RTE_DIM(table_tests);
67
68 /* Function prototypes */
69 static int
70 test_table_hash_lru_generic(struct rte_table_ops *ops, uint32_t key_size);
71 static int
72 test_table_hash_ext_generic(struct rte_table_ops *ops, uint32_t key_size);
73
74 struct rte_bucket_4_8 {
75         /* Cache line 0 */
76         uint64_t signature;
77         uint64_t lru_list;
78         struct rte_bucket_4_8 *next;
79         uint64_t next_valid;
80         uint64_t key[4];
81         /* Cache line 1 */
82         uint8_t data[0];
83 };
84
85 #if RTE_TABLE_HASH_LRU_STRATEGY == 3
86 uint64_t shuffles = 0xfffffffdfffbfff9ULL;
87 #else
88 uint64_t shuffles = 0x0003000200010000ULL;
89 #endif
90
91 static int test_lru_update(void)
92 {
93         struct rte_bucket_4_8 b;
94         struct rte_bucket_4_8 *bucket;
95         uint32_t i;
96         uint64_t pos;
97         uint64_t iterations;
98         uint64_t j;
99         int poss;
100
101         printf("---------------------------\n");
102         printf("Testing lru_update macro...\n");
103         printf("---------------------------\n");
104         bucket = &b;
105         iterations = 10;
106 #if RTE_TABLE_HASH_LRU_STRATEGY == 3
107         bucket->lru_list = 0xFFFFFFFFFFFFFFFFULL;
108 #else
109         bucket->lru_list = 0x0000000100020003ULL;
110 #endif
111         poss = 0;
112         for (j = 0; j < iterations; j++)
113                 for (i = 0; i < 9; i++) {
114                         uint32_t idx = i >> 1;
115                         lru_update(bucket, idx);
116                         pos = lru_pos(bucket);
117                         poss += pos;
118                         printf("%s: %d lru_list=%016"PRIx64", upd=%d, "
119                                 "pos=%"PRIx64"\n",
120                                 __func__, i, bucket->lru_list, i>>1, pos);
121                 }
122
123         if (bucket->lru_list != shuffles) {
124                 printf("%s: ERROR: %d lru_list=%016"PRIx64", expected %016"
125                         PRIx64"\n",
126                         __func__, i, bucket->lru_list, shuffles);
127                 return -1;
128         }
129         printf("%s: output checksum of results =%d\n",
130                 __func__, poss);
131 #if 0
132         if (poss != 126) {
133                 printf("%s: ERROR output checksum of results =%d expected %d\n",
134                         __func__, poss, 126);
135                 return -1;
136         }
137 #endif
138
139         fflush(stdout);
140
141         uint64_t sc_start = rte_rdtsc();
142         iterations = 100000000;
143         poss = 0;
144         for (j = 0; j < iterations; j++) {
145                 for (i = 0; i < 4; i++) {
146                         lru_update(bucket, i);
147                         pos |= bucket->lru_list;
148                 }
149         }
150         uint64_t sc_end = rte_rdtsc();
151
152         printf("%s: output checksum of results =%llu\n",
153                 __func__, (long long unsigned int)pos);
154         printf("%s: start=%016"PRIx64", end=%016"PRIx64"\n",
155                 __func__, sc_start, sc_end);
156         printf("\nlru_update: %lu cycles per loop iteration.\n\n",
157                 (long unsigned int)((sc_end-sc_start)/(iterations*4)));
158
159         return 0;
160 }
161
162 /* Table tests */
163 int
164 test_table_stub(void)
165 {
166         int i;
167         uint64_t expected_mask = 0, result_mask;
168         struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX];
169         void *table;
170         char *entries[RTE_PORT_IN_BURST_SIZE_MAX];
171
172         /* Create */
173         table = rte_table_stub_ops.f_create(NULL, 0, 1);
174         if (table == NULL)
175                 return -1;
176
177         /* Traffic flow */
178         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
179                 if (i % 2 == 0)
180                         PREPARE_PACKET(mbufs[i], 0xadadadad);
181                 else
182                         PREPARE_PACKET(mbufs[i], 0xadadadab);
183
184         expected_mask = 0;
185         rte_table_stub_ops.f_lookup(table, mbufs, -1,
186                 &result_mask, (void **)entries);
187         if (result_mask != expected_mask)
188                 return -2;
189
190         /* Free resources */
191         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
192                 rte_pktmbuf_free(mbufs[i]);
193
194         return 0;
195 }
196
197 int
198 test_table_array(void)
199 {
200         int status, i;
201         uint64_t result_mask;
202         struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX];
203         void *table;
204         char *entries[RTE_PORT_IN_BURST_SIZE_MAX];
205         char entry1, entry2;
206         void *entry_ptr;
207         int key_found;
208
209         /* Initialize params and create tables */
210         struct rte_table_array_params array_params = {
211                 .n_entries = 7,
212                 .offset = APP_METADATA_OFFSET(1)
213         };
214
215         table = rte_table_array_ops.f_create(NULL, 0, 1);
216         if (table != NULL)
217                 return -1;
218
219         array_params.n_entries = 0;
220
221         table = rte_table_array_ops.f_create(&array_params, 0, 1);
222         if (table != NULL)
223                 return -2;
224
225         array_params.n_entries = 7;
226
227         table = rte_table_array_ops.f_create(&array_params, 0, 1);
228         if (table != NULL)
229                 return -3;
230
231         array_params.n_entries = 1 << 24;
232         array_params.offset = APP_METADATA_OFFSET(1);
233
234         table = rte_table_array_ops.f_create(&array_params, 0, 1);
235         if (table == NULL)
236                 return -4;
237
238         array_params.offset = APP_METADATA_OFFSET(32);
239
240         table = rte_table_array_ops.f_create(&array_params, 0, 1);
241         if (table == NULL)
242                 return -5;
243
244         /* Free */
245         status = rte_table_array_ops.f_free(table);
246         if (status < 0)
247                 return -6;
248
249         status = rte_table_array_ops.f_free(NULL);
250         if (status == 0)
251                 return -7;
252
253         /* Add */
254         struct rte_table_array_key array_key_1 = {
255                 .pos = 10,
256         };
257         struct rte_table_array_key array_key_2 = {
258                 .pos = 20,
259         };
260         entry1 = 'A';
261         entry2 = 'B';
262
263         table = rte_table_array_ops.f_create(&array_params, 0, 1);
264         if (table == NULL)
265                 return -8;
266
267         status = rte_table_array_ops.f_add(NULL, (void *) &array_key_1, &entry1,
268                 &key_found, &entry_ptr);
269         if (status == 0)
270                 return -9;
271
272         status = rte_table_array_ops.f_add(table, (void *) &array_key_1, NULL,
273                 &key_found, &entry_ptr);
274         if (status == 0)
275                 return -10;
276
277         status = rte_table_array_ops.f_add(table, (void *) &array_key_1,
278                 &entry1, &key_found, &entry_ptr);
279         if (status != 0)
280                 return -11;
281
282         /* Traffic flow */
283         status = rte_table_array_ops.f_add(table, (void *) &array_key_2,
284                 &entry2, &key_found, &entry_ptr);
285         if (status != 0)
286                 return -12;
287
288         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
289                 if (i % 2 == 0)
290                         PREPARE_PACKET(mbufs[i], 10);
291                 else
292                         PREPARE_PACKET(mbufs[i], 20);
293
294         rte_table_array_ops.f_lookup(table, mbufs, -1,
295                 &result_mask, (void **)entries);
296
297         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
298                 if (i % 2 == 0 && *entries[i] != 'A')
299                         return -13;
300                 else
301                         if (i % 2 == 1 && *entries[i] != 'B')
302                                 return -13;
303
304         /* Free resources */
305         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
306                 rte_pktmbuf_free(mbufs[i]);
307
308         status = rte_table_array_ops.f_free(table);
309
310         return 0;
311 }
312
313 int
314 test_table_lpm(void)
315 {
316         int status, i;
317         uint64_t expected_mask = 0, result_mask;
318         struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX];
319         void *table;
320         char *entries[RTE_PORT_IN_BURST_SIZE_MAX];
321         char entry;
322         void *entry_ptr;
323         int key_found;
324         uint32_t entry_size = 1;
325
326         /* Initialize params and create tables */
327         struct rte_table_lpm_params lpm_params = {
328                 .name = "LPM",
329                 .n_rules = 1 << 24,
330                 .number_tbl8s = 1 << 8,
331                 .flags = 0,
332                 .entry_unique_size = entry_size,
333                 .offset = APP_METADATA_OFFSET(1)
334         };
335
336         table = rte_table_lpm_ops.f_create(NULL, 0, entry_size);
337         if (table != NULL)
338                 return -1;
339
340         lpm_params.name = NULL;
341
342         table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size);
343         if (table != NULL)
344                 return -2;
345
346         lpm_params.name = "LPM";
347         lpm_params.n_rules = 0;
348
349         table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size);
350         if (table != NULL)
351                 return -3;
352
353         lpm_params.n_rules = 1 << 24;
354         lpm_params.offset = APP_METADATA_OFFSET(32);
355         lpm_params.entry_unique_size = 0;
356
357         table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size);
358         if (table != NULL)
359                 return -4;
360
361         lpm_params.entry_unique_size = entry_size + 1;
362
363         table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size);
364         if (table != NULL)
365                 return -5;
366
367         lpm_params.entry_unique_size = entry_size;
368
369         table = rte_table_lpm_ops.f_create(&lpm_params, 0, entry_size);
370         if (table == NULL)
371                 return -6;
372
373         /* Free */
374         status = rte_table_lpm_ops.f_free(table);
375         if (status < 0)
376                 return -7;
377
378         status = rte_table_lpm_ops.f_free(NULL);
379         if (status == 0)
380                 return -8;
381
382         /* Add */
383         struct rte_table_lpm_key lpm_key;
384         lpm_key.ip = 0xadadadad;
385
386         table = rte_table_lpm_ops.f_create(&lpm_params, 0, 1);
387         if (table == NULL)
388                 return -9;
389
390         status = rte_table_lpm_ops.f_add(NULL, &lpm_key, &entry, &key_found,
391                 &entry_ptr);
392         if (status == 0)
393                 return -10;
394
395         status = rte_table_lpm_ops.f_add(table, NULL, &entry, &key_found,
396                 &entry_ptr);
397         if (status == 0)
398                 return -11;
399
400         status = rte_table_lpm_ops.f_add(table, &lpm_key, NULL, &key_found,
401                 &entry_ptr);
402         if (status == 0)
403                 return -12;
404
405         lpm_key.depth = 0;
406         status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found,
407                 &entry_ptr);
408         if (status == 0)
409                 return -13;
410
411         lpm_key.depth = 33;
412         status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found,
413                 &entry_ptr);
414         if (status == 0)
415                 return -14;
416
417         lpm_key.depth = 16;
418         status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found,
419                 &entry_ptr);
420         if (status != 0)
421                 return -15;
422
423         /* Delete */
424         status = rte_table_lpm_ops.f_delete(NULL, &lpm_key, &key_found, NULL);
425         if (status == 0)
426                 return -16;
427
428         status = rte_table_lpm_ops.f_delete(table, NULL, &key_found, NULL);
429         if (status == 0)
430                 return -17;
431
432         lpm_key.depth = 0;
433         status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL);
434         if (status == 0)
435                 return -18;
436
437         lpm_key.depth = 33;
438         status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL);
439         if (status == 0)
440                 return -19;
441
442         lpm_key.depth = 16;
443         status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL);
444         if (status != 0)
445                 return -20;
446
447         status = rte_table_lpm_ops.f_delete(table, &lpm_key, &key_found, NULL);
448         if (status != 0)
449                 return -21;
450
451         /* Traffic flow */
452         entry = 'A';
453         status = rte_table_lpm_ops.f_add(table, &lpm_key, &entry, &key_found,
454                 &entry_ptr);
455         if (status < 0)
456                 return -22;
457
458         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
459                 if (i % 2 == 0) {
460                         expected_mask |= (uint64_t)1 << i;
461                         PREPARE_PACKET(mbufs[i], 0xadadadad);
462                 } else
463                         PREPARE_PACKET(mbufs[i], 0xadadadab);
464
465         rte_table_lpm_ops.f_lookup(table, mbufs, -1,
466                 &result_mask, (void **)entries);
467         if (result_mask != expected_mask)
468                 return -23;
469
470         /* Free resources */
471         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
472                 rte_pktmbuf_free(mbufs[i]);
473
474         status = rte_table_lpm_ops.f_free(table);
475
476         return 0;
477 }
478
479 int
480 test_table_lpm_ipv6(void)
481 {
482         int status, i;
483         uint64_t expected_mask = 0, result_mask;
484         struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX];
485         void *table;
486         char *entries[RTE_PORT_IN_BURST_SIZE_MAX];
487         char entry;
488         void *entry_ptr;
489         int key_found;
490         uint32_t entry_size = 1;
491
492         /* Initialize params and create tables */
493         struct rte_table_lpm_ipv6_params lpm_params = {
494                 .name = "LPM",
495                 .n_rules = 1 << 24,
496                 .number_tbl8s = 1 << 21,
497                 .entry_unique_size = entry_size,
498                 .offset = APP_METADATA_OFFSET(32)
499         };
500
501         table = rte_table_lpm_ipv6_ops.f_create(NULL, 0, entry_size);
502         if (table != NULL)
503                 return -1;
504
505         lpm_params.name = NULL;
506
507         table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size);
508         if (table != NULL)
509                 return -2;
510
511         lpm_params.name = "LPM";
512         lpm_params.n_rules = 0;
513
514         table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size);
515         if (table != NULL)
516                 return -3;
517
518         lpm_params.n_rules = 1 << 24;
519         lpm_params.number_tbl8s = 0;
520         table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size);
521         if (table != NULL)
522                 return -4;
523
524         lpm_params.number_tbl8s = 1 << 21;
525         lpm_params.entry_unique_size = 0;
526         table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size);
527         if (table != NULL)
528                 return -5;
529
530         lpm_params.entry_unique_size = entry_size + 1;
531         table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size);
532         if (table != NULL)
533                 return -6;
534
535         lpm_params.entry_unique_size = entry_size;
536         lpm_params.offset = APP_METADATA_OFFSET(32);
537
538         table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size);
539         if (table == NULL)
540                 return -7;
541
542         /* Free */
543         status = rte_table_lpm_ipv6_ops.f_free(table);
544         if (status < 0)
545                 return -8;
546
547         status = rte_table_lpm_ipv6_ops.f_free(NULL);
548         if (status == 0)
549                 return -9;
550
551         /* Add */
552         struct rte_table_lpm_ipv6_key lpm_key;
553
554         lpm_key.ip[0] = 0xad;
555         lpm_key.ip[1] = 0xad;
556         lpm_key.ip[2] = 0xad;
557         lpm_key.ip[3] = 0xad;
558
559         table = rte_table_lpm_ipv6_ops.f_create(&lpm_params, 0, entry_size);
560         if (table == NULL)
561                 return -10;
562
563         status = rte_table_lpm_ipv6_ops.f_add(NULL, &lpm_key, &entry,
564                 &key_found, &entry_ptr);
565         if (status == 0)
566                 return -11;
567
568         status = rte_table_lpm_ipv6_ops.f_add(table, NULL, &entry, &key_found,
569                 &entry_ptr);
570         if (status == 0)
571                 return -12;
572
573         status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, NULL, &key_found,
574                 &entry_ptr);
575         if (status == 0)
576                 return -13;
577
578         lpm_key.depth = 0;
579         status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry,
580                 &key_found, &entry_ptr);
581         if (status == 0)
582                 return -14;
583
584         lpm_key.depth = 129;
585         status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry,
586                 &key_found, &entry_ptr);
587         if (status == 0)
588                 return -15;
589
590         lpm_key.depth = 16;
591         status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry,
592                 &key_found, &entry_ptr);
593         if (status != 0)
594                 return -16;
595
596         /* Delete */
597         status = rte_table_lpm_ipv6_ops.f_delete(NULL, &lpm_key, &key_found,
598                 NULL);
599         if (status == 0)
600                 return -17;
601
602         status = rte_table_lpm_ipv6_ops.f_delete(table, NULL, &key_found, NULL);
603         if (status == 0)
604                 return -18;
605
606         lpm_key.depth = 0;
607         status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found,
608                 NULL);
609         if (status == 0)
610                 return -19;
611
612         lpm_key.depth = 129;
613         status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found,
614                 NULL);
615         if (status == 0)
616                 return -20;
617
618         lpm_key.depth = 16;
619         status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found,
620                 NULL);
621         if (status != 0)
622                 return -21;
623
624         status = rte_table_lpm_ipv6_ops.f_delete(table, &lpm_key, &key_found,
625                 NULL);
626         if (status != 0)
627                 return -22;
628
629         /* Traffic flow */
630         entry = 'A';
631         status = rte_table_lpm_ipv6_ops.f_add(table, &lpm_key, &entry,
632                 &key_found, &entry_ptr);
633         if (status < 0)
634                 return -23;
635
636         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
637                 if (i % 2 == 0) {
638                         expected_mask |= (uint64_t)1 << i;
639                         PREPARE_PACKET(mbufs[i], 0xadadadad);
640                 } else
641                         PREPARE_PACKET(mbufs[i], 0xadadadab);
642
643         rte_table_lpm_ipv6_ops.f_lookup(table, mbufs, -1,
644                 &result_mask, (void **)entries);
645         if (result_mask != expected_mask)
646                 return -24;
647
648         /* Free resources */
649         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
650                 rte_pktmbuf_free(mbufs[i]);
651
652         status = rte_table_lpm_ipv6_ops.f_free(table);
653
654         return 0;
655 }
656
657 static int
658 test_table_hash_lru_generic(struct rte_table_ops *ops, uint32_t key_size)
659 {
660         int status, i;
661         uint64_t expected_mask = 0, result_mask;
662         struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX];
663         void *table;
664         char *entries[RTE_PORT_IN_BURST_SIZE_MAX];
665         char entry;
666         void *entry_ptr;
667         int key_found;
668
669         /* Initialize params and create tables */
670         struct rte_table_hash_params hash_params = {
671                 .name = "TABLE",
672                 .key_size = key_size,
673                 .key_offset = APP_METADATA_OFFSET(32),
674                 .key_mask = NULL,
675                 .n_keys = 1 << 10,
676                 .n_buckets = 1 << 10,
677                 .f_hash = pipeline_test_hash,
678                 .seed = 0,
679         };
680
681         hash_params.n_keys = 0;
682
683         table = ops->f_create(&hash_params, 0, 1);
684         if (table != NULL)
685                 return -1;
686
687         hash_params.n_keys = 1 << 10;
688         hash_params.f_hash = NULL;
689
690         table = ops->f_create(&hash_params, 0, 1);
691         if (table != NULL)
692                 return -4;
693
694         hash_params.f_hash = pipeline_test_hash;
695
696         table = ops->f_create(&hash_params, 0, 1);
697         if (table == NULL)
698                 return -5;
699
700         /* Free */
701         status = ops->f_free(table);
702         if (status < 0)
703                 return -6;
704
705         status = ops->f_free(NULL);
706         if (status == 0)
707                 return -7;
708
709         /* Add */
710         uint8_t key[32];
711         uint32_t *k32 = (uint32_t *) &key;
712
713         memset(key, 0, 32);
714         k32[0] = rte_be_to_cpu_32(0xadadadad);
715
716         table = ops->f_create(&hash_params, 0, 1);
717         if (table == NULL)
718                 return -8;
719
720         entry = 'A';
721         status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr);
722         if (status != 0)
723                 return -9;
724
725         /* Delete */
726         status = ops->f_delete(table, &key, &key_found, NULL);
727         if (status != 0)
728                 return -10;
729
730         status = ops->f_delete(table, &key, &key_found, NULL);
731         if (status != 0)
732                 return -11;
733
734         /* Traffic flow */
735         entry = 'A';
736         status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr);
737         if (status < 0)
738                 return -12;
739
740         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
741                 if (i % 2 == 0) {
742                         expected_mask |= (uint64_t)1 << i;
743                         PREPARE_PACKET(mbufs[i], 0xadadadad);
744                 } else
745                         PREPARE_PACKET(mbufs[i], 0xadadadab);
746
747         ops->f_lookup(table, mbufs, -1, &result_mask, (void **)entries);
748         if (result_mask != expected_mask)
749                 return -13;
750
751         /* Free resources */
752         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
753                 rte_pktmbuf_free(mbufs[i]);
754
755         status = ops->f_free(table);
756
757         return 0;
758 }
759
760 static int
761 test_table_hash_ext_generic(struct rte_table_ops *ops, uint32_t key_size)
762 {
763         int status, i;
764         uint64_t expected_mask = 0, result_mask;
765         struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX];
766         void *table;
767         char *entries[RTE_PORT_IN_BURST_SIZE_MAX];
768         char entry;
769         int key_found;
770         void *entry_ptr;
771
772         /* Initialize params and create tables */
773         struct rte_table_hash_params hash_params = {
774                 .name = "TABLE",
775                 .key_size = key_size,
776                 .key_offset = APP_METADATA_OFFSET(32),
777                 .key_mask = NULL,
778                 .n_keys = 1 << 10,
779                 .n_buckets = 1 << 10,
780                 .f_hash = pipeline_test_hash,
781                 .seed = 0,
782         };
783
784         hash_params.n_keys = 0;
785
786         table = ops->f_create(&hash_params, 0, 1);
787         if (table != NULL)
788                 return -1;
789
790         hash_params.n_keys = 1 << 10;
791         hash_params.key_offset = APP_METADATA_OFFSET(1);
792
793         table = ops->f_create(&hash_params, 0, 1);
794         if (table == NULL)
795                 return -3;
796
797         hash_params.key_offset = APP_METADATA_OFFSET(32);
798         hash_params.f_hash = NULL;
799
800         table = ops->f_create(&hash_params, 0, 1);
801         if (table != NULL)
802                 return -4;
803
804         hash_params.f_hash = pipeline_test_hash;
805
806         table = ops->f_create(&hash_params, 0, 1);
807         if (table == NULL)
808                 return -5;
809
810         /* Free */
811         status = ops->f_free(table);
812         if (status < 0)
813                 return -6;
814
815         status = ops->f_free(NULL);
816         if (status == 0)
817                 return -7;
818
819         /* Add */
820         uint8_t key[32];
821         uint32_t *k32 = (uint32_t *) &key;
822
823         memset(key, 0, 32);
824         k32[0] = rte_be_to_cpu_32(0xadadadad);
825
826         table = ops->f_create(&hash_params, 0, 1);
827         if (table == NULL)
828                 return -8;
829
830         entry = 'A';
831         status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr);
832         if (status != 0)
833                 return -9;
834
835         /* Delete */
836         status = ops->f_delete(table, &key, &key_found, NULL);
837         if (status != 0)
838                 return -10;
839
840         status = ops->f_delete(table, &key, &key_found, NULL);
841         if (status != 0)
842                 return -11;
843
844         /* Traffic flow */
845         entry = 'A';
846         status = ops->f_add(table, &key, &entry, &key_found, &entry_ptr);
847         if (status < 0)
848                 return -12;
849
850         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
851                 if (i % 2 == 0) {
852                         expected_mask |= (uint64_t)1 << i;
853                         PREPARE_PACKET(mbufs[i], 0xadadadad);
854                 } else
855                         PREPARE_PACKET(mbufs[i], 0xadadadab);
856
857         ops->f_lookup(table, mbufs, -1, &result_mask, (void **)entries);
858         if (result_mask != expected_mask)
859                 return -13;
860
861         /* Free resources */
862         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
863                 rte_pktmbuf_free(mbufs[i]);
864
865         status = ops->f_free(table);
866
867         return 0;
868 }
869
870 int
871 test_table_hash_lru(void)
872 {
873         int status;
874
875         status = test_table_hash_lru_generic(
876                 &rte_table_hash_key8_lru_ops,
877                 8);
878         if (status < 0)
879                 return status;
880
881         status = test_table_hash_lru_generic(
882                 &rte_table_hash_key16_lru_ops,
883                 16);
884         if (status < 0)
885                 return status;
886
887         status = test_table_hash_lru_generic(
888                 &rte_table_hash_key32_lru_ops,
889                 32);
890         if (status < 0)
891                 return status;
892
893         status = test_lru_update();
894         if (status < 0)
895                 return status;
896
897         return 0;
898 }
899
900 int
901 test_table_hash_ext(void)
902 {
903         int status;
904
905         status = test_table_hash_ext_generic(&rte_table_hash_key8_ext_ops, 8);
906         if (status < 0)
907                 return status;
908
909         status = test_table_hash_ext_generic(&rte_table_hash_key16_ext_ops, 16);
910         if (status < 0)
911                 return status;
912
913         status = test_table_hash_ext_generic(&rte_table_hash_key32_ext_ops, 32);
914         if (status < 0)
915                 return status;
916
917         return 0;
918 }
919
920
921 int
922 test_table_hash_cuckoo(void)
923 {
924         int status, i;
925         uint64_t expected_mask = 0, result_mask;
926         struct rte_mbuf *mbufs[RTE_PORT_IN_BURST_SIZE_MAX];
927         void *table;
928         char *entries[RTE_PORT_IN_BURST_SIZE_MAX];
929         char entry;
930         void *entry_ptr;
931         int key_found;
932         uint32_t entry_size = 1;
933
934         /* Initialize params and create tables */
935         struct rte_table_hash_params cuckoo_params = {
936                 .name = "TABLE",
937                 .key_size = 32,
938                 .key_offset = APP_METADATA_OFFSET(32),
939                 .key_mask = NULL,
940                 .n_keys = 1 << 16,
941                 .n_buckets = 1 << 16,
942                 .f_hash = (rte_table_hash_op_hash)pipeline_test_hash,
943                 .seed = 0, 
944         };
945
946         table = rte_table_hash_cuckoo_ops.f_create(NULL, 0, entry_size);
947         if (table != NULL)
948                 return -1;
949
950         cuckoo_params.key_size = 0;
951
952         table = rte_table_hash_cuckoo_ops.f_create(&cuckoo_params,
953                 0, entry_size);
954         if (table != NULL)
955                 return -2;
956
957         cuckoo_params.key_size = 32;
958         cuckoo_params.n_keys = 0;
959
960         table = rte_table_hash_cuckoo_ops.f_create(&cuckoo_params,
961                 0, entry_size);
962         if (table != NULL)
963                 return -3;
964
965         cuckoo_params.n_keys = 1 << 24;
966         cuckoo_params.f_hash = NULL;
967
968         table = rte_table_hash_cuckoo_ops.f_create(&cuckoo_params,
969                 0, entry_size);
970         if (table != NULL)
971                 return -4;
972
973         cuckoo_params.f_hash = pipeline_test_hash;
974         cuckoo_params.name = NULL;
975
976         table = rte_table_hash_cuckoo_ops.f_create(&cuckoo_params,
977                 0, entry_size);
978         if (table != NULL)
979                 return -5;
980
981         cuckoo_params.name = "CUCKOO";
982
983         table = rte_table_hash_cuckoo_ops.f_create(&cuckoo_params,
984                 0, entry_size);
985         if (table == NULL)
986                 return -6;
987
988         /* Free */
989         status = rte_table_hash_cuckoo_ops.f_free(table);
990         if (status < 0)
991                 return -7;
992
993         status = rte_table_hash_cuckoo_ops.f_free(NULL);
994         if (status == 0)
995                 return -8;
996
997         /* Add */
998         uint8_t key_cuckoo[32];
999         uint32_t *kcuckoo = (uint32_t *) &key_cuckoo;
1000
1001         memset(key_cuckoo, 0, 32);
1002         kcuckoo[0] = rte_be_to_cpu_32(0xadadadad);
1003
1004         table = rte_table_hash_cuckoo_ops.f_create(&cuckoo_params, 0, 1);
1005         if (table == NULL)
1006                 return -9;
1007
1008         entry = 'A';
1009         status = rte_table_hash_cuckoo_ops.f_add(NULL, &key_cuckoo,
1010                 &entry, &key_found, &entry_ptr);
1011         if (status == 0)
1012                 return -10;
1013
1014         status = rte_table_hash_cuckoo_ops.f_add(table, NULL, &entry,
1015                 &key_found, &entry_ptr);
1016         if (status == 0)
1017                 return -11;
1018
1019         status = rte_table_hash_cuckoo_ops.f_add(table, &key_cuckoo,
1020                 NULL, &key_found, &entry_ptr);
1021         if (status == 0)
1022                 return -12;
1023
1024         status = rte_table_hash_cuckoo_ops.f_add(table, &key_cuckoo,
1025                 &entry, &key_found, &entry_ptr);
1026         if (status != 0)
1027                 return -13;
1028
1029         status = rte_table_hash_cuckoo_ops.f_add(table, &key_cuckoo,
1030                 &entry, &key_found, &entry_ptr);
1031         if (status != 0)
1032                 return -14;
1033
1034         /* Delete */
1035         status = rte_table_hash_cuckoo_ops.f_delete(NULL, &key_cuckoo,
1036                 &key_found, NULL);
1037         if (status == 0)
1038                 return -15;
1039
1040         status = rte_table_hash_cuckoo_ops.f_delete(table, NULL,
1041                 &key_found, NULL);
1042         if (status == 0)
1043                 return -16;
1044
1045         status = rte_table_hash_cuckoo_ops.f_delete(table, &key_cuckoo,
1046                 &key_found, NULL);
1047         if (status != 0)
1048                 return -17;
1049
1050         status = rte_table_hash_cuckoo_ops.f_delete(table, &key_cuckoo,
1051                 &key_found, NULL);
1052         if (status != -ENOENT)
1053                 return -18;
1054
1055         /* Traffic flow */
1056         entry = 'A';
1057         status = rte_table_hash_cuckoo_ops.f_add(table, &key_cuckoo,
1058                 &entry, &key_found,
1059                 &entry_ptr);
1060         if (status < 0)
1061                 return -19;
1062
1063         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
1064                 if (i % 2 == 0) {
1065                         expected_mask |= (uint64_t)1 << i;
1066                         PREPARE_PACKET(mbufs[i], 0xadadadad);
1067                 } else
1068                         PREPARE_PACKET(mbufs[i], 0xadadadab);
1069
1070         rte_table_hash_cuckoo_ops.f_lookup(table, mbufs, -1,
1071                 &result_mask, (void **)entries);
1072         if (result_mask != expected_mask)
1073                 return -20;
1074
1075         /* Free resources */
1076         for (i = 0; i < RTE_PORT_IN_BURST_SIZE_MAX; i++)
1077                 rte_pktmbuf_free(mbufs[i]);
1078
1079         status = rte_table_hash_cuckoo_ops.f_free(table);
1080
1081         return 0;
1082 }
1083