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