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