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