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