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