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