9163cd7eb021dd52e1c314922c6198e8b789d931
[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 100 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 < 100; 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^16 routes with different first 16 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, j;
710
711         config.max_rules = MAX_RULES;
712         config.number_tbl8s = NUMBER_TBL8S;
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                 for (j = 0; j < 256; j++) {
721                         ip[1] = (uint8_t)j;
722                         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
723                         TEST_LPM_ASSERT(status == 0);
724                 }
725         }
726
727         ip[0] = 255;
728         ip[1] = 255;
729         ip[2] = 1;
730         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
731         TEST_LPM_ASSERT(status == -ENOSPC);
732
733         ip[0] = 255;
734         ip[1] = 255;
735         ip[2] = 0;
736         status = rte_lpm6_delete(lpm, ip, depth);
737         TEST_LPM_ASSERT(status == 0);
738
739         ip[0] = 255;
740         ip[1] = 255;
741         ip[2] = 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, next_hop_add = 100, next_hop_return = 0;
760         int32_t status = 0;
761
762         config.max_rules = MAX_RULES;
763         config.number_tbl8s = NUMBER_TBL8S;
764         config.flags = 0;
765
766         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
767         TEST_LPM_ASSERT(lpm != NULL);
768
769         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
770         TEST_LPM_ASSERT(status == 0);
771
772         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
773         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
774
775         status = rte_lpm6_delete(lpm, ip, depth);
776         TEST_LPM_ASSERT(status == 0);
777
778         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
779         TEST_LPM_ASSERT(status == -ENOENT);
780
781         rte_lpm6_free(lpm);
782
783         return PASS;
784 }
785
786 /*
787  * Call add, lookup and delete for a single rule with depth > 24
788  */
789 int32_t
790 test16(void)
791 {
792         struct rte_lpm6 *lpm = NULL;
793         struct rte_lpm6_config config;
794         uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0};
795         uint8_t depth = 128, next_hop_add = 100, next_hop_return = 0;
796         int32_t status = 0;
797
798         config.max_rules = MAX_RULES;
799         config.number_tbl8s = NUMBER_TBL8S;
800         config.flags = 0;
801
802         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
803         TEST_LPM_ASSERT(lpm != NULL);
804
805         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
806         TEST_LPM_ASSERT(status == 0);
807
808         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
809         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
810
811         status = rte_lpm6_delete(lpm, ip, depth);
812         TEST_LPM_ASSERT(status == 0);
813
814         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
815         TEST_LPM_ASSERT(status == -ENOENT);
816
817         rte_lpm6_free(lpm);
818
819         return PASS;
820 }
821
822 /*
823  * Use rte_lpm6_add to add rules which effect only the second half of the lpm
824  * table. Use all possible depths ranging from 1..32. Set the next hop = to the
825  * depth. Check lookup hit for on every add and check for lookup miss on the
826  * first half of the lpm table after each add. Finally delete all rules going
827  * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
828  * delete. The lookup should return the next_hop_add value related to the
829  * previous depth value (i.e. depth -1).
830  */
831 int32_t
832 test17(void)
833 {
834         struct rte_lpm6 *lpm = NULL;
835         struct rte_lpm6_config config;
836         uint8_t ip1[] = {127,255,255,255,255,255,255,255,255,
837                         255,255,255,255,255,255,255};
838         uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
839         uint8_t depth, next_hop_add, next_hop_return;
840         int32_t status = 0;
841
842         config.max_rules = MAX_RULES;
843         config.number_tbl8s = NUMBER_TBL8S;
844         config.flags = 0;
845
846         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
847         TEST_LPM_ASSERT(lpm != NULL);
848
849         /* Loop with rte_lpm6_add. */
850         for (depth = 1; depth <= 128; depth++) {
851                 /* Let the next_hop_add value = depth. Just for change. */
852                 next_hop_add = depth;
853
854                 status = rte_lpm6_add(lpm, ip2, depth, next_hop_add);
855                 TEST_LPM_ASSERT(status == 0);
856
857                 /* Check IP in first half of tbl24 which should be empty. */
858                 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
859                 TEST_LPM_ASSERT(status == -ENOENT);
860
861                 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
862                 TEST_LPM_ASSERT((status == 0) &&
863                         (next_hop_return == next_hop_add));
864         }
865
866         /* Loop with rte_lpm6_delete. */
867         for (depth = 128; depth >= 1; depth--) {
868                 next_hop_add = (uint8_t) (depth - 1);
869
870                 status = rte_lpm6_delete(lpm, ip2, depth);
871                 TEST_LPM_ASSERT(status == 0);
872
873                 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
874
875                 if (depth != 1) {
876                         TEST_LPM_ASSERT((status == 0) &&
877                                 (next_hop_return == next_hop_add));
878                 }
879                 else {
880                         TEST_LPM_ASSERT(status == -ENOENT);
881                 }
882
883                 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
884                 TEST_LPM_ASSERT(status == -ENOENT);
885         }
886
887         rte_lpm6_free(lpm);
888
889         return PASS;
890 }
891
892 /*
893  * - Add & lookup to hit invalid TBL24 entry
894  * - Add & lookup to hit valid TBL24 entry not extended
895  * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
896  * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
897  */
898 int32_t
899 test18(void)
900 {
901         struct rte_lpm6 *lpm = NULL;
902         struct rte_lpm6_config config;
903         uint8_t ip[16], ip_1[16], ip_2[16];
904         uint8_t depth, depth_1, depth_2, next_hop_add, next_hop_add_1,
905                 next_hop_add_2, next_hop_return;
906         int32_t status = 0;
907
908         config.max_rules = MAX_RULES;
909         config.number_tbl8s = NUMBER_TBL8S;
910         config.flags = 0;
911
912         /* Add & lookup to hit invalid TBL24 entry */
913         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
914         depth = 24;
915         next_hop_add = 100;
916
917         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
918         TEST_LPM_ASSERT(lpm != NULL);
919
920         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
921         TEST_LPM_ASSERT(status == 0);
922
923         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
924         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
925
926         status = rte_lpm6_delete(lpm, ip, depth);
927         TEST_LPM_ASSERT(status == 0);
928
929         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
930         TEST_LPM_ASSERT(status == -ENOENT);
931
932         rte_lpm6_delete_all(lpm);
933
934         /* Add & lookup to hit valid TBL24 entry not extended */
935         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
936         depth = 23;
937         next_hop_add = 100;
938
939         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
940         TEST_LPM_ASSERT(status == 0);
941
942         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
943         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
944
945         depth = 24;
946         next_hop_add = 101;
947
948         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
949         TEST_LPM_ASSERT(status == 0);
950
951         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
952         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
953
954         depth = 24;
955
956         status = rte_lpm6_delete(lpm, ip, depth);
957         TEST_LPM_ASSERT(status == 0);
958
959         depth = 23;
960
961         status = rte_lpm6_delete(lpm, ip, depth);
962         TEST_LPM_ASSERT(status == 0);
963
964         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
965         TEST_LPM_ASSERT(status == -ENOENT);
966
967         rte_lpm6_delete_all(lpm);
968
969         /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
970          * entry.
971          */
972         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
973         depth = 32;
974         next_hop_add = 100;
975
976         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
977         TEST_LPM_ASSERT(status == 0);
978
979         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
980         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
981
982         IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
983         depth = 32;
984         next_hop_add = 101;
985
986         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
987         TEST_LPM_ASSERT(status == 0);
988
989         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
990         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
991
992         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
993         depth = 32;
994         next_hop_add = 100;
995
996         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
997         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
998
999         status = rte_lpm6_delete(lpm, ip, depth);
1000         TEST_LPM_ASSERT(status == 0);
1001
1002         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1003         TEST_LPM_ASSERT(status == -ENOENT);
1004
1005         rte_lpm6_delete_all(lpm);
1006
1007         /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
1008          * entry
1009          */
1010         IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1011         depth_1 = 25;
1012         next_hop_add_1 = 101;
1013
1014         IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1015         depth_2 = 32;
1016         next_hop_add_2 = 102;
1017
1018         next_hop_return = 0;
1019
1020         status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1);
1021         TEST_LPM_ASSERT(status == 0);
1022
1023         status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1024         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1025
1026         status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_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_2));
1031
1032         status = rte_lpm6_delete(lpm, ip_2, depth_2);
1033         TEST_LPM_ASSERT(status == 0);
1034
1035         status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1036         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1037
1038         status = rte_lpm6_delete(lpm, ip_1, depth_1);
1039         TEST_LPM_ASSERT(status == 0);
1040
1041         status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1042         TEST_LPM_ASSERT(status == -ENOENT);
1043
1044         rte_lpm6_free(lpm);
1045
1046         return PASS;
1047 }
1048
1049 /*
1050  * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
1051  *   lookup)
1052  * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
1053  * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
1054  *   delete & lookup)
1055  * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
1056  * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
1057  * - Delete a rule that is not present in the TBL24 & lookup
1058  * - Delete a rule that is not present in the TBL8 & lookup
1059  */
1060 int32_t
1061 test19(void)
1062 {
1063         struct rte_lpm6 *lpm = NULL;
1064         struct rte_lpm6_config config;
1065         uint8_t ip[16];
1066         uint8_t depth, next_hop_add, next_hop_return;
1067         int32_t status = 0;
1068
1069         config.max_rules = MAX_RULES;
1070         config.number_tbl8s = NUMBER_TBL8S;
1071         config.flags = 0;
1072
1073         /* Add rule that covers a TBL24 range previously invalid & lookup
1074          * (& delete & lookup)
1075          */
1076         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1077         TEST_LPM_ASSERT(lpm != NULL);
1078
1079         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1080         depth = 16;
1081         next_hop_add = 100;
1082
1083         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1084         TEST_LPM_ASSERT(status == 0);
1085
1086         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1087         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1088
1089         status = rte_lpm6_delete(lpm, ip, depth);
1090         TEST_LPM_ASSERT(status == 0);
1091
1092         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1093         TEST_LPM_ASSERT(status == -ENOENT);
1094
1095         rte_lpm6_delete_all(lpm);
1096
1097         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1098         depth = 25;
1099         next_hop_add = 100;
1100
1101         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1102         TEST_LPM_ASSERT(status == 0);
1103
1104         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1105         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1106
1107         status = rte_lpm6_delete(lpm, ip, depth);
1108         TEST_LPM_ASSERT(status == 0);
1109
1110         rte_lpm6_delete_all(lpm);
1111
1112         /*
1113          * Add rule that extends a TBL24 valid entry & lookup for both rules
1114          * (& delete & lookup)
1115          */
1116
1117         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1118         depth = 24;
1119         next_hop_add = 100;
1120
1121         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1122         TEST_LPM_ASSERT(status == 0);
1123
1124         IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1125         depth = 32;
1126         next_hop_add = 101;
1127
1128         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1129         TEST_LPM_ASSERT(status == 0);
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         next_hop_add = 100;
1136
1137         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1138         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1139
1140         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1141         depth = 24;
1142
1143         status = rte_lpm6_delete(lpm, ip, depth);
1144         TEST_LPM_ASSERT(status == 0);
1145
1146         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1147         TEST_LPM_ASSERT(status == -ENOENT);
1148
1149         IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1150         depth = 32;
1151
1152         status = rte_lpm6_delete(lpm, ip, depth);
1153         TEST_LPM_ASSERT(status == 0);
1154
1155         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1156         TEST_LPM_ASSERT(status == -ENOENT);
1157
1158         rte_lpm6_delete_all(lpm);
1159
1160         /*
1161          * Add rule that updates the next hop in TBL24 & lookup
1162          * (& delete & lookup)
1163          */
1164
1165         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1166         depth = 24;
1167         next_hop_add = 100;
1168
1169         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1170         TEST_LPM_ASSERT(status == 0);
1171
1172         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1173         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1174
1175         next_hop_add = 101;
1176
1177         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1178         TEST_LPM_ASSERT(status == 0);
1179
1180         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1181         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1182
1183         status = rte_lpm6_delete(lpm, ip, depth);
1184         TEST_LPM_ASSERT(status == 0);
1185
1186         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1187         TEST_LPM_ASSERT(status == -ENOENT);
1188
1189         rte_lpm6_delete_all(lpm);
1190
1191         /*
1192          * Add rule that updates the next hop in TBL8 & lookup
1193          * (& delete & lookup)
1194          */
1195
1196         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1197         depth = 32;
1198         next_hop_add = 100;
1199
1200         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1201         TEST_LPM_ASSERT(status == 0);
1202
1203         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1204         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1205
1206         next_hop_add = 101;
1207
1208         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1209         TEST_LPM_ASSERT(status == 0);
1210
1211         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1212         TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1213
1214         status = rte_lpm6_delete(lpm, ip, depth);
1215         TEST_LPM_ASSERT(status == 0);
1216
1217         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1218         TEST_LPM_ASSERT(status == -ENOENT);
1219
1220         rte_lpm6_delete_all(lpm);
1221
1222         /* Delete a rule that is not present in the TBL24 & lookup */
1223
1224         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1225         depth = 24;
1226         next_hop_add = 100;
1227
1228         status = rte_lpm6_delete(lpm, ip, depth);
1229         TEST_LPM_ASSERT(status < 0);
1230
1231         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1232         TEST_LPM_ASSERT(status == -ENOENT);
1233
1234         rte_lpm6_delete_all(lpm);
1235
1236         /* Delete a rule that is not present in the TBL8 & lookup */
1237
1238         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1239         depth = 32;
1240         next_hop_add = 100;
1241
1242         status = rte_lpm6_delete(lpm, ip, depth);
1243         TEST_LPM_ASSERT(status < 0);
1244
1245         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1246         TEST_LPM_ASSERT(status == -ENOENT);
1247
1248         rte_lpm6_free(lpm);
1249
1250         return PASS;
1251 }
1252
1253 /*
1254  * Add two rules, lookup to hit the more specific one, lookup to hit the less
1255  * specific one delete the less specific rule and lookup previous values again;
1256  * add a more specific rule than the existing rule, lookup again
1257  */
1258 int32_t
1259 test20(void)
1260 {
1261         struct rte_lpm6 *lpm = NULL;
1262         struct rte_lpm6_config config;
1263         uint8_t ip[16];
1264         uint8_t depth, next_hop_add, next_hop_return;
1265         int32_t status = 0;
1266
1267         config.max_rules = MAX_RULES;
1268         config.number_tbl8s = NUMBER_TBL8S;
1269         config.flags = 0;
1270
1271         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1272         TEST_LPM_ASSERT(lpm != NULL);
1273
1274         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1275         depth = 24;
1276         next_hop_add = 100;
1277
1278         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1279         TEST_LPM_ASSERT(status == 0);
1280
1281         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1282         depth = 128;
1283         next_hop_add = 101;
1284
1285         status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1286         TEST_LPM_ASSERT(status == 0);
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         next_hop_add = 100;
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         depth = 24;
1299
1300         status = rte_lpm6_delete(lpm, ip, depth);
1301         TEST_LPM_ASSERT(status == 0);
1302
1303         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1304         TEST_LPM_ASSERT(status == -ENOENT);
1305
1306         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1307         depth = 128;
1308
1309         status = rte_lpm6_delete(lpm, ip, depth);
1310         TEST_LPM_ASSERT(status == 0);
1311
1312         status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1313         TEST_LPM_ASSERT(status == -ENOENT);
1314
1315         rte_lpm6_free(lpm);
1316
1317         return PASS;
1318 }
1319
1320 /*
1321  * Adds 3 rules and look them up through the lookup_bulk function.
1322  * Includes in the lookup a fourth IP address that won't match
1323  * and checks that the result is as expected.
1324  */
1325 int32_t
1326 test21(void)
1327 {
1328         struct rte_lpm6 *lpm = NULL;
1329         struct rte_lpm6_config config;
1330         uint8_t ip_batch[4][16];
1331         uint8_t depth, next_hop_add;
1332         int16_t next_hop_return[4];
1333         int32_t status = 0;
1334
1335         config.max_rules = MAX_RULES;
1336         config.number_tbl8s = NUMBER_TBL8S;
1337         config.flags = 0;
1338
1339         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1340         TEST_LPM_ASSERT(lpm != NULL);
1341
1342         IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1343         depth = 48;
1344         next_hop_add = 100;
1345
1346         status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add);
1347         TEST_LPM_ASSERT(status == 0);
1348
1349         IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1350         depth = 48;
1351         next_hop_add = 101;
1352
1353         status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add);
1354         TEST_LPM_ASSERT(status == 0);
1355
1356         IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1357         depth = 48;
1358         next_hop_add = 102;
1359
1360         status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add);
1361         TEST_LPM_ASSERT(status == 0);
1362
1363         IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1364
1365         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1366                         next_hop_return, 4);
1367         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100
1368                         && next_hop_return[1] == 101 && next_hop_return[2] == 102
1369                         && next_hop_return[3] == -1);
1370
1371         rte_lpm6_free(lpm);
1372
1373         return PASS;
1374 }
1375
1376 /*
1377  * Adds 5 rules and look them up.
1378  * Use the delete_bulk function to delete two of them. Lookup again.
1379  * Use the delete_bulk function to delete one more. Lookup again.
1380  * Use the delete_bulk function to delete two more, one invalid. Lookup again.
1381  * Use the delete_bulk function to delete the remaining one. Lookup again.
1382  */
1383 int32_t
1384 test22(void)
1385 {
1386         struct rte_lpm6 *lpm = NULL;
1387         struct rte_lpm6_config config;
1388         uint8_t ip_batch[5][16];
1389         uint8_t depth[5], next_hop_add;
1390         int16_t next_hop_return[5];
1391         int32_t status = 0;
1392
1393         config.max_rules = MAX_RULES;
1394         config.number_tbl8s = NUMBER_TBL8S;
1395         config.flags = 0;
1396
1397         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1398         TEST_LPM_ASSERT(lpm != NULL);
1399
1400         /* Adds 5 rules and look them up */
1401
1402         IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1403         depth[0] = 48;
1404         next_hop_add = 101;
1405
1406         status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add);
1407         TEST_LPM_ASSERT(status == 0);
1408
1409         IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1410         depth[1] = 48;
1411         next_hop_add = 102;
1412
1413         status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add);
1414         TEST_LPM_ASSERT(status == 0);
1415
1416         IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1417         depth[2] = 48;
1418         next_hop_add = 103;
1419
1420         status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add);
1421         TEST_LPM_ASSERT(status == 0);
1422
1423         IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1424         depth[3] = 48;
1425         next_hop_add = 104;
1426
1427         status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add);
1428         TEST_LPM_ASSERT(status == 0);
1429
1430         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1431         depth[4] = 48;
1432         next_hop_add = 105;
1433
1434         status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add);
1435         TEST_LPM_ASSERT(status == 0);
1436
1437         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1438                         next_hop_return, 5);
1439         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101
1440                         && next_hop_return[1] == 102 && next_hop_return[2] == 103
1441                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1442
1443         /* Use the delete_bulk function to delete two of them. Lookup again */
1444
1445         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2);
1446         TEST_LPM_ASSERT(status == 0);
1447
1448         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1449                         next_hop_return, 5);
1450         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1451                         && next_hop_return[1] == -1 && next_hop_return[2] == 103
1452                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1453
1454         /* Use the delete_bulk function to delete one more. Lookup again */
1455
1456         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1);
1457         TEST_LPM_ASSERT(status == 0);
1458
1459         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1460                         next_hop_return, 5);
1461         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1462                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1463                         && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1464
1465         /* Use the delete_bulk function to delete two, one invalid. Lookup again */
1466
1467         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1468         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2);
1469         TEST_LPM_ASSERT(status == 0);
1470
1471         IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1472         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1473                         next_hop_return, 5);
1474         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1475                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1476                         && next_hop_return[3] == -1 && next_hop_return[4] == 105);
1477
1478         /* Use the delete_bulk function to delete the remaining one. Lookup again */
1479
1480         status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1);
1481         TEST_LPM_ASSERT(status == 0);
1482
1483         status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1484                         next_hop_return, 5);
1485         TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1486                         && next_hop_return[1] == -1 && next_hop_return[2] == -1
1487                         && next_hop_return[3] == -1 && next_hop_return[4] == -1);
1488
1489         rte_lpm6_free(lpm);
1490
1491         return PASS;
1492 }
1493
1494 /*
1495  * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
1496  * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension
1497  * and contraction.
1498  */
1499 int32_t
1500 test23(void)
1501 {
1502         struct rte_lpm6 *lpm = NULL;
1503         struct rte_lpm6_config config;
1504         uint32_t i;
1505         uint8_t ip[16];
1506         uint8_t depth, next_hop_add, next_hop_return;
1507         int32_t status = 0;
1508
1509         config.max_rules = MAX_RULES;
1510         config.number_tbl8s = NUMBER_TBL8S;
1511         config.flags = 0;
1512
1513         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1514         TEST_LPM_ASSERT(lpm != NULL);
1515
1516         IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1517         depth = 128;
1518         next_hop_add = 100;
1519
1520         for (i = 0; i < 1000; i++) {
1521                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1522                 TEST_LPM_ASSERT(status == 0);
1523
1524                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1525                 TEST_LPM_ASSERT((status == 0) &&
1526                                 (next_hop_return == next_hop_add));
1527
1528                 status = rte_lpm6_delete(lpm, ip, depth);
1529                 TEST_LPM_ASSERT(status == 0);
1530
1531                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1532                 TEST_LPM_ASSERT(status == -ENOENT);
1533         }
1534
1535         rte_lpm6_free(lpm);
1536
1537         return PASS;
1538 }
1539
1540 /*
1541  * Sequence of operations for find existing lpm table
1542  *
1543  *  - create table
1544  *  - find existing table: hit
1545  *  - find non-existing table: miss
1546  */
1547 int32_t
1548 test24(void)
1549 {
1550         struct rte_lpm6 *lpm = NULL, *result = NULL;
1551         struct rte_lpm6_config config;
1552
1553         config.max_rules = 256 * 32;
1554         config.number_tbl8s = NUMBER_TBL8S;
1555         config.flags = 0;
1556
1557         /* Create lpm  */
1558         lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1559         TEST_LPM_ASSERT(lpm != NULL);
1560
1561         /* Try to find existing lpm */
1562         result = rte_lpm6_find_existing("lpm_find_existing");
1563         TEST_LPM_ASSERT(result == lpm);
1564
1565         /* Try to find non-existing lpm */
1566         result = rte_lpm6_find_existing("lpm_find_non_existing");
1567         TEST_LPM_ASSERT(result == NULL);
1568
1569         /* Cleanup. */
1570         rte_lpm6_delete_all(lpm);
1571         rte_lpm6_free(lpm);
1572
1573         return PASS;
1574 }
1575
1576 /*
1577  * Add a set of random routes with random depths.
1578  * Lookup different IP addresses that match the routes previously added.
1579  * Checks that the next hop is the expected one.
1580  * The routes, IP addresses and expected result for every case have been
1581  * precalculated by using a python script and stored in a .h file.
1582  */
1583 int32_t
1584 test25(void)
1585 {
1586         struct rte_lpm6 *lpm = NULL;
1587         struct rte_lpm6_config config;
1588         uint8_t ip[16];
1589         uint32_t i;
1590         uint8_t depth, next_hop_add, next_hop_return, next_hop_expected;
1591         int32_t status = 0;
1592
1593         config.max_rules = MAX_RULES;
1594         config.number_tbl8s = NUMBER_TBL8S;
1595         config.flags = 0;
1596
1597         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1598         TEST_LPM_ASSERT(lpm != NULL);
1599
1600         for (i = 0; i < 1000; i++) {
1601                 memcpy(ip, large_route_table[i].ip, 16);
1602                 depth = large_route_table[i].depth;
1603                 next_hop_add = large_route_table[i].next_hop;
1604                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1605                 TEST_LPM_ASSERT(status == 0);
1606         }
1607
1608         for (i = 0; i < 100000; i++) {
1609                 memcpy(ip, large_ips_table[i].ip, 16);
1610                 next_hop_expected = large_ips_table[i].next_hop;
1611
1612                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1613                 TEST_LPM_ASSERT((status == 0) &&
1614                                 (next_hop_return == next_hop_expected));
1615         }
1616
1617         rte_lpm6_free(lpm);
1618
1619         return PASS;
1620 }
1621
1622 /*
1623  * Test for overwriting of tbl8:
1624  *  - add rule /32 and lookup
1625  *  - add new rule /24 and lookup
1626  *      - add third rule /25 and lookup
1627  *      - lookup /32 and /24 rule to ensure the table has not been overwritten.
1628  */
1629 int32_t
1630 test26(void)
1631 {
1632         struct rte_lpm6 *lpm = NULL;
1633         struct rte_lpm6_config config;
1634         uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1635         uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1636         uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1637         uint8_t d_ip_10_32 = 32;
1638         uint8_t d_ip_10_24 = 24;
1639         uint8_t d_ip_20_25 = 25;
1640         uint8_t next_hop_ip_10_32 = 100;
1641         uint8_t next_hop_ip_10_24 = 105;
1642         uint8_t next_hop_ip_20_25 = 111;
1643         uint8_t next_hop_return = 0;
1644         int32_t status = 0;
1645
1646         config.max_rules = MAX_RULES;
1647         config.number_tbl8s = NUMBER_TBL8S;
1648         config.flags = 0;
1649
1650         lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1651         TEST_LPM_ASSERT(lpm != NULL);
1652
1653         if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32,
1654                         next_hop_ip_10_32)) < 0)
1655                 return -1;
1656
1657         status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1658         uint8_t test_hop_10_32 = next_hop_return;
1659         TEST_LPM_ASSERT(status == 0);
1660         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1661
1662         if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24,
1663                         next_hop_ip_10_24)) < 0)
1664                         return -1;
1665
1666         status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1667         uint8_t test_hop_10_24 = next_hop_return;
1668         TEST_LPM_ASSERT(status == 0);
1669         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1670
1671         if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25,
1672                         next_hop_ip_20_25)) < 0)
1673                 return -1;
1674
1675         status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return);
1676         uint8_t test_hop_20_25 = next_hop_return;
1677         TEST_LPM_ASSERT(status == 0);
1678         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1679
1680         if (test_hop_10_32 == test_hop_10_24) {
1681                 printf("Next hop return equal\n");
1682                 return -1;
1683         }
1684
1685         if (test_hop_10_24 == test_hop_20_25){
1686                 printf("Next hop return equal\n");
1687                 return -1;
1688         }
1689
1690         status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1691         TEST_LPM_ASSERT(status == 0);
1692         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1693
1694         status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1695         TEST_LPM_ASSERT(status == 0);
1696         TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1697
1698         rte_lpm6_free(lpm);
1699
1700         return PASS;
1701 }
1702
1703 /*
1704  * Add a rule that reaches the end of the tree.
1705  * Add a rule that is more generic than the first one.
1706  * Check every possible combination that produces a match for the second rule.
1707  * This tests tbl expansion.
1708  */
1709 int32_t
1710 test27(void)
1711 {
1712                 struct rte_lpm6 *lpm = NULL;
1713                 struct rte_lpm6_config config;
1714                 uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0};
1715                 uint8_t depth = 128, next_hop_add = 100, next_hop_return;
1716                 int32_t status = 0;
1717                 int i, j;
1718
1719                 config.max_rules = MAX_RULES;
1720                 config.number_tbl8s = NUMBER_TBL8S;
1721                 config.flags = 0;
1722
1723                 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1724                 TEST_LPM_ASSERT(lpm != NULL);
1725
1726                 depth = 128;
1727                 next_hop_add = 128;
1728                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1729                 TEST_LPM_ASSERT(status == 0);
1730
1731                 depth = 112;
1732                 next_hop_add = 112;
1733                 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1734                 TEST_LPM_ASSERT(status == 0);
1735
1736                 for (i = 0; i < 256; i++) {
1737                         ip[14] = (uint8_t)i;
1738                         for (j = 0; j < 256; j++) {
1739                                 ip[15] = (uint8_t)j;
1740                                 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1741                                 if (i == 0 && j == 0)
1742                                         TEST_LPM_ASSERT(status == 0 && next_hop_return == 128);
1743                                 else
1744                                         TEST_LPM_ASSERT(status == 0 && next_hop_return == 112);
1745                                 }
1746                 }
1747
1748                 rte_lpm6_free(lpm);
1749
1750                 return PASS;
1751 }
1752
1753 /*
1754  * Do all unit tests.
1755  */
1756 static int
1757 test_lpm6(void)
1758 {
1759         unsigned i;
1760         int status = -1, global_status = 0;
1761
1762         for (i = 0; i < NUM_LPM6_TESTS; i++) {
1763                 status = tests6[i]();
1764
1765                 if (status < 0) {
1766                         printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i]));
1767                         global_status = status;
1768                 }
1769         }
1770
1771         return global_status;
1772 }
1773
1774 static struct test_command lpm6_cmd = {
1775         .command = "lpm6_autotest",
1776         .callback = test_lpm6,
1777 };
1778 REGISTER_TEST_COMMAND(lpm6_cmd);