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