i40e: fix crash on DCB query
[dpdk.git] / app / test / test_lpm6.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 #include <stdio.h>
34 #include <stdint.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <sys/queue.h>
39
40 #include <time.h>
41
42 #include "test.h"
43
44 #include <rte_common.h>
45 #include <rte_cycles.h>
46 #include <rte_memory.h>
47 #include <rte_random.h>
48 #include <rte_branch_prediction.h>
49 #include <rte_ip.h>
50
51 #include "rte_lpm6.h"
52 #include "test_lpm6_routes.h"
53
54 #define TEST_LPM_ASSERT(cond) do {                                            \
55         if (!(cond)) {                                                        \
56                 printf("Error at line %d: \n", __LINE__);                     \
57                 return -1;                                                    \
58         }                                                                     \
59 } while(0)
60
61 typedef int32_t (* rte_lpm6_test)(void);
62
63 static int32_t test0(void);
64 static int32_t test1(void);
65 static int32_t test2(void);
66 static int32_t test3(void);
67 static int32_t test4(void);
68 static int32_t test5(void);
69 static int32_t test6(void);
70 static int32_t test7(void);
71 static int32_t test8(void);
72 static int32_t test9(void);
73 static int32_t test10(void);
74 static int32_t test11(void);
75 static int32_t test12(void);
76 static int32_t test13(void);
77 static int32_t test14(void);
78 static int32_t test15(void);
79 static int32_t test16(void);
80 static int32_t test17(void);
81 static int32_t test18(void);
82 static int32_t test19(void);
83 static int32_t test20(void);
84 static int32_t test21(void);
85 static int32_t test22(void);
86 static int32_t test23(void);
87 static int32_t test24(void);
88 static int32_t test25(void);
89 static int32_t test26(void);
90 static int32_t test27(void);
91 static int32_t perf_test(void);
92
93 rte_lpm6_test tests6[] = {
94 /* Test Cases */
95         test0,
96         test1,
97         test2,
98         test3,
99         test4,
100         test5,
101         test6,
102         test7,
103         test8,
104         test9,
105         test10,
106         test11,
107         test12,
108         test13,
109         test14,
110         test15,
111         test16,
112         test17,
113         test18,
114         test19,
115         test20,
116         test21,
117         test22,
118         test23,
119         test24,
120         test25,
121         test26,
122         test27,
123         perf_test,
124 };
125
126 #define NUM_LPM6_TESTS                (sizeof(tests6)/sizeof(tests6[0]))
127 #define RTE_LPM6_TBL24_NUM_ENTRIES                             (1 << 24)
128 #define RTE_LPM6_LOOKUP_SUCCESS                               0x04000000
129 #define MAX_DEPTH                                                    128
130 #define MAX_RULES                                                1000000
131 #define NUMBER_TBL8S                                           (1 << 16)
132 #define MAX_NUM_TBL8S                                          (1 << 21)
133 #define PASS 0
134
135 static void
136 IPv6(uint8_t *ip, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5,
137                 uint8_t b6, uint8_t b7, uint8_t b8, uint8_t b9, uint8_t b10,
138                 uint8_t b11, uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15,
139                 uint8_t b16)
140 {
141         ip[0] = b1;
142         ip[1] = b2;
143         ip[2] = b3;
144         ip[3] = b4;
145         ip[4] = b5;
146         ip[5] = b6;
147         ip[6] = b7;
148         ip[7] = b8;
149         ip[8] = b9;
150         ip[9] = b10;
151         ip[10] = b11;
152         ip[11] = b12;
153         ip[12] = b13;
154         ip[13] = b14;
155         ip[14] = b15;
156         ip[15] = b16;
157 }
158
159 /*
160  * Check that rte_lpm6_create fails gracefully for incorrect user input
161  * arguments
162  */
163 int32_t
164 test0(void)
165 {
166         struct rte_lpm6 *lpm = NULL;
167         struct rte_lpm6_config config;
168
169         config.max_rules = MAX_RULES;
170         config.number_tbl8s = NUMBER_TBL8S;
171         config.flags = 0;
172
173         /* rte_lpm6_create: lpm name == NULL */
174         lpm = rte_lpm6_create(NULL, SOCKET_ID_ANY, &config);
175         TEST_LPM_ASSERT(lpm == NULL);
176
177         /* rte_lpm6_create: max_rules = 0 */
178         /* Note: __func__ inserts the function name, in this case "test0". */
179         config.max_rules = 0;
180         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
181         TEST_LPM_ASSERT(lpm == NULL);
182
183         /* socket_id < -1 is invalid */
184         config.max_rules = MAX_RULES;
185         lpm = rte_lpm6_create(__func__, -2, &config);
186         TEST_LPM_ASSERT(lpm == NULL);
187
188         /* rte_lpm6_create: number_tbl8s is bigger than the maximum */
189         config.number_tbl8s = MAX_NUM_TBL8S + 1;
190         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
191         TEST_LPM_ASSERT(lpm == NULL);
192
193         /* rte_lpm6_create: config = NULL */
194         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, NULL);
195         TEST_LPM_ASSERT(lpm == NULL);
196
197         return PASS;
198 }
199
200 /*
201  * Creates two different LPM tables. Tries to create a third one with the same
202  * name as the first one and expects the create function to return the same
203  * pointer.
204  */
205 int32_t
206 test1(void)
207 {
208         struct rte_lpm6 *lpm1 = NULL, *lpm2 = NULL, *lpm3 = NULL;
209         struct rte_lpm6_config config;
210
211         config.max_rules = MAX_RULES;
212         config.number_tbl8s = NUMBER_TBL8S;
213         config.flags = 0;
214
215         /* rte_lpm6_create: lpm name == LPM1 */
216         lpm1 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
217         TEST_LPM_ASSERT(lpm1 != NULL);
218
219         /* rte_lpm6_create: lpm name == LPM2 */
220         lpm2 = rte_lpm6_create("LPM2", SOCKET_ID_ANY, &config);
221         TEST_LPM_ASSERT(lpm2 != NULL);
222
223         /* rte_lpm6_create: lpm name == LPM2 */
224         lpm3 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
225         TEST_LPM_ASSERT(lpm3 == lpm1);
226
227         rte_lpm6_free(lpm1);
228         rte_lpm6_free(lpm2);
229
230         return PASS;
231 }
232
233 /*
234  * Create lpm table then delete lpm table 100 times
235  * Use a slightly different rules size each time
236  */
237 int32_t
238 test2(void)
239 {
240         struct rte_lpm6 *lpm = NULL;
241         struct rte_lpm6_config config;
242         int32_t i;
243
244         config.number_tbl8s = NUMBER_TBL8S;
245         config.flags = 0;
246
247         /* rte_lpm6_free: Free NULL */
248         for (i = 0; i < 100; i++) {
249                 config.max_rules = MAX_RULES - i;
250                 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
251                 TEST_LPM_ASSERT(lpm != NULL);
252
253                 rte_lpm6_free(lpm);
254         }
255
256         /* Can not test free so return success */
257         return PASS;
258 }
259
260 /*
261  * Call rte_lpm6_free for NULL pointer user input. Note: free has no return and
262  * therefore it is impossible to check for failure but this test is added to
263  * increase function coverage metrics and to validate that freeing null does
264  * not crash.
265  */
266 int32_t
267 test3(void)
268 {
269         struct rte_lpm6 *lpm = NULL;
270         struct rte_lpm6_config config;
271
272         config.max_rules = MAX_RULES;
273         config.number_tbl8s = NUMBER_TBL8S;
274         config.flags = 0;
275
276         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
277         TEST_LPM_ASSERT(lpm != NULL);
278
279         rte_lpm6_free(lpm);
280         rte_lpm6_free(NULL);
281         return PASS;
282 }
283
284 /*
285  * Check that rte_lpm6_add fails gracefully for incorrect user input arguments
286  */
287 int32_t
288 test4(void)
289 {
290         struct rte_lpm6 *lpm = NULL;
291         struct rte_lpm6_config config;
292
293         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
294         uint8_t depth = 24, next_hop = 100;
295         int32_t status = 0;
296
297         config.max_rules = MAX_RULES;
298         config.number_tbl8s = NUMBER_TBL8S;
299         config.flags = 0;
300
301         /* rte_lpm6_add: lpm == NULL */
302         status = rte_lpm6_add(NULL, ip, depth, next_hop);
303         TEST_LPM_ASSERT(status < 0);
304
305         /*Create vaild lpm to use in rest of test. */
306         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
307         TEST_LPM_ASSERT(lpm != NULL);
308
309         /* rte_lpm6_add: depth < 1 */
310         status = rte_lpm6_add(lpm, ip, 0, next_hop);
311         TEST_LPM_ASSERT(status < 0);
312
313         /* rte_lpm6_add: depth > MAX_DEPTH */
314         status = rte_lpm6_add(lpm, ip, (MAX_DEPTH + 1), next_hop);
315         TEST_LPM_ASSERT(status < 0);
316
317         rte_lpm6_free(lpm);
318
319         return PASS;
320 }
321
322 /*
323  * Check that rte_lpm6_delete fails gracefully for incorrect user input
324  * arguments
325  */
326 int32_t
327 test5(void)
328 {
329         struct rte_lpm6 *lpm = NULL;
330         struct rte_lpm6_config config;
331         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
332         uint8_t depth = 24;
333         int32_t status = 0;
334
335         config.max_rules = MAX_RULES;
336         config.number_tbl8s = NUMBER_TBL8S;
337         config.flags = 0;
338
339         /* rte_lpm_delete: lpm == NULL */
340         status = rte_lpm6_delete(NULL, ip, depth);
341         TEST_LPM_ASSERT(status < 0);
342
343         /*Create vaild lpm to use in rest of test. */
344         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
345         TEST_LPM_ASSERT(lpm != NULL);
346
347         /* rte_lpm_delete: depth < 1 */
348         status = rte_lpm6_delete(lpm, ip, 0);
349         TEST_LPM_ASSERT(status < 0);
350
351         /* rte_lpm_delete: depth > MAX_DEPTH */
352         status = rte_lpm6_delete(lpm, ip, (MAX_DEPTH + 1));
353         TEST_LPM_ASSERT(status < 0);
354
355         rte_lpm6_free(lpm);
356
357         return PASS;
358 }
359
360 /*
361  * Check that rte_lpm6_lookup fails gracefully for incorrect user input
362  * arguments
363  */
364 int32_t
365 test6(void)
366 {
367         struct rte_lpm6 *lpm = NULL;
368         struct rte_lpm6_config config;
369         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
370         uint8_t next_hop_return = 0;
371         int32_t status = 0;
372
373         config.max_rules = MAX_RULES;
374         config.number_tbl8s = NUMBER_TBL8S;
375         config.flags = 0;
376
377         /* rte_lpm6_lookup: lpm == NULL */
378         status = rte_lpm6_lookup(NULL, ip, &next_hop_return);
379         TEST_LPM_ASSERT(status < 0);
380
381         /*Create vaild lpm to use in rest of test. */
382         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
383         TEST_LPM_ASSERT(lpm != NULL);
384
385         /* rte_lpm6_lookup: ip = NULL */
386         status = rte_lpm6_lookup(lpm, NULL, &next_hop_return);
387         TEST_LPM_ASSERT(status < 0);
388
389         /* rte_lpm6_lookup: next_hop = NULL */
390         status = rte_lpm6_lookup(lpm, ip, NULL);
391         TEST_LPM_ASSERT(status < 0);
392
393         rte_lpm6_free(lpm);
394
395         return PASS;
396 }
397
398 /*
399  * Checks that rte_lpm6_lookup_bulk_func fails gracefully for incorrect user
400  * input arguments
401  */
402 int32_t
403 test7(void)
404 {
405         struct rte_lpm6 *lpm = NULL;
406         struct rte_lpm6_config config;
407         uint8_t ip[10][16];
408         int16_t next_hop_return[10];
409         int32_t status = 0;
410
411         config.max_rules = MAX_RULES;
412         config.number_tbl8s = NUMBER_TBL8S;
413         config.flags = 0;
414
415         /* rte_lpm6_lookup: lpm == NULL */
416         status = rte_lpm6_lookup_bulk_func(NULL, ip, next_hop_return, 10);
417         TEST_LPM_ASSERT(status < 0);
418
419         /*Create vaild lpm to use in rest of test. */
420         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
421         TEST_LPM_ASSERT(lpm != NULL);
422
423         /* rte_lpm6_lookup: ip = NULL */
424         status = rte_lpm6_lookup_bulk_func(lpm, NULL, next_hop_return, 10);
425         TEST_LPM_ASSERT(status < 0);
426
427         /* rte_lpm6_lookup: next_hop = NULL */
428         status = rte_lpm6_lookup_bulk_func(lpm, ip, NULL, 10);
429         TEST_LPM_ASSERT(status < 0);
430
431         rte_lpm6_free(lpm);
432
433         return PASS;
434 }
435
436 /*
437  * Checks that rte_lpm6_delete_bulk_func fails gracefully for incorrect user
438  * input arguments
439  */
440 int32_t
441 test8(void)
442 {
443         struct rte_lpm6 *lpm = NULL;
444         struct rte_lpm6_config config;
445         uint8_t ip[10][16];
446         uint8_t depth[10];
447         int32_t status = 0;
448
449         config.max_rules = MAX_RULES;
450         config.number_tbl8s = NUMBER_TBL8S;
451         config.flags = 0;
452
453         /* rte_lpm6_delete: lpm == NULL */
454         status = rte_lpm6_delete_bulk_func(NULL, ip, depth, 10);
455         TEST_LPM_ASSERT(status < 0);
456
457         /*Create vaild lpm to use in rest of test. */
458         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
459         TEST_LPM_ASSERT(lpm != NULL);
460
461         /* rte_lpm6_delete: ip = NULL */
462         status = rte_lpm6_delete_bulk_func(lpm, NULL, depth, 10);
463         TEST_LPM_ASSERT(status < 0);
464
465         /* rte_lpm6_delete: next_hop = NULL */
466         status = rte_lpm6_delete_bulk_func(lpm, ip, NULL, 10);
467         TEST_LPM_ASSERT(status < 0);
468
469         rte_lpm6_free(lpm);
470
471         return PASS;
472 }
473
474 /*
475  * Call add, lookup and delete for a single rule with depth < 24.
476  * Check all the combinations for the first three bytes that result in a hit.
477  * Delete the rule and check that the same test returs a miss.
478  */
479 int32_t
480 test9(void)
481 {
482         struct rte_lpm6 *lpm = NULL;
483         struct rte_lpm6_config config;
484         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
485         uint8_t depth = 16, next_hop_add = 100, next_hop_return = 0;
486         int32_t status = 0;
487         uint8_t i;
488
489         config.max_rules = MAX_RULES;
490         config.number_tbl8s = NUMBER_TBL8S;
491         config.flags = 0;
492
493         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
494         TEST_LPM_ASSERT(lpm != NULL);
495
496         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
497         TEST_LPM_ASSERT(status == 0);
498
499         for (i = 0; i < UINT8_MAX; i++) {
500                 ip[2] = i;
501                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
502                 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
503         }
504
505         status = rte_lpm6_delete(lpm, ip, depth);
506         TEST_LPM_ASSERT(status == 0);
507
508         for (i = 0; i < UINT8_MAX; i++) {
509                 ip[2] = i;
510                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
511                 TEST_LPM_ASSERT(status == -ENOENT);
512         }
513
514         rte_lpm6_free(lpm);
515
516         return PASS;
517 }
518
519 /*
520  * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds
521  * another one and expects success.
522  */
523 int32_t
524 test10(void)
525 {
526         struct rte_lpm6 *lpm = NULL;
527         struct rte_lpm6_config config;
528         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
529         uint8_t depth, next_hop_add = 100;
530         int32_t status = 0;
531         int i;
532
533         config.max_rules = 127;
534         config.number_tbl8s = NUMBER_TBL8S;
535         config.flags = 0;
536
537         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
538         TEST_LPM_ASSERT(lpm != NULL);
539
540         for (i = 1; i < 128; i++) {
541                 depth = (uint8_t)i;
542                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
543                 TEST_LPM_ASSERT(status == 0);
544         }
545
546         depth = 128;
547         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
548         TEST_LPM_ASSERT(status == -ENOSPC);
549
550         depth = 127;
551         status = rte_lpm6_delete(lpm, ip, depth);
552         TEST_LPM_ASSERT(status == 0);
553
554         depth = 128;
555         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
556         TEST_LPM_ASSERT(status == 0);
557
558         rte_lpm6_free(lpm);
559
560         return PASS;
561 }
562
563 /*
564  * Creates an LPM table with a small number of tbl8s and exhaust them in the
565  * middle of the process of creating a rule.
566  */
567 int32_t
568 test11(void)
569 {
570         struct rte_lpm6 *lpm = NULL;
571         struct rte_lpm6_config config;
572         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
573         uint8_t depth, next_hop_add = 100;
574         int32_t status = 0;
575
576         config.max_rules = MAX_RULES;
577         config.number_tbl8s = 16;
578         config.flags = 0;
579
580         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
581         TEST_LPM_ASSERT(lpm != NULL);
582
583         depth = 128;
584         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
585         TEST_LPM_ASSERT(status == 0);
586
587         ip[0] = 1;
588         depth = 25;
589         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
590         TEST_LPM_ASSERT(status == 0);
591
592         status = rte_lpm6_delete(lpm, ip, depth);
593         TEST_LPM_ASSERT(status == 0);
594
595         depth = 33;
596         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
597         TEST_LPM_ASSERT(status == 0);
598
599         status = rte_lpm6_delete(lpm, ip, depth);
600         TEST_LPM_ASSERT(status == 0);
601
602         depth = 41;
603         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
604         TEST_LPM_ASSERT(status == 0);
605
606         status = rte_lpm6_delete(lpm, ip, depth);
607         TEST_LPM_ASSERT(status == 0);
608
609         depth = 49;
610         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
611         TEST_LPM_ASSERT(status == -ENOSPC);
612
613         depth = 41;
614         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
615         TEST_LPM_ASSERT(status == 0);
616
617         rte_lpm6_free(lpm);
618
619         return PASS;
620 }
621
622 /*
623  * Creates an LPM table with a small number of tbl8s and exhaust them in the
624  * middle of the process of adding a rule when there is already an existing rule
625  * in that position and needs to be extended.
626  */
627 int32_t
628 test12(void)
629 {
630         struct rte_lpm6 *lpm = NULL;
631         struct rte_lpm6_config config;
632         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
633         uint8_t depth, next_hop_add = 100;
634         int32_t status = 0;
635
636         config.max_rules = MAX_RULES;
637         config.number_tbl8s = 16;
638         config.flags = 0;
639
640         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
641         TEST_LPM_ASSERT(lpm != NULL);
642
643         depth = 128;
644         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
645         TEST_LPM_ASSERT(status == 0);
646
647         ip[0] = 1;
648         depth = 41;
649         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
650         TEST_LPM_ASSERT(status == 0);
651
652         depth = 49;
653         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
654         TEST_LPM_ASSERT(status == -ENOSPC);
655
656         rte_lpm6_free(lpm);
657
658         return PASS;
659 }
660
661 /*
662  * Creates an LPM table with max_rules = 2 and tries to add 3 rules.
663  * Delete one of the rules and tries to add the third one again.
664  */
665 int32_t
666 test13(void)
667 {
668         struct rte_lpm6 *lpm = NULL;
669         struct rte_lpm6_config config;
670         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
671         uint8_t depth, next_hop_add = 100;
672         int32_t status = 0;
673
674         config.max_rules = 2;
675         config.number_tbl8s = NUMBER_TBL8S;
676         config.flags = 0;
677
678         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
679         TEST_LPM_ASSERT(lpm != NULL);
680
681         depth = 1;
682         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
683         TEST_LPM_ASSERT(status == 0);
684
685         depth = 2;
686         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
687         TEST_LPM_ASSERT(status == 0);
688
689         depth = 3;
690         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
691         TEST_LPM_ASSERT(status == -ENOSPC);
692
693         depth = 2;
694         status = rte_lpm6_delete(lpm, ip, depth);
695         TEST_LPM_ASSERT(status == 0);
696
697         depth = 3;
698         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
699         TEST_LPM_ASSERT(status == 0);
700
701         rte_lpm6_free(lpm);
702
703         return PASS;
704 }
705
706 /*
707  * Add 2^16 routes with different first 16 bits and depth 25.
708  * Add one more route with the same depth and check that results in a failure.
709  * After that delete the last rule and create the one that was attempted to be
710  * created. This checks tbl8 exhaustion.
711  */
712 int32_t
713 test14(void)
714 {
715         struct rte_lpm6 *lpm = NULL;
716         struct rte_lpm6_config config;
717         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
718         uint8_t depth = 25, next_hop_add = 100;
719         int32_t status = 0;
720         int i, j;
721
722         config.max_rules = MAX_RULES;
723         config.number_tbl8s = NUMBER_TBL8S;
724         config.flags = 0;
725
726         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
727         TEST_LPM_ASSERT(lpm != NULL);
728
729         for (i = 0; i < 256; i++) {
730                 ip[0] = (uint8_t)i;
731                 for (j = 0; j < 256; j++) {
732                         ip[1] = (uint8_t)j;
733                         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
734                         TEST_LPM_ASSERT(status == 0);
735                 }
736         }
737
738         ip[0] = 255;
739         ip[1] = 255;
740         ip[2] = 1;
741         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
742         TEST_LPM_ASSERT(status == -ENOSPC);
743
744         ip[0] = 255;
745         ip[1] = 255;
746         ip[2] = 0;
747         status = rte_lpm6_delete(lpm, ip, depth);
748         TEST_LPM_ASSERT(status == 0);
749
750         ip[0] = 255;
751         ip[1] = 255;
752         ip[2] = 1;
753         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
754         TEST_LPM_ASSERT(status == 0);
755
756         rte_lpm6_free(lpm);
757
758         return PASS;
759 }
760
761 /*
762  * Call add, lookup and delete for a single rule with depth = 24
763  */
764 int32_t
765 test15(void)
766 {
767         struct rte_lpm6 *lpm = NULL;
768         struct rte_lpm6_config config;
769         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
770         uint8_t depth = 24, next_hop_add = 100, next_hop_return = 0;
771         int32_t status = 0;
772
773         config.max_rules = MAX_RULES;
774         config.number_tbl8s = NUMBER_TBL8S;
775         config.flags = 0;
776
777         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
778         TEST_LPM_ASSERT(lpm != NULL);
779
780         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
781         TEST_LPM_ASSERT(status == 0);
782
783         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
784         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
785
786         status = rte_lpm6_delete(lpm, ip, depth);
787         TEST_LPM_ASSERT(status == 0);
788
789         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
790         TEST_LPM_ASSERT(status == -ENOENT);
791
792         rte_lpm6_free(lpm);
793
794         return PASS;
795 }
796
797 /*
798  * Call add, lookup and delete for a single rule with depth > 24
799  */
800 int32_t
801 test16(void)
802 {
803         struct rte_lpm6 *lpm = NULL;
804         struct rte_lpm6_config config;
805         uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0};
806         uint8_t depth = 128, next_hop_add = 100, next_hop_return = 0;
807         int32_t status = 0;
808
809         config.max_rules = MAX_RULES;
810         config.number_tbl8s = NUMBER_TBL8S;
811         config.flags = 0;
812
813         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
814         TEST_LPM_ASSERT(lpm != NULL);
815
816         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
817         TEST_LPM_ASSERT(status == 0);
818
819         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
820         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
821
822         status = rte_lpm6_delete(lpm, ip, depth);
823         TEST_LPM_ASSERT(status == 0);
824
825         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
826         TEST_LPM_ASSERT(status == -ENOENT);
827
828         rte_lpm6_free(lpm);
829
830         return PASS;
831 }
832
833 /*
834  * Use rte_lpm6_add to add rules which effect only the second half of the lpm
835  * table. Use all possible depths ranging from 1..32. Set the next hop = to the
836  * depth. Check lookup hit for on every add and check for lookup miss on the
837  * first half of the lpm table after each add. Finally delete all rules going
838  * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
839  * delete. The lookup should return the next_hop_add value related to the
840  * previous depth value (i.e. depth -1).
841  */
842 int32_t
843 test17(void)
844 {
845         struct rte_lpm6 *lpm = NULL;
846         struct rte_lpm6_config config;
847         uint8_t ip1[] = {127,255,255,255,255,255,255,255,255,
848                         255,255,255,255,255,255,255};
849         uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
850         uint8_t depth, next_hop_add, next_hop_return;
851         int32_t status = 0;
852
853         config.max_rules = MAX_RULES;
854         config.number_tbl8s = NUMBER_TBL8S;
855         config.flags = 0;
856
857         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
858         TEST_LPM_ASSERT(lpm != NULL);
859
860         /* Loop with rte_lpm6_add. */
861         for (depth = 1; depth <= 128; depth++) {
862                 /* Let the next_hop_add value = depth. Just for change. */
863                 next_hop_add = depth;
864
865                 status = rte_lpm6_add(lpm, ip2, depth, next_hop_add);
866                 TEST_LPM_ASSERT(status == 0);
867
868                 /* Check IP in first half of tbl24 which should be empty. */
869                 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
870                 TEST_LPM_ASSERT(status == -ENOENT);
871
872                 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
873                 TEST_LPM_ASSERT((status == 0) &&
874                         (next_hop_return == next_hop_add));
875         }
876
877         /* Loop with rte_lpm6_delete. */
878         for (depth = 128; depth >= 1; depth--) {
879                 next_hop_add = (uint8_t) (depth - 1);
880
881                 status = rte_lpm6_delete(lpm, ip2, depth);
882                 TEST_LPM_ASSERT(status == 0);
883
884                 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
885
886                 if (depth != 1) {
887                         TEST_LPM_ASSERT((status == 0) &&
888                                 (next_hop_return == next_hop_add));
889                 }
890                 else {
891                         TEST_LPM_ASSERT(status == -ENOENT);
892                 }
893
894                 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
895                 TEST_LPM_ASSERT(status == -ENOENT);
896         }
897
898         rte_lpm6_free(lpm);
899
900         return PASS;
901 }
902
903 /*
904  * - Add & lookup to hit invalid TBL24 entry
905  * - Add & lookup to hit valid TBL24 entry not extended
906  * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
907  * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
908  */
909 int32_t
910 test18(void)
911 {
912         struct rte_lpm6 *lpm = NULL;
913         struct rte_lpm6_config config;
914         uint8_t ip[16], ip_1[16], ip_2[16];
915         uint8_t depth, depth_1, depth_2, next_hop_add, next_hop_add_1,
916                 next_hop_add_2, next_hop_return;
917         int32_t status = 0;
918
919         config.max_rules = MAX_RULES;
920         config.number_tbl8s = NUMBER_TBL8S;
921         config.flags = 0;
922
923         /* Add & lookup to hit invalid TBL24 entry */
924         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
925         depth = 24;
926         next_hop_add = 100;
927
928         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
929         TEST_LPM_ASSERT(lpm != NULL);
930
931         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
932         TEST_LPM_ASSERT(status == 0);
933
934         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
935         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
936
937         status = rte_lpm6_delete(lpm, ip, depth);
938         TEST_LPM_ASSERT(status == 0);
939
940         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
941         TEST_LPM_ASSERT(status == -ENOENT);
942
943         rte_lpm6_delete_all(lpm);
944
945         /* Add & lookup to hit valid TBL24 entry not extended */
946         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
947         depth = 23;
948         next_hop_add = 100;
949
950         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
951         TEST_LPM_ASSERT(status == 0);
952
953         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
954         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
955
956         depth = 24;
957         next_hop_add = 101;
958
959         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
960         TEST_LPM_ASSERT(status == 0);
961
962         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
963         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
964
965         depth = 24;
966
967         status = rte_lpm6_delete(lpm, ip, depth);
968         TEST_LPM_ASSERT(status == 0);
969
970         depth = 23;
971
972         status = rte_lpm6_delete(lpm, ip, depth);
973         TEST_LPM_ASSERT(status == 0);
974
975         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
976         TEST_LPM_ASSERT(status == -ENOENT);
977
978         rte_lpm6_delete_all(lpm);
979
980         /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
981          * entry.
982          */
983         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
984         depth = 32;
985         next_hop_add = 100;
986
987         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
988         TEST_LPM_ASSERT(status == 0);
989
990         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
991         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
992
993         IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
994         depth = 32;
995         next_hop_add = 101;
996
997         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
998         TEST_LPM_ASSERT(status == 0);
999
1000         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1001         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1002
1003         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1004         depth = 32;
1005         next_hop_add = 100;
1006
1007         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1008         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1009
1010         status = rte_lpm6_delete(lpm, ip, depth);
1011         TEST_LPM_ASSERT(status == 0);
1012
1013         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1014         TEST_LPM_ASSERT(status == -ENOENT);
1015
1016         rte_lpm6_delete_all(lpm);
1017
1018         /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
1019          * entry
1020          */
1021         IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1022         depth_1 = 25;
1023         next_hop_add_1 = 101;
1024
1025         IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1026         depth_2 = 32;
1027         next_hop_add_2 = 102;
1028
1029         next_hop_return = 0;
1030
1031         status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1);
1032         TEST_LPM_ASSERT(status == 0);
1033
1034         status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1035         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1036
1037         status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_2);
1038         TEST_LPM_ASSERT(status == 0);
1039
1040         status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1041         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
1042
1043         status = rte_lpm6_delete(lpm, ip_2, depth_2);
1044         TEST_LPM_ASSERT(status == 0);
1045
1046         status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1047         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1048
1049         status = rte_lpm6_delete(lpm, ip_1, depth_1);
1050         TEST_LPM_ASSERT(status == 0);
1051
1052         status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1053         TEST_LPM_ASSERT(status == -ENOENT);
1054
1055         rte_lpm6_free(lpm);
1056
1057         return PASS;
1058 }
1059
1060 /*
1061  * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
1062  *   lookup)
1063  * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
1064  * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
1065  *   delete & lookup)
1066  * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
1067  * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
1068  * - Delete a rule that is not present in the TBL24 & lookup
1069  * - Delete a rule that is not present in the TBL8 & lookup
1070  */
1071 int32_t
1072 test19(void)
1073 {
1074         struct rte_lpm6 *lpm = NULL;
1075         struct rte_lpm6_config config;
1076         uint8_t ip[16];
1077         uint8_t depth, next_hop_add, next_hop_return;
1078         int32_t status = 0;
1079
1080         config.max_rules = MAX_RULES;
1081         config.number_tbl8s = NUMBER_TBL8S;
1082         config.flags = 0;
1083
1084         /* Add rule that covers a TBL24 range previously invalid & lookup
1085          * (& delete & lookup)
1086          */
1087         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1088         TEST_LPM_ASSERT(lpm != NULL);
1089
1090         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1091         depth = 16;
1092         next_hop_add = 100;
1093
1094         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1095         TEST_LPM_ASSERT(status == 0);
1096
1097         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1098         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1099
1100         status = rte_lpm6_delete(lpm, ip, depth);
1101         TEST_LPM_ASSERT(status == 0);
1102
1103         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1104         TEST_LPM_ASSERT(status == -ENOENT);
1105
1106         rte_lpm6_delete_all(lpm);
1107
1108         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1109         depth = 25;
1110         next_hop_add = 100;
1111
1112         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1113         TEST_LPM_ASSERT(status == 0);
1114
1115         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1116         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1117
1118         status = rte_lpm6_delete(lpm, ip, depth);
1119         TEST_LPM_ASSERT(status == 0);
1120
1121         rte_lpm6_delete_all(lpm);
1122
1123         /*
1124          * Add rule that extends a TBL24 valid entry & lookup for both rules
1125          * (& delete & lookup)
1126          */
1127
1128         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1129         depth = 24;
1130         next_hop_add = 100;
1131
1132         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1133         TEST_LPM_ASSERT(status == 0);
1134
1135         IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1136         depth = 32;
1137         next_hop_add = 101;
1138
1139         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1140         TEST_LPM_ASSERT(status == 0);
1141
1142         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1143         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1144
1145         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1146         next_hop_add = 100;
1147
1148         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1149         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1150
1151         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1152         depth = 24;
1153
1154         status = rte_lpm6_delete(lpm, ip, depth);
1155         TEST_LPM_ASSERT(status == 0);
1156
1157         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1158         TEST_LPM_ASSERT(status == -ENOENT);
1159
1160         IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1161         depth = 32;
1162
1163         status = rte_lpm6_delete(lpm, ip, depth);
1164         TEST_LPM_ASSERT(status == 0);
1165
1166         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1167         TEST_LPM_ASSERT(status == -ENOENT);
1168
1169         rte_lpm6_delete_all(lpm);
1170
1171         /*
1172          * Add rule that updates the next hop in TBL24 & lookup
1173          * (& delete & lookup)
1174          */
1175
1176         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1177         depth = 24;
1178         next_hop_add = 100;
1179
1180         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1181         TEST_LPM_ASSERT(status == 0);
1182
1183         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1184         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1185
1186         next_hop_add = 101;
1187
1188         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1189         TEST_LPM_ASSERT(status == 0);
1190
1191         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1192         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1193
1194         status = rte_lpm6_delete(lpm, ip, depth);
1195         TEST_LPM_ASSERT(status == 0);
1196
1197         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1198         TEST_LPM_ASSERT(status == -ENOENT);
1199
1200         rte_lpm6_delete_all(lpm);
1201
1202         /*
1203          * Add rule that updates the next hop in TBL8 & lookup
1204          * (& delete & lookup)
1205          */
1206
1207         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1208         depth = 32;
1209         next_hop_add = 100;
1210
1211         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1212         TEST_LPM_ASSERT(status == 0);
1213
1214         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1215         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1216
1217         next_hop_add = 101;
1218
1219         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1220         TEST_LPM_ASSERT(status == 0);
1221
1222         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1223         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1224
1225         status = rte_lpm6_delete(lpm, ip, depth);
1226         TEST_LPM_ASSERT(status == 0);
1227
1228         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1229         TEST_LPM_ASSERT(status == -ENOENT);
1230
1231         rte_lpm6_delete_all(lpm);
1232
1233         /* Delete a rule that is not present in the TBL24 & lookup */
1234
1235         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1236         depth = 24;
1237         next_hop_add = 100;
1238
1239         status = rte_lpm6_delete(lpm, ip, depth);
1240         TEST_LPM_ASSERT(status < 0);
1241
1242         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1243         TEST_LPM_ASSERT(status == -ENOENT);
1244
1245         rte_lpm6_delete_all(lpm);
1246
1247         /* Delete a rule that is not present in the TBL8 & lookup */
1248
1249         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1250         depth = 32;
1251         next_hop_add = 100;
1252
1253         status = rte_lpm6_delete(lpm, ip, depth);
1254         TEST_LPM_ASSERT(status < 0);
1255
1256         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1257         TEST_LPM_ASSERT(status == -ENOENT);
1258
1259         rte_lpm6_free(lpm);
1260
1261         return PASS;
1262 }
1263
1264 /*
1265  * Add two rules, lookup to hit the more specific one, lookup to hit the less
1266  * specific one delete the less specific rule and lookup previous values again;
1267  * add a more specific rule than the existing rule, lookup again
1268  */
1269 int32_t
1270 test20(void)
1271 {
1272         struct rte_lpm6 *lpm = NULL;
1273         struct rte_lpm6_config config;
1274         uint8_t ip[16];
1275         uint8_t depth, next_hop_add, next_hop_return;
1276         int32_t status = 0;
1277
1278         config.max_rules = MAX_RULES;
1279         config.number_tbl8s = NUMBER_TBL8S;
1280         config.flags = 0;
1281
1282         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1283         TEST_LPM_ASSERT(lpm != NULL);
1284
1285         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1286         depth = 24;
1287         next_hop_add = 100;
1288
1289         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1290         TEST_LPM_ASSERT(status == 0);
1291
1292         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1293         depth = 128;
1294         next_hop_add = 101;
1295
1296         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1297         TEST_LPM_ASSERT(status == 0);
1298
1299         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1300         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1301
1302         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1303         next_hop_add = 100;
1304
1305         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1306         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1307
1308         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1309         depth = 24;
1310
1311         status = rte_lpm6_delete(lpm, ip, depth);
1312         TEST_LPM_ASSERT(status == 0);
1313
1314         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1315         TEST_LPM_ASSERT(status == -ENOENT);
1316
1317         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1318         depth = 128;
1319
1320         status = rte_lpm6_delete(lpm, ip, depth);
1321         TEST_LPM_ASSERT(status == 0);
1322
1323         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1324         TEST_LPM_ASSERT(status == -ENOENT);
1325
1326         rte_lpm6_free(lpm);
1327
1328         return PASS;
1329 }
1330
1331 /*
1332  * Adds 3 rules and look them up through the lookup_bulk function.
1333  * Includes in the lookup a fourth IP address that won't match
1334  * and checks that the result is as expected.
1335  */
1336 int32_t
1337 test21(void)
1338 {
1339         struct rte_lpm6 *lpm = NULL;
1340         struct rte_lpm6_config config;
1341         uint8_t ip_batch[4][16];
1342         uint8_t depth, next_hop_add;
1343         int16_t next_hop_return[4];
1344         int32_t status = 0;
1345
1346         config.max_rules = MAX_RULES;
1347         config.number_tbl8s = NUMBER_TBL8S;
1348         config.flags = 0;
1349
1350         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1351         TEST_LPM_ASSERT(lpm != NULL);
1352
1353         IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1354         depth = 48;
1355         next_hop_add = 100;
1356
1357         status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add);
1358         TEST_LPM_ASSERT(status == 0);
1359
1360         IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1361         depth = 48;
1362         next_hop_add = 101;
1363
1364         status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add);
1365         TEST_LPM_ASSERT(status == 0);
1366
1367         IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1368         depth = 48;
1369         next_hop_add = 102;
1370
1371         status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add);
1372         TEST_LPM_ASSERT(status == 0);
1373
1374         IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1375
1376         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1377                         next_hop_return, 4);
1378         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100
1379                         && next_hop_return[1] == 101 && next_hop_return[2] == 102
1380                         && next_hop_return[3] == -1);
1381
1382         rte_lpm6_free(lpm);
1383
1384         return PASS;
1385 }
1386
1387 /*
1388  * Adds 5 rules and look them up.
1389  * Use the delete_bulk function to delete two of them. Lookup again.
1390  * Use the delete_bulk function to delete one more. Lookup again.
1391  * Use the delete_bulk function to delete two more, one invalid. Lookup again.
1392  * Use the delete_bulk function to delete the remaining one. Lookup again.
1393  */
1394 int32_t
1395 test22(void)
1396 {
1397         struct rte_lpm6 *lpm = NULL;
1398         struct rte_lpm6_config config;
1399         uint8_t ip_batch[5][16];
1400         uint8_t depth[5], next_hop_add;
1401         int16_t next_hop_return[5];
1402         int32_t status = 0;
1403
1404         config.max_rules = MAX_RULES;
1405         config.number_tbl8s = NUMBER_TBL8S;
1406         config.flags = 0;
1407
1408         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1409         TEST_LPM_ASSERT(lpm != NULL);
1410
1411         /* Adds 5 rules and look them up */
1412
1413         IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1414         depth[0] = 48;
1415         next_hop_add = 101;
1416
1417         status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add);
1418         TEST_LPM_ASSERT(status == 0);
1419
1420         IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1421         depth[1] = 48;
1422         next_hop_add = 102;
1423
1424         status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add);
1425         TEST_LPM_ASSERT(status == 0);
1426
1427         IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1428         depth[2] = 48;
1429         next_hop_add = 103;
1430
1431         status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add);
1432         TEST_LPM_ASSERT(status == 0);
1433
1434         IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1435         depth[3] = 48;
1436         next_hop_add = 104;
1437
1438         status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add);
1439         TEST_LPM_ASSERT(status == 0);
1440
1441         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1442         depth[4] = 48;
1443         next_hop_add = 105;
1444
1445         status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add);
1446         TEST_LPM_ASSERT(status == 0);
1447
1448         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1449                         next_hop_return, 5);
1450         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101
1451                         && next_hop_return[1] == 102 && next_hop_return[2] == 103
1452                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1453
1454         /* Use the delete_bulk function to delete two of them. Lookup again */
1455
1456         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2);
1457         TEST_LPM_ASSERT(status == 0);
1458
1459         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1460                         next_hop_return, 5);
1461         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1462                         && next_hop_return[1] == -1 && next_hop_return[2] == 103
1463                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1464
1465         /* Use the delete_bulk function to delete one more. Lookup again */
1466
1467         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1);
1468         TEST_LPM_ASSERT(status == 0);
1469
1470         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1471                         next_hop_return, 5);
1472         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1473                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1474                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1475
1476         /* Use the delete_bulk function to delete two, one invalid. Lookup again */
1477
1478         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1479         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2);
1480         TEST_LPM_ASSERT(status == 0);
1481
1482         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1483         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1484                         next_hop_return, 5);
1485         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1486                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1487                         && next_hop_return[3] == -1 && next_hop_return[4] == 105);
1488
1489         /* Use the delete_bulk function to delete the remaining one. Lookup again */
1490
1491         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1);
1492         TEST_LPM_ASSERT(status == 0);
1493
1494         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1495                         next_hop_return, 5);
1496         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1497                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1498                         && next_hop_return[3] == -1 && next_hop_return[4] == -1);
1499
1500         rte_lpm6_free(lpm);
1501
1502         return PASS;
1503 }
1504
1505 /*
1506  * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
1507  * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension
1508  * and contraction.
1509  */
1510 int32_t
1511 test23(void)
1512 {
1513         struct rte_lpm6 *lpm = NULL;
1514         struct rte_lpm6_config config;
1515         uint32_t i;
1516         uint8_t ip[16];
1517         uint8_t depth, next_hop_add, next_hop_return;
1518         int32_t status = 0;
1519
1520         config.max_rules = MAX_RULES;
1521         config.number_tbl8s = NUMBER_TBL8S;
1522         config.flags = 0;
1523
1524         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1525         TEST_LPM_ASSERT(lpm != NULL);
1526
1527         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1528         depth = 128;
1529         next_hop_add = 100;
1530
1531         for (i = 0; i < 1000; i++) {
1532                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1533                 TEST_LPM_ASSERT(status == 0);
1534
1535                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1536                 TEST_LPM_ASSERT((status == 0) &&
1537                                 (next_hop_return == next_hop_add));
1538
1539                 status = rte_lpm6_delete(lpm, ip, depth);
1540                 TEST_LPM_ASSERT(status == 0);
1541
1542                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1543                 TEST_LPM_ASSERT(status == -ENOENT);
1544         }
1545
1546         rte_lpm6_free(lpm);
1547
1548         return PASS;
1549 }
1550
1551 /*
1552  * Sequence of operations for find existing lpm table
1553  *
1554  *  - create table
1555  *  - find existing table: hit
1556  *  - find non-existing table: miss
1557  */
1558 int32_t
1559 test24(void)
1560 {
1561         struct rte_lpm6 *lpm = NULL, *result = NULL;
1562         struct rte_lpm6_config config;
1563
1564         config.max_rules = 256 * 32;
1565         config.number_tbl8s = NUMBER_TBL8S;
1566         config.flags = 0;
1567
1568         /* Create lpm  */
1569         lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1570         TEST_LPM_ASSERT(lpm != NULL);
1571
1572         /* Try to find existing lpm */
1573         result = rte_lpm6_find_existing("lpm_find_existing");
1574         TEST_LPM_ASSERT(result == lpm);
1575
1576         /* Try to find non-existing lpm */
1577         result = rte_lpm6_find_existing("lpm_find_non_existing");
1578         TEST_LPM_ASSERT(result == NULL);
1579
1580         /* Cleanup. */
1581         rte_lpm6_delete_all(lpm);
1582         rte_lpm6_free(lpm);
1583
1584         return PASS;
1585 }
1586
1587 /*
1588  * Add a set of random routes with random depths.
1589  * Lookup different IP addresses that match the routes previously added.
1590  * Checks that the next hop is the expected one.
1591  * The routes, IP addresses and expected result for every case have been
1592  * precalculated by using a python script and stored in a .h file.
1593  */
1594 int32_t
1595 test25(void)
1596 {
1597         struct rte_lpm6 *lpm = NULL;
1598         struct rte_lpm6_config config;
1599         uint8_t ip[16];
1600         uint32_t i;
1601         uint8_t depth, next_hop_add, next_hop_return, next_hop_expected;
1602         int32_t status = 0;
1603
1604         config.max_rules = MAX_RULES;
1605         config.number_tbl8s = NUMBER_TBL8S;
1606         config.flags = 0;
1607
1608         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1609         TEST_LPM_ASSERT(lpm != NULL);
1610
1611         for (i = 0; i < 1000; i++) {
1612                 memcpy(ip, large_route_table[i].ip, 16);
1613                 depth = large_route_table[i].depth;
1614                 next_hop_add = large_route_table[i].next_hop;
1615                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1616                 TEST_LPM_ASSERT(status == 0);
1617         }
1618
1619         for (i = 0; i < 100000; i++) {
1620                 memcpy(ip, large_ips_table[i].ip, 16);
1621                 next_hop_expected = large_ips_table[i].next_hop;
1622
1623                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1624                 TEST_LPM_ASSERT((status == 0) &&
1625                                 (next_hop_return == next_hop_expected));
1626         }
1627
1628         rte_lpm6_free(lpm);
1629
1630         return PASS;
1631 }
1632
1633 /*
1634  * Test for overwriting of tbl8:
1635  *  - add rule /32 and lookup
1636  *  - add new rule /24 and lookup
1637  *      - add third rule /25 and lookup
1638  *      - lookup /32 and /24 rule to ensure the table has not been overwritten.
1639  */
1640 int32_t
1641 test26(void)
1642 {
1643         struct rte_lpm6 *lpm = NULL;
1644         struct rte_lpm6_config config;
1645         uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1646         uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1647         uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1648         uint8_t d_ip_10_32 = 32;
1649         uint8_t d_ip_10_24 = 24;
1650         uint8_t d_ip_20_25 = 25;
1651         uint8_t next_hop_ip_10_32 = 100;
1652         uint8_t next_hop_ip_10_24 = 105;
1653         uint8_t next_hop_ip_20_25 = 111;
1654         uint8_t next_hop_return = 0;
1655         int32_t status = 0;
1656
1657         config.max_rules = MAX_RULES;
1658         config.number_tbl8s = NUMBER_TBL8S;
1659         config.flags = 0;
1660
1661         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1662         TEST_LPM_ASSERT(lpm != NULL);
1663
1664         if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32,
1665                         next_hop_ip_10_32)) < 0)
1666                 return -1;
1667
1668         status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1669         uint8_t test_hop_10_32 = next_hop_return;
1670         TEST_LPM_ASSERT(status == 0);
1671         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1672
1673         if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24,
1674                         next_hop_ip_10_24)) < 0)
1675                         return -1;
1676
1677         status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1678         uint8_t test_hop_10_24 = next_hop_return;
1679         TEST_LPM_ASSERT(status == 0);
1680         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1681
1682         if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25,
1683                         next_hop_ip_20_25)) < 0)
1684                 return -1;
1685
1686         status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return);
1687         uint8_t test_hop_20_25 = next_hop_return;
1688         TEST_LPM_ASSERT(status == 0);
1689         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1690
1691         if (test_hop_10_32 == test_hop_10_24) {
1692                 printf("Next hop return equal\n");
1693                 return -1;
1694         }
1695
1696         if (test_hop_10_24 == test_hop_20_25){
1697                 printf("Next hop return equal\n");
1698                 return -1;
1699         }
1700
1701         status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1702         TEST_LPM_ASSERT(status == 0);
1703         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1704
1705         status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1706         TEST_LPM_ASSERT(status == 0);
1707         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1708
1709         rte_lpm6_free(lpm);
1710
1711         return PASS;
1712 }
1713
1714 /*
1715  * Add a rule that reaches the end of the tree.
1716  * Add a rule that is more generic than the first one.
1717  * Check every possible combination that produces a match for the second rule.
1718  * This tests tbl expansion.
1719  */
1720 int32_t
1721 test27(void)
1722 {
1723                 struct rte_lpm6 *lpm = NULL;
1724                 struct rte_lpm6_config config;
1725                 uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0};
1726                 uint8_t depth = 128, next_hop_add = 100, next_hop_return;
1727                 int32_t status = 0;
1728                 int i, j;
1729
1730                 config.max_rules = MAX_RULES;
1731                 config.number_tbl8s = NUMBER_TBL8S;
1732                 config.flags = 0;
1733
1734                 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1735                 TEST_LPM_ASSERT(lpm != NULL);
1736
1737                 depth = 128;
1738                 next_hop_add = 128;
1739                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1740                 TEST_LPM_ASSERT(status == 0);
1741
1742                 depth = 112;
1743                 next_hop_add = 112;
1744                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1745                 TEST_LPM_ASSERT(status == 0);
1746
1747                 for (i = 0; i < 256; i++) {
1748                         ip[14] = (uint8_t)i;
1749                         for (j = 0; j < 256; j++) {
1750                                 ip[15] = (uint8_t)j;
1751                                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1752                                 if (i == 0 && j == 0)
1753                                         TEST_LPM_ASSERT(status == 0 && next_hop_return == 128);
1754                                 else
1755                                         TEST_LPM_ASSERT(status == 0 && next_hop_return == 112);
1756                                 }
1757                 }
1758
1759                 rte_lpm6_free(lpm);
1760
1761                 return PASS;
1762 }
1763
1764 /*
1765  * Lookup performance test
1766  */
1767
1768 #define ITERATIONS (1 << 10)
1769 #define BATCH_SIZE 100000
1770
1771 static void
1772 print_route_distribution(const struct rules_tbl_entry *table, uint32_t n)
1773 {
1774         unsigned i, j;
1775
1776         printf("Route distribution per prefix width: \n");
1777         printf("DEPTH    QUANTITY (PERCENT)\n");
1778         printf("--------------------------- \n");
1779
1780         /* Count depths. */
1781         for(i = 1; i <= 128; i++) {
1782                 unsigned depth_counter = 0;
1783                 double percent_hits;
1784
1785                 for (j = 0; j < n; j++)
1786                         if (table[j].depth == (uint8_t) i)
1787                                 depth_counter++;
1788
1789                 percent_hits = ((double)depth_counter)/((double)n) * 100;
1790                 printf("%.2u%15u (%.2f)\n", i, depth_counter, percent_hits);
1791         }
1792         printf("\n");
1793 }
1794
1795 int32_t
1796 perf_test(void)
1797 {
1798         struct rte_lpm6 *lpm = NULL;
1799         struct rte_lpm6_config config;
1800         uint64_t begin, total_time;
1801         unsigned i, j;
1802         uint8_t next_hop_add = 0xAA, next_hop_return = 0;
1803         int status = 0;
1804         int64_t count = 0;
1805
1806         config.max_rules = 1000000;
1807         config.number_tbl8s = NUMBER_TBL8S;
1808         config.flags = 0;
1809
1810         rte_srand(rte_rdtsc());
1811
1812         printf("No. routes = %u\n", (unsigned) NUM_ROUTE_ENTRIES);
1813
1814         print_route_distribution(large_route_table, (uint32_t) NUM_ROUTE_ENTRIES);
1815
1816         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1817         TEST_LPM_ASSERT(lpm != NULL);
1818
1819         /* Measure add. */
1820         begin = rte_rdtsc();
1821
1822         for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1823                 if (rte_lpm6_add(lpm, large_route_table[i].ip,
1824                                 large_route_table[i].depth, next_hop_add) == 0)
1825                         status++;
1826         }
1827         /* End Timer. */
1828         total_time = rte_rdtsc() - begin;
1829
1830         printf("Unique added entries = %d\n", status);
1831         printf("Average LPM Add: %g cycles\n",
1832                         (double)total_time / NUM_ROUTE_ENTRIES);
1833
1834         /* Measure single Lookup */
1835         total_time = 0;
1836         count = 0;
1837
1838         for (i = 0; i < ITERATIONS; i ++) {
1839                 begin = rte_rdtsc();
1840
1841                 for (j = 0; j < NUM_IPS_ENTRIES; j ++) {
1842                         if (rte_lpm6_lookup(lpm, large_ips_table[j].ip,
1843                                         &next_hop_return) != 0)
1844                                 count++;
1845                 }
1846
1847                 total_time += rte_rdtsc() - begin;
1848
1849         }
1850         printf("Average LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1851                         (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1852                         (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1853
1854         /* Measure bulk Lookup */
1855         total_time = 0;
1856         count = 0;
1857
1858         uint8_t ip_batch[NUM_IPS_ENTRIES][16];
1859         int16_t next_hops[NUM_IPS_ENTRIES];
1860
1861         for (i = 0; i < NUM_IPS_ENTRIES; i++)
1862                 memcpy(ip_batch[i], large_ips_table[i].ip, 16);
1863
1864         for (i = 0; i < ITERATIONS; i ++) {
1865
1866                 /* Lookup per batch */
1867                 begin = rte_rdtsc();
1868                 rte_lpm6_lookup_bulk_func(lpm, ip_batch, next_hops, NUM_IPS_ENTRIES);
1869                 total_time += rte_rdtsc() - begin;
1870
1871                 for (j = 0; j < NUM_IPS_ENTRIES; j++)
1872                         if (next_hops[j] < 0)
1873                                 count++;
1874         }
1875         printf("BULK LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1876                         (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1877                         (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1878
1879         /* Delete */
1880         status = 0;
1881         begin = rte_rdtsc();
1882
1883         for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1884                 /* rte_lpm_delete(lpm, ip, depth) */
1885                 status += rte_lpm6_delete(lpm, large_route_table[i].ip,
1886                                 large_route_table[i].depth);
1887         }
1888
1889         total_time += rte_rdtsc() - begin;
1890
1891         printf("Average LPM Delete: %g cycles\n",
1892                         (double)total_time / NUM_ROUTE_ENTRIES);
1893
1894         rte_lpm6_delete_all(lpm);
1895         rte_lpm6_free(lpm);
1896
1897         return PASS;
1898 }
1899
1900 /*
1901  * Do all unit and performance tests.
1902  */
1903 static int
1904 test_lpm6(void)
1905 {
1906         unsigned i;
1907         int status = -1, global_status = 0;
1908
1909         for (i = 0; i < NUM_LPM6_TESTS; i++) {
1910                 status = tests6[i]();
1911
1912                 if (status < 0) {
1913                         printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i]));
1914                         global_status = status;
1915                 }
1916         }
1917
1918         return global_status;
1919 }
1920
1921 static struct test_command lpm6_cmd = {
1922         .command = "lpm6_autotest",
1923         .callback = test_lpm6,
1924 };
1925 REGISTER_TEST_COMMAND(lpm6_cmd);