app/test: shorten execution time
[dpdk.git] / app / test / test_lpm6.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
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_routes.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
83 rte_lpm6_test tests6[] = {
84 /* Test Cases */
85         test0,
86         test1,
87         test2,
88         test3,
89         test4,
90         test5,
91         test6,
92         test7,
93         test8,
94         test9,
95         test10,
96         test11,
97         test12,
98         test13,
99         test14,
100         test15,
101         test16,
102         test17,
103         test18,
104         test19,
105         test20,
106         test21,
107         test22,
108         test23,
109         test24,
110         test25,
111         test26,
112         test27,
113 };
114
115 #define NUM_LPM6_TESTS                (sizeof(tests6)/sizeof(tests6[0]))
116 #define RTE_LPM6_TBL24_NUM_ENTRIES                             (1 << 24)
117 #define RTE_LPM6_LOOKUP_SUCCESS                               0x04000000
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         uint8_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         int16_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, next_hop_add = 100, next_hop_return = 0;
475         int32_t status = 0;
476         uint8_t i;
477
478         config.max_rules = MAX_RULES;
479         config.number_tbl8s = NUMBER_TBL8S;
480         config.flags = 0;
481
482         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
483         TEST_LPM_ASSERT(lpm != NULL);
484
485         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
486         TEST_LPM_ASSERT(status == 0);
487
488         for (i = 0; i < UINT8_MAX; i++) {
489                 ip[2] = i;
490                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
491                 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
492         }
493
494         status = rte_lpm6_delete(lpm, ip, depth);
495         TEST_LPM_ASSERT(status == 0);
496
497         for (i = 0; i < UINT8_MAX; i++) {
498                 ip[2] = i;
499                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
500                 TEST_LPM_ASSERT(status == -ENOENT);
501         }
502
503         rte_lpm6_free(lpm);
504
505         return PASS;
506 }
507
508 /*
509  * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds
510  * another one and expects success.
511  */
512 int32_t
513 test10(void)
514 {
515         struct rte_lpm6 *lpm = NULL;
516         struct rte_lpm6_config config;
517         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
518         uint8_t depth, next_hop_add = 100;
519         int32_t status = 0;
520         int i;
521
522         config.max_rules = 127;
523         config.number_tbl8s = NUMBER_TBL8S;
524         config.flags = 0;
525
526         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
527         TEST_LPM_ASSERT(lpm != NULL);
528
529         for (i = 1; i < 128; i++) {
530                 depth = (uint8_t)i;
531                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
532                 TEST_LPM_ASSERT(status == 0);
533         }
534
535         depth = 128;
536         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
537         TEST_LPM_ASSERT(status == -ENOSPC);
538
539         depth = 127;
540         status = rte_lpm6_delete(lpm, ip, depth);
541         TEST_LPM_ASSERT(status == 0);
542
543         depth = 128;
544         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
545         TEST_LPM_ASSERT(status == 0);
546
547         rte_lpm6_free(lpm);
548
549         return PASS;
550 }
551
552 /*
553  * Creates an LPM table with a small number of tbl8s and exhaust them in the
554  * middle of the process of creating a rule.
555  */
556 int32_t
557 test11(void)
558 {
559         struct rte_lpm6 *lpm = NULL;
560         struct rte_lpm6_config config;
561         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
562         uint8_t depth, next_hop_add = 100;
563         int32_t status = 0;
564
565         config.max_rules = MAX_RULES;
566         config.number_tbl8s = 16;
567         config.flags = 0;
568
569         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
570         TEST_LPM_ASSERT(lpm != NULL);
571
572         depth = 128;
573         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
574         TEST_LPM_ASSERT(status == 0);
575
576         ip[0] = 1;
577         depth = 25;
578         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
579         TEST_LPM_ASSERT(status == 0);
580
581         status = rte_lpm6_delete(lpm, ip, depth);
582         TEST_LPM_ASSERT(status == 0);
583
584         depth = 33;
585         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
586         TEST_LPM_ASSERT(status == 0);
587
588         status = rte_lpm6_delete(lpm, ip, depth);
589         TEST_LPM_ASSERT(status == 0);
590
591         depth = 41;
592         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
593         TEST_LPM_ASSERT(status == 0);
594
595         status = rte_lpm6_delete(lpm, ip, depth);
596         TEST_LPM_ASSERT(status == 0);
597
598         depth = 49;
599         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
600         TEST_LPM_ASSERT(status == -ENOSPC);
601
602         depth = 41;
603         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
604         TEST_LPM_ASSERT(status == 0);
605
606         rte_lpm6_free(lpm);
607
608         return PASS;
609 }
610
611 /*
612  * Creates an LPM table with a small number of tbl8s and exhaust them in the
613  * middle of the process of adding a rule when there is already an existing rule
614  * in that position and needs to be extended.
615  */
616 int32_t
617 test12(void)
618 {
619         struct rte_lpm6 *lpm = NULL;
620         struct rte_lpm6_config config;
621         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
622         uint8_t depth, next_hop_add = 100;
623         int32_t status = 0;
624
625         config.max_rules = MAX_RULES;
626         config.number_tbl8s = 16;
627         config.flags = 0;
628
629         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
630         TEST_LPM_ASSERT(lpm != NULL);
631
632         depth = 128;
633         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
634         TEST_LPM_ASSERT(status == 0);
635
636         ip[0] = 1;
637         depth = 41;
638         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
639         TEST_LPM_ASSERT(status == 0);
640
641         depth = 49;
642         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
643         TEST_LPM_ASSERT(status == -ENOSPC);
644
645         rte_lpm6_free(lpm);
646
647         return PASS;
648 }
649
650 /*
651  * Creates an LPM table with max_rules = 2 and tries to add 3 rules.
652  * Delete one of the rules and tries to add the third one again.
653  */
654 int32_t
655 test13(void)
656 {
657         struct rte_lpm6 *lpm = NULL;
658         struct rte_lpm6_config config;
659         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
660         uint8_t depth, next_hop_add = 100;
661         int32_t status = 0;
662
663         config.max_rules = 2;
664         config.number_tbl8s = NUMBER_TBL8S;
665         config.flags = 0;
666
667         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
668         TEST_LPM_ASSERT(lpm != NULL);
669
670         depth = 1;
671         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
672         TEST_LPM_ASSERT(status == 0);
673
674         depth = 2;
675         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
676         TEST_LPM_ASSERT(status == 0);
677
678         depth = 3;
679         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
680         TEST_LPM_ASSERT(status == -ENOSPC);
681
682         depth = 2;
683         status = rte_lpm6_delete(lpm, ip, depth);
684         TEST_LPM_ASSERT(status == 0);
685
686         depth = 3;
687         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
688         TEST_LPM_ASSERT(status == 0);
689
690         rte_lpm6_free(lpm);
691
692         return PASS;
693 }
694
695 /*
696  * Add 2^12 routes with different first 12 bits and depth 25.
697  * Add one more route with the same depth and check that results in a failure.
698  * After that delete the last rule and create the one that was attempted to be
699  * created. This checks tbl8 exhaustion.
700  */
701 int32_t
702 test14(void)
703 {
704         struct rte_lpm6 *lpm = NULL;
705         struct rte_lpm6_config config;
706         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
707         uint8_t depth = 25, next_hop_add = 100;
708         int32_t status = 0;
709         int i;
710
711         config.max_rules = MAX_RULES;
712         config.number_tbl8s = 256;
713         config.flags = 0;
714
715         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
716         TEST_LPM_ASSERT(lpm != NULL);
717
718         for (i = 0; i < 256; i++) {
719                 ip[0] = (uint8_t)i;
720                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
721                 TEST_LPM_ASSERT(status == 0);
722         }
723
724         ip[0] = 255;
725         ip[1] = 1;
726         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
727         TEST_LPM_ASSERT(status == -ENOSPC);
728
729         ip[0] = 255;
730         ip[1] = 0;
731         status = rte_lpm6_delete(lpm, ip, depth);
732         TEST_LPM_ASSERT(status == 0);
733
734         ip[0] = 255;
735         ip[1] = 1;
736         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
737         TEST_LPM_ASSERT(status == 0);
738
739         rte_lpm6_free(lpm);
740
741         return PASS;
742 }
743
744 /*
745  * Call add, lookup and delete for a single rule with depth = 24
746  */
747 int32_t
748 test15(void)
749 {
750         struct rte_lpm6 *lpm = NULL;
751         struct rte_lpm6_config config;
752         uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
753         uint8_t depth = 24, next_hop_add = 100, next_hop_return = 0;
754         int32_t status = 0;
755
756         config.max_rules = MAX_RULES;
757         config.number_tbl8s = NUMBER_TBL8S;
758         config.flags = 0;
759
760         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
761         TEST_LPM_ASSERT(lpm != NULL);
762
763         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
764         TEST_LPM_ASSERT(status == 0);
765
766         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
767         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
768
769         status = rte_lpm6_delete(lpm, ip, depth);
770         TEST_LPM_ASSERT(status == 0);
771
772         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
773         TEST_LPM_ASSERT(status == -ENOENT);
774
775         rte_lpm6_free(lpm);
776
777         return PASS;
778 }
779
780 /*
781  * Call add, lookup and delete for a single rule with depth > 24
782  */
783 int32_t
784 test16(void)
785 {
786         struct rte_lpm6 *lpm = NULL;
787         struct rte_lpm6_config config;
788         uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0};
789         uint8_t depth = 128, next_hop_add = 100, next_hop_return = 0;
790         int32_t status = 0;
791
792         config.max_rules = MAX_RULES;
793         config.number_tbl8s = NUMBER_TBL8S;
794         config.flags = 0;
795
796         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
797         TEST_LPM_ASSERT(lpm != NULL);
798
799         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
800         TEST_LPM_ASSERT(status == 0);
801
802         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
803         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
804
805         status = rte_lpm6_delete(lpm, ip, depth);
806         TEST_LPM_ASSERT(status == 0);
807
808         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
809         TEST_LPM_ASSERT(status == -ENOENT);
810
811         rte_lpm6_free(lpm);
812
813         return PASS;
814 }
815
816 /*
817  * Use rte_lpm6_add to add rules which effect only the second half of the lpm
818  * table. Use all possible depths ranging from 1..32. Set the next hop = to the
819  * depth. Check lookup hit for on every add and check for lookup miss on the
820  * first half of the lpm table after each add. Finally delete all rules going
821  * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
822  * delete. The lookup should return the next_hop_add value related to the
823  * previous depth value (i.e. depth -1).
824  */
825 int32_t
826 test17(void)
827 {
828         struct rte_lpm6 *lpm = NULL;
829         struct rte_lpm6_config config;
830         uint8_t ip1[] = {127,255,255,255,255,255,255,255,255,
831                         255,255,255,255,255,255,255};
832         uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
833         uint8_t depth, next_hop_add, next_hop_return;
834         int32_t status = 0;
835
836         config.max_rules = MAX_RULES;
837         config.number_tbl8s = NUMBER_TBL8S;
838         config.flags = 0;
839
840         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
841         TEST_LPM_ASSERT(lpm != NULL);
842
843         /* Loop with rte_lpm6_add. */
844         for (depth = 1; depth <= 16; depth++) {
845                 /* Let the next_hop_add value = depth. Just for change. */
846                 next_hop_add = depth;
847
848                 status = rte_lpm6_add(lpm, ip2, depth, next_hop_add);
849                 TEST_LPM_ASSERT(status == 0);
850
851                 /* Check IP in first half of tbl24 which should be empty. */
852                 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
853                 TEST_LPM_ASSERT(status == -ENOENT);
854
855                 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
856                 TEST_LPM_ASSERT((status == 0) &&
857                         (next_hop_return == next_hop_add));
858         }
859
860         /* Loop with rte_lpm6_delete. */
861         for (depth = 16; depth >= 1; depth--) {
862                 next_hop_add = (uint8_t) (depth - 1);
863
864                 status = rte_lpm6_delete(lpm, ip2, depth);
865                 TEST_LPM_ASSERT(status == 0);
866
867                 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
868
869                 if (depth != 1) {
870                         TEST_LPM_ASSERT((status == 0) &&
871                                 (next_hop_return == next_hop_add));
872                 }
873                 else {
874                         TEST_LPM_ASSERT(status == -ENOENT);
875                 }
876
877                 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
878                 TEST_LPM_ASSERT(status == -ENOENT);
879         }
880
881         rte_lpm6_free(lpm);
882
883         return PASS;
884 }
885
886 /*
887  * - Add & lookup to hit invalid TBL24 entry
888  * - Add & lookup to hit valid TBL24 entry not extended
889  * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
890  * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
891  */
892 int32_t
893 test18(void)
894 {
895         struct rte_lpm6 *lpm = NULL;
896         struct rte_lpm6_config config;
897         uint8_t ip[16], ip_1[16], ip_2[16];
898         uint8_t depth, depth_1, depth_2, next_hop_add, next_hop_add_1,
899                 next_hop_add_2, next_hop_return;
900         int32_t status = 0;
901
902         config.max_rules = MAX_RULES;
903         config.number_tbl8s = NUMBER_TBL8S;
904         config.flags = 0;
905
906         /* Add & lookup to hit invalid TBL24 entry */
907         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
908         depth = 24;
909         next_hop_add = 100;
910
911         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
912         TEST_LPM_ASSERT(lpm != NULL);
913
914         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
915         TEST_LPM_ASSERT(status == 0);
916
917         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
918         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
919
920         status = rte_lpm6_delete(lpm, ip, depth);
921         TEST_LPM_ASSERT(status == 0);
922
923         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
924         TEST_LPM_ASSERT(status == -ENOENT);
925
926         rte_lpm6_delete_all(lpm);
927
928         /* Add & lookup to hit valid TBL24 entry not extended */
929         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
930         depth = 23;
931         next_hop_add = 100;
932
933         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
934         TEST_LPM_ASSERT(status == 0);
935
936         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
937         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
938
939         depth = 24;
940         next_hop_add = 101;
941
942         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
943         TEST_LPM_ASSERT(status == 0);
944
945         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
946         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
947
948         depth = 24;
949
950         status = rte_lpm6_delete(lpm, ip, depth);
951         TEST_LPM_ASSERT(status == 0);
952
953         depth = 23;
954
955         status = rte_lpm6_delete(lpm, ip, depth);
956         TEST_LPM_ASSERT(status == 0);
957
958         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
959         TEST_LPM_ASSERT(status == -ENOENT);
960
961         rte_lpm6_delete_all(lpm);
962
963         /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
964          * entry.
965          */
966         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
967         depth = 32;
968         next_hop_add = 100;
969
970         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
971         TEST_LPM_ASSERT(status == 0);
972
973         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
974         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
975
976         IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
977         depth = 32;
978         next_hop_add = 101;
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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
987         depth = 32;
988         next_hop_add = 100;
989
990         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
991         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
992
993         status = rte_lpm6_delete(lpm, ip, depth);
994         TEST_LPM_ASSERT(status == 0);
995
996         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
997         TEST_LPM_ASSERT(status == -ENOENT);
998
999         rte_lpm6_delete_all(lpm);
1000
1001         /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
1002          * entry
1003          */
1004         IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1005         depth_1 = 25;
1006         next_hop_add_1 = 101;
1007
1008         IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1009         depth_2 = 32;
1010         next_hop_add_2 = 102;
1011
1012         next_hop_return = 0;
1013
1014         status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1);
1015         TEST_LPM_ASSERT(status == 0);
1016
1017         status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1018         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1019
1020         status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_2);
1021         TEST_LPM_ASSERT(status == 0);
1022
1023         status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1024         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
1025
1026         status = rte_lpm6_delete(lpm, ip_2, depth_2);
1027         TEST_LPM_ASSERT(status == 0);
1028
1029         status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1030         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1031
1032         status = rte_lpm6_delete(lpm, ip_1, depth_1);
1033         TEST_LPM_ASSERT(status == 0);
1034
1035         status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1036         TEST_LPM_ASSERT(status == -ENOENT);
1037
1038         rte_lpm6_free(lpm);
1039
1040         return PASS;
1041 }
1042
1043 /*
1044  * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
1045  *   lookup)
1046  * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
1047  * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
1048  *   delete & lookup)
1049  * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
1050  * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
1051  * - Delete a rule that is not present in the TBL24 & lookup
1052  * - Delete a rule that is not present in the TBL8 & lookup
1053  */
1054 int32_t
1055 test19(void)
1056 {
1057         struct rte_lpm6 *lpm = NULL;
1058         struct rte_lpm6_config config;
1059         uint8_t ip[16];
1060         uint8_t depth, next_hop_add, next_hop_return;
1061         int32_t status = 0;
1062
1063         config.max_rules = MAX_RULES;
1064         config.number_tbl8s = NUMBER_TBL8S;
1065         config.flags = 0;
1066
1067         /* Add rule that covers a TBL24 range previously invalid & lookup
1068          * (& delete & lookup)
1069          */
1070         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1071         TEST_LPM_ASSERT(lpm != NULL);
1072
1073         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1074         depth = 16;
1075         next_hop_add = 100;
1076
1077         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1078         TEST_LPM_ASSERT(status == 0);
1079
1080         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1081         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1082
1083         status = rte_lpm6_delete(lpm, ip, depth);
1084         TEST_LPM_ASSERT(status == 0);
1085
1086         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1087         TEST_LPM_ASSERT(status == -ENOENT);
1088
1089         rte_lpm6_delete_all(lpm);
1090
1091         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1092         depth = 25;
1093         next_hop_add = 100;
1094
1095         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1096         TEST_LPM_ASSERT(status == 0);
1097
1098         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1099         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1100
1101         status = rte_lpm6_delete(lpm, ip, depth);
1102         TEST_LPM_ASSERT(status == 0);
1103
1104         rte_lpm6_delete_all(lpm);
1105
1106         /*
1107          * Add rule that extends a TBL24 valid entry & lookup for both rules
1108          * (& delete & lookup)
1109          */
1110
1111         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1112         depth = 24;
1113         next_hop_add = 100;
1114
1115         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1116         TEST_LPM_ASSERT(status == 0);
1117
1118         IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1119         depth = 32;
1120         next_hop_add = 101;
1121
1122         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1123         TEST_LPM_ASSERT(status == 0);
1124
1125         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1126         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1127
1128         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1129         next_hop_add = 100;
1130
1131         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1132         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1133
1134         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1135         depth = 24;
1136
1137         status = rte_lpm6_delete(lpm, ip, depth);
1138         TEST_LPM_ASSERT(status == 0);
1139
1140         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1141         TEST_LPM_ASSERT(status == -ENOENT);
1142
1143         IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1144         depth = 32;
1145
1146         status = rte_lpm6_delete(lpm, ip, depth);
1147         TEST_LPM_ASSERT(status == 0);
1148
1149         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1150         TEST_LPM_ASSERT(status == -ENOENT);
1151
1152         rte_lpm6_delete_all(lpm);
1153
1154         /*
1155          * Add rule that updates the next hop in TBL24 & lookup
1156          * (& delete & lookup)
1157          */
1158
1159         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1160         depth = 24;
1161         next_hop_add = 100;
1162
1163         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1164         TEST_LPM_ASSERT(status == 0);
1165
1166         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1167         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1168
1169         next_hop_add = 101;
1170
1171         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1172         TEST_LPM_ASSERT(status == 0);
1173
1174         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1175         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1176
1177         status = rte_lpm6_delete(lpm, ip, depth);
1178         TEST_LPM_ASSERT(status == 0);
1179
1180         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1181         TEST_LPM_ASSERT(status == -ENOENT);
1182
1183         rte_lpm6_delete_all(lpm);
1184
1185         /*
1186          * Add rule that updates the next hop in TBL8 & lookup
1187          * (& delete & lookup)
1188          */
1189
1190         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1191         depth = 32;
1192         next_hop_add = 100;
1193
1194         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1195         TEST_LPM_ASSERT(status == 0);
1196
1197         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1198         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1199
1200         next_hop_add = 101;
1201
1202         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1203         TEST_LPM_ASSERT(status == 0);
1204
1205         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1206         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1207
1208         status = rte_lpm6_delete(lpm, ip, depth);
1209         TEST_LPM_ASSERT(status == 0);
1210
1211         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1212         TEST_LPM_ASSERT(status == -ENOENT);
1213
1214         rte_lpm6_delete_all(lpm);
1215
1216         /* Delete a rule that is not present in the TBL24 & lookup */
1217
1218         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1219         depth = 24;
1220         next_hop_add = 100;
1221
1222         status = rte_lpm6_delete(lpm, ip, depth);
1223         TEST_LPM_ASSERT(status < 0);
1224
1225         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1226         TEST_LPM_ASSERT(status == -ENOENT);
1227
1228         rte_lpm6_delete_all(lpm);
1229
1230         /* Delete a rule that is not present in the TBL8 & lookup */
1231
1232         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1233         depth = 32;
1234         next_hop_add = 100;
1235
1236         status = rte_lpm6_delete(lpm, ip, depth);
1237         TEST_LPM_ASSERT(status < 0);
1238
1239         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1240         TEST_LPM_ASSERT(status == -ENOENT);
1241
1242         rte_lpm6_free(lpm);
1243
1244         return PASS;
1245 }
1246
1247 /*
1248  * Add two rules, lookup to hit the more specific one, lookup to hit the less
1249  * specific one delete the less specific rule and lookup previous values again;
1250  * add a more specific rule than the existing rule, lookup again
1251  */
1252 int32_t
1253 test20(void)
1254 {
1255         struct rte_lpm6 *lpm = NULL;
1256         struct rte_lpm6_config config;
1257         uint8_t ip[16];
1258         uint8_t depth, next_hop_add, next_hop_return;
1259         int32_t status = 0;
1260
1261         config.max_rules = MAX_RULES;
1262         config.number_tbl8s = NUMBER_TBL8S;
1263         config.flags = 0;
1264
1265         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1266         TEST_LPM_ASSERT(lpm != NULL);
1267
1268         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1269         depth = 24;
1270         next_hop_add = 100;
1271
1272         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1273         TEST_LPM_ASSERT(status == 0);
1274
1275         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1276         depth = 128;
1277         next_hop_add = 101;
1278
1279         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1280         TEST_LPM_ASSERT(status == 0);
1281
1282         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1283         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1284
1285         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1286         next_hop_add = 100;
1287
1288         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1289         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1290
1291         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1292         depth = 24;
1293
1294         status = rte_lpm6_delete(lpm, ip, depth);
1295         TEST_LPM_ASSERT(status == 0);
1296
1297         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1298         TEST_LPM_ASSERT(status == -ENOENT);
1299
1300         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1301         depth = 128;
1302
1303         status = rte_lpm6_delete(lpm, ip, depth);
1304         TEST_LPM_ASSERT(status == 0);
1305
1306         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1307         TEST_LPM_ASSERT(status == -ENOENT);
1308
1309         rte_lpm6_free(lpm);
1310
1311         return PASS;
1312 }
1313
1314 /*
1315  * Adds 3 rules and look them up through the lookup_bulk function.
1316  * Includes in the lookup a fourth IP address that won't match
1317  * and checks that the result is as expected.
1318  */
1319 int32_t
1320 test21(void)
1321 {
1322         struct rte_lpm6 *lpm = NULL;
1323         struct rte_lpm6_config config;
1324         uint8_t ip_batch[4][16];
1325         uint8_t depth, next_hop_add;
1326         int16_t next_hop_return[4];
1327         int32_t status = 0;
1328
1329         config.max_rules = MAX_RULES;
1330         config.number_tbl8s = NUMBER_TBL8S;
1331         config.flags = 0;
1332
1333         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1334         TEST_LPM_ASSERT(lpm != NULL);
1335
1336         IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1337         depth = 48;
1338         next_hop_add = 100;
1339
1340         status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add);
1341         TEST_LPM_ASSERT(status == 0);
1342
1343         IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1344         depth = 48;
1345         next_hop_add = 101;
1346
1347         status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add);
1348         TEST_LPM_ASSERT(status == 0);
1349
1350         IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1351         depth = 48;
1352         next_hop_add = 102;
1353
1354         status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add);
1355         TEST_LPM_ASSERT(status == 0);
1356
1357         IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1358
1359         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1360                         next_hop_return, 4);
1361         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100
1362                         && next_hop_return[1] == 101 && next_hop_return[2] == 102
1363                         && next_hop_return[3] == -1);
1364
1365         rte_lpm6_free(lpm);
1366
1367         return PASS;
1368 }
1369
1370 /*
1371  * Adds 5 rules and look them up.
1372  * Use the delete_bulk function to delete two of them. Lookup again.
1373  * Use the delete_bulk function to delete one more. Lookup again.
1374  * Use the delete_bulk function to delete two more, one invalid. Lookup again.
1375  * Use the delete_bulk function to delete the remaining one. Lookup again.
1376  */
1377 int32_t
1378 test22(void)
1379 {
1380         struct rte_lpm6 *lpm = NULL;
1381         struct rte_lpm6_config config;
1382         uint8_t ip_batch[5][16];
1383         uint8_t depth[5], next_hop_add;
1384         int16_t next_hop_return[5];
1385         int32_t status = 0;
1386
1387         config.max_rules = MAX_RULES;
1388         config.number_tbl8s = NUMBER_TBL8S;
1389         config.flags = 0;
1390
1391         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1392         TEST_LPM_ASSERT(lpm != NULL);
1393
1394         /* Adds 5 rules and look them up */
1395
1396         IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1397         depth[0] = 48;
1398         next_hop_add = 101;
1399
1400         status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add);
1401         TEST_LPM_ASSERT(status == 0);
1402
1403         IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1404         depth[1] = 48;
1405         next_hop_add = 102;
1406
1407         status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add);
1408         TEST_LPM_ASSERT(status == 0);
1409
1410         IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1411         depth[2] = 48;
1412         next_hop_add = 103;
1413
1414         status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add);
1415         TEST_LPM_ASSERT(status == 0);
1416
1417         IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1418         depth[3] = 48;
1419         next_hop_add = 104;
1420
1421         status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add);
1422         TEST_LPM_ASSERT(status == 0);
1423
1424         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1425         depth[4] = 48;
1426         next_hop_add = 105;
1427
1428         status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add);
1429         TEST_LPM_ASSERT(status == 0);
1430
1431         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1432                         next_hop_return, 5);
1433         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101
1434                         && next_hop_return[1] == 102 && next_hop_return[2] == 103
1435                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1436
1437         /* Use the delete_bulk function to delete two of them. Lookup again */
1438
1439         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2);
1440         TEST_LPM_ASSERT(status == 0);
1441
1442         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1443                         next_hop_return, 5);
1444         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1445                         && next_hop_return[1] == -1 && next_hop_return[2] == 103
1446                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1447
1448         /* Use the delete_bulk function to delete one more. Lookup again */
1449
1450         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1);
1451         TEST_LPM_ASSERT(status == 0);
1452
1453         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1454                         next_hop_return, 5);
1455         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1456                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1457                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1458
1459         /* Use the delete_bulk function to delete two, one invalid. Lookup again */
1460
1461         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1462         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2);
1463         TEST_LPM_ASSERT(status == 0);
1464
1465         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1466         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1467                         next_hop_return, 5);
1468         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1469                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1470                         && next_hop_return[3] == -1 && next_hop_return[4] == 105);
1471
1472         /* Use the delete_bulk function to delete the remaining one. Lookup again */
1473
1474         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1);
1475         TEST_LPM_ASSERT(status == 0);
1476
1477         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1478                         next_hop_return, 5);
1479         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1480                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1481                         && next_hop_return[3] == -1 && next_hop_return[4] == -1);
1482
1483         rte_lpm6_free(lpm);
1484
1485         return PASS;
1486 }
1487
1488 /*
1489  * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
1490  * lookup (miss) in a for loop of 30 times. This will check tbl8 extension
1491  * and contraction.
1492  */
1493 int32_t
1494 test23(void)
1495 {
1496         struct rte_lpm6 *lpm = NULL;
1497         struct rte_lpm6_config config;
1498         uint32_t i;
1499         uint8_t ip[16];
1500         uint8_t depth, next_hop_add, next_hop_return;
1501         int32_t status = 0;
1502
1503         config.max_rules = MAX_RULES;
1504         config.number_tbl8s = NUMBER_TBL8S;
1505         config.flags = 0;
1506
1507         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1508         TEST_LPM_ASSERT(lpm != NULL);
1509
1510         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1511         depth = 128;
1512         next_hop_add = 100;
1513
1514         for (i = 0; i < 30; i++) {
1515                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1516                 TEST_LPM_ASSERT(status == 0);
1517
1518                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1519                 TEST_LPM_ASSERT((status == 0) &&
1520                                 (next_hop_return == next_hop_add));
1521
1522                 status = rte_lpm6_delete(lpm, ip, depth);
1523                 TEST_LPM_ASSERT(status == 0);
1524
1525                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1526                 TEST_LPM_ASSERT(status == -ENOENT);
1527         }
1528
1529         rte_lpm6_free(lpm);
1530
1531         return PASS;
1532 }
1533
1534 /*
1535  * Sequence of operations for find existing lpm table
1536  *
1537  *  - create table
1538  *  - find existing table: hit
1539  *  - find non-existing table: miss
1540  */
1541 int32_t
1542 test24(void)
1543 {
1544         struct rte_lpm6 *lpm = NULL, *result = NULL;
1545         struct rte_lpm6_config config;
1546
1547         config.max_rules = 256 * 32;
1548         config.number_tbl8s = NUMBER_TBL8S;
1549         config.flags = 0;
1550
1551         /* Create lpm  */
1552         lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1553         TEST_LPM_ASSERT(lpm != NULL);
1554
1555         /* Try to find existing lpm */
1556         result = rte_lpm6_find_existing("lpm_find_existing");
1557         TEST_LPM_ASSERT(result == lpm);
1558
1559         /* Try to find non-existing lpm */
1560         result = rte_lpm6_find_existing("lpm_find_non_existing");
1561         TEST_LPM_ASSERT(result == NULL);
1562
1563         /* Cleanup. */
1564         rte_lpm6_delete_all(lpm);
1565         rte_lpm6_free(lpm);
1566
1567         return PASS;
1568 }
1569
1570 /*
1571  * Add a set of random routes with random depths.
1572  * Lookup different IP addresses that match the routes previously added.
1573  * Checks that the next hop is the expected one.
1574  * The routes, IP addresses and expected result for every case have been
1575  * precalculated by using a python script and stored in a .h file.
1576  */
1577 int32_t
1578 test25(void)
1579 {
1580         struct rte_lpm6 *lpm = NULL;
1581         struct rte_lpm6_config config;
1582         uint8_t ip[16];
1583         uint32_t i;
1584         uint8_t depth, next_hop_add, next_hop_return, next_hop_expected;
1585         int32_t status = 0;
1586
1587         config.max_rules = MAX_RULES;
1588         config.number_tbl8s = NUMBER_TBL8S;
1589         config.flags = 0;
1590
1591         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1592         TEST_LPM_ASSERT(lpm != NULL);
1593
1594         for (i = 0; i < 1000; i++) {
1595                 memcpy(ip, large_route_table[i].ip, 16);
1596                 depth = large_route_table[i].depth;
1597                 next_hop_add = large_route_table[i].next_hop;
1598                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1599                 TEST_LPM_ASSERT(status == 0);
1600         }
1601
1602         for (i = 0; i < 100000; i++) {
1603                 memcpy(ip, large_ips_table[i].ip, 16);
1604                 next_hop_expected = large_ips_table[i].next_hop;
1605
1606                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1607                 TEST_LPM_ASSERT((status == 0) &&
1608                                 (next_hop_return == next_hop_expected));
1609         }
1610
1611         rte_lpm6_free(lpm);
1612
1613         return PASS;
1614 }
1615
1616 /*
1617  * Test for overwriting of tbl8:
1618  *  - add rule /32 and lookup
1619  *  - add new rule /24 and lookup
1620  *      - add third rule /25 and lookup
1621  *      - lookup /32 and /24 rule to ensure the table has not been overwritten.
1622  */
1623 int32_t
1624 test26(void)
1625 {
1626         struct rte_lpm6 *lpm = NULL;
1627         struct rte_lpm6_config config;
1628         uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1629         uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1630         uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1631         uint8_t d_ip_10_32 = 32;
1632         uint8_t d_ip_10_24 = 24;
1633         uint8_t d_ip_20_25 = 25;
1634         uint8_t next_hop_ip_10_32 = 100;
1635         uint8_t next_hop_ip_10_24 = 105;
1636         uint8_t next_hop_ip_20_25 = 111;
1637         uint8_t next_hop_return = 0;
1638         int32_t status = 0;
1639
1640         config.max_rules = MAX_RULES;
1641         config.number_tbl8s = NUMBER_TBL8S;
1642         config.flags = 0;
1643
1644         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1645         TEST_LPM_ASSERT(lpm != NULL);
1646
1647         if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32,
1648                         next_hop_ip_10_32)) < 0)
1649                 return -1;
1650
1651         status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1652         uint8_t test_hop_10_32 = next_hop_return;
1653         TEST_LPM_ASSERT(status == 0);
1654         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1655
1656         if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24,
1657                         next_hop_ip_10_24)) < 0)
1658                         return -1;
1659
1660         status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1661         uint8_t test_hop_10_24 = next_hop_return;
1662         TEST_LPM_ASSERT(status == 0);
1663         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1664
1665         if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25,
1666                         next_hop_ip_20_25)) < 0)
1667                 return -1;
1668
1669         status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return);
1670         uint8_t test_hop_20_25 = next_hop_return;
1671         TEST_LPM_ASSERT(status == 0);
1672         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1673
1674         if (test_hop_10_32 == test_hop_10_24) {
1675                 printf("Next hop return equal\n");
1676                 return -1;
1677         }
1678
1679         if (test_hop_10_24 == test_hop_20_25){
1680                 printf("Next hop return equal\n");
1681                 return -1;
1682         }
1683
1684         status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1685         TEST_LPM_ASSERT(status == 0);
1686         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1687
1688         status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1689         TEST_LPM_ASSERT(status == 0);
1690         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1691
1692         rte_lpm6_free(lpm);
1693
1694         return PASS;
1695 }
1696
1697 /*
1698  * Add a rule that reaches the end of the tree.
1699  * Add a rule that is more generic than the first one.
1700  * Check every possible combination that produces a match for the second rule.
1701  * This tests tbl expansion.
1702  */
1703 int32_t
1704 test27(void)
1705 {
1706                 struct rte_lpm6 *lpm = NULL;
1707                 struct rte_lpm6_config config;
1708                 uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0};
1709                 uint8_t depth = 128, next_hop_add = 100, next_hop_return;
1710                 int32_t status = 0;
1711                 int i, j;
1712
1713                 config.max_rules = MAX_RULES;
1714                 config.number_tbl8s = NUMBER_TBL8S;
1715                 config.flags = 0;
1716
1717                 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1718                 TEST_LPM_ASSERT(lpm != NULL);
1719
1720                 depth = 128;
1721                 next_hop_add = 128;
1722                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1723                 TEST_LPM_ASSERT(status == 0);
1724
1725                 depth = 112;
1726                 next_hop_add = 112;
1727                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1728                 TEST_LPM_ASSERT(status == 0);
1729
1730                 for (i = 0; i < 256; i++) {
1731                         ip[14] = (uint8_t)i;
1732                         for (j = 0; j < 256; j++) {
1733                                 ip[15] = (uint8_t)j;
1734                                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1735                                 if (i == 0 && j == 0)
1736                                         TEST_LPM_ASSERT(status == 0 && next_hop_return == 128);
1737                                 else
1738                                         TEST_LPM_ASSERT(status == 0 && next_hop_return == 112);
1739                                 }
1740                 }
1741
1742                 rte_lpm6_free(lpm);
1743
1744                 return PASS;
1745 }
1746
1747 /*
1748  * Do all unit tests.
1749  */
1750 static int
1751 test_lpm6(void)
1752 {
1753         unsigned i;
1754         int status = -1, global_status = 0;
1755
1756         for (i = 0; i < NUM_LPM6_TESTS; i++) {
1757                 printf("# test %02d\n", i);
1758                 status = tests6[i]();
1759
1760                 if (status < 0) {
1761                         printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i]));
1762                         global_status = status;
1763                 }
1764         }
1765
1766         return global_status;
1767 }
1768
1769 static struct test_command lpm6_cmd = {
1770         .command = "lpm6_autotest",
1771         .callback = test_lpm6,
1772 };
1773 REGISTER_TEST_COMMAND(lpm6_cmd);