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