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