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