4 * Copyright(c) 2010-2013 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 #include <sys/queue.h>
40 #include <cmdline_parse.h>
48 #include <rte_common.h>
49 #include <rte_cycles.h>
50 #include <rte_memory.h>
51 #include <rte_random.h>
52 #include <rte_branch_prediction.h>
56 #include "test_lpm6_routes.h"
58 #define TEST_LPM_ASSERT(cond) do { \
60 printf("Error at line %d: \n", __LINE__); \
65 typedef int32_t (* rte_lpm6_test)(void);
67 static int32_t test0(void);
68 static int32_t test1(void);
69 static int32_t test2(void);
70 static int32_t test3(void);
71 static int32_t test4(void);
72 static int32_t test5(void);
73 static int32_t test6(void);
74 static int32_t test7(void);
75 static int32_t test8(void);
76 static int32_t test9(void);
77 static int32_t test10(void);
78 static int32_t test11(void);
79 static int32_t test12(void);
80 static int32_t test13(void);
81 static int32_t test14(void);
82 static int32_t test15(void);
83 static int32_t test16(void);
84 static int32_t test17(void);
85 static int32_t test18(void);
86 static int32_t test19(void);
87 static int32_t test20(void);
88 static int32_t test21(void);
89 static int32_t test22(void);
90 static int32_t test23(void);
91 static int32_t test24(void);
92 static int32_t test25(void);
93 static int32_t test26(void);
94 static int32_t test27(void);
95 static int32_t perf_test(void);
97 rte_lpm6_test tests6[] = {
130 #define NUM_LPM6_TESTS (sizeof(tests6)/sizeof(tests6[0]))
131 #define RTE_LPM6_TBL24_NUM_ENTRIES (1 << 24)
132 #define RTE_LPM6_LOOKUP_SUCCESS 0x04000000
133 #define MAX_DEPTH 128
134 #define MAX_RULES 1000000
135 #define NUMBER_TBL8S (1 << 16)
136 #define MAX_NUM_TBL8S (1 << 21)
140 IPv6(uint8_t *ip, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5,
141 uint8_t b6, uint8_t b7, uint8_t b8, uint8_t b9, uint8_t b10,
142 uint8_t b11, uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15,
164 * Check that rte_lpm6_create fails gracefully for incorrect user input
170 struct rte_lpm6 *lpm = NULL;
171 struct rte_lpm6_config config;
173 config.max_rules = MAX_RULES;
174 config.number_tbl8s = NUMBER_TBL8S;
177 /* rte_lpm6_create: lpm name == NULL */
178 lpm = rte_lpm6_create(NULL, SOCKET_ID_ANY, &config);
179 TEST_LPM_ASSERT(lpm == NULL);
181 /* rte_lpm6_create: max_rules = 0 */
182 /* Note: __func__ inserts the function name, in this case "test0". */
183 config.max_rules = 0;
184 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
185 TEST_LPM_ASSERT(lpm == NULL);
187 /* socket_id < -1 is invalid */
188 config.max_rules = MAX_RULES;
189 lpm = rte_lpm6_create(__func__, -2, &config);
190 TEST_LPM_ASSERT(lpm == NULL);
192 /* rte_lpm6_create: number_tbl8s is bigger than the maximum */
193 config.number_tbl8s = MAX_NUM_TBL8S + 1;
194 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
195 TEST_LPM_ASSERT(lpm == NULL);
197 /* rte_lpm6_create: config = NULL */
198 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, NULL);
199 TEST_LPM_ASSERT(lpm == NULL);
205 * Creates two different LPM tables. Tries to create a third one with the same
206 * name as the first one and expects the create function to return the same
212 struct rte_lpm6 *lpm1 = NULL, *lpm2 = NULL, *lpm3 = NULL;
213 struct rte_lpm6_config config;
215 config.max_rules = MAX_RULES;
216 config.number_tbl8s = NUMBER_TBL8S;
219 /* rte_lpm6_create: lpm name == LPM1 */
220 lpm1 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
221 TEST_LPM_ASSERT(lpm1 != NULL);
223 /* rte_lpm6_create: lpm name == LPM2 */
224 lpm2 = rte_lpm6_create("LPM2", SOCKET_ID_ANY, &config);
225 TEST_LPM_ASSERT(lpm2 != NULL);
227 /* rte_lpm6_create: lpm name == LPM2 */
228 lpm3 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
229 TEST_LPM_ASSERT(lpm3 == lpm1);
238 * Create lpm table then delete lpm table 100 times
239 * Use a slightly different rules size each time
244 struct rte_lpm6 *lpm = NULL;
245 struct rte_lpm6_config config;
248 config.number_tbl8s = NUMBER_TBL8S;
251 /* rte_lpm6_free: Free NULL */
252 for (i = 0; i < 100; i++) {
253 config.max_rules = MAX_RULES - i;
254 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
255 TEST_LPM_ASSERT(lpm != NULL);
260 /* Can not test free so return success */
265 * Call rte_lpm6_free for NULL pointer user input. Note: free has no return and
266 * therefore it is impossible to check for failure but this test is added to
267 * increase function coverage metrics and to validate that freeing null does
273 struct rte_lpm6 *lpm = NULL;
274 struct rte_lpm6_config config;
276 config.max_rules = MAX_RULES;
277 config.number_tbl8s = NUMBER_TBL8S;
280 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
281 TEST_LPM_ASSERT(lpm != NULL);
289 * Check that rte_lpm6_add fails gracefully for incorrect user input arguments
294 struct rte_lpm6 *lpm = NULL;
295 struct rte_lpm6_config config;
297 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
298 uint8_t depth = 24, next_hop = 100;
301 config.max_rules = MAX_RULES;
302 config.number_tbl8s = NUMBER_TBL8S;
305 /* rte_lpm6_add: lpm == NULL */
306 status = rte_lpm6_add(NULL, ip, depth, next_hop);
307 TEST_LPM_ASSERT(status < 0);
309 /*Create vaild lpm to use in rest of test. */
310 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
311 TEST_LPM_ASSERT(lpm != NULL);
313 /* rte_lpm6_add: depth < 1 */
314 status = rte_lpm6_add(lpm, ip, 0, next_hop);
315 TEST_LPM_ASSERT(status < 0);
317 /* rte_lpm6_add: depth > MAX_DEPTH */
318 status = rte_lpm6_add(lpm, ip, (MAX_DEPTH + 1), next_hop);
319 TEST_LPM_ASSERT(status < 0);
327 * Check that rte_lpm6_delete fails gracefully for incorrect user input
333 struct rte_lpm6 *lpm = NULL;
334 struct rte_lpm6_config config;
335 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
339 config.max_rules = MAX_RULES;
340 config.number_tbl8s = NUMBER_TBL8S;
343 /* rte_lpm_delete: lpm == NULL */
344 status = rte_lpm6_delete(NULL, ip, depth);
345 TEST_LPM_ASSERT(status < 0);
347 /*Create vaild lpm to use in rest of test. */
348 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
349 TEST_LPM_ASSERT(lpm != NULL);
351 /* rte_lpm_delete: depth < 1 */
352 status = rte_lpm6_delete(lpm, ip, 0);
353 TEST_LPM_ASSERT(status < 0);
355 /* rte_lpm_delete: depth > MAX_DEPTH */
356 status = rte_lpm6_delete(lpm, ip, (MAX_DEPTH + 1));
357 TEST_LPM_ASSERT(status < 0);
365 * Check that rte_lpm6_lookup fails gracefully for incorrect user input
371 struct rte_lpm6 *lpm = NULL;
372 struct rte_lpm6_config config;
373 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
374 uint8_t next_hop_return = 0;
377 config.max_rules = MAX_RULES;
378 config.number_tbl8s = NUMBER_TBL8S;
381 /* rte_lpm6_lookup: lpm == NULL */
382 status = rte_lpm6_lookup(NULL, ip, &next_hop_return);
383 TEST_LPM_ASSERT(status < 0);
385 /*Create vaild lpm to use in rest of test. */
386 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
387 TEST_LPM_ASSERT(lpm != NULL);
389 /* rte_lpm6_lookup: ip = NULL */
390 status = rte_lpm6_lookup(lpm, NULL, &next_hop_return);
391 TEST_LPM_ASSERT(status < 0);
393 /* rte_lpm6_lookup: next_hop = NULL */
394 status = rte_lpm6_lookup(lpm, ip, NULL);
395 TEST_LPM_ASSERT(status < 0);
403 * Checks that rte_lpm6_lookup_bulk_func fails gracefully for incorrect user
409 struct rte_lpm6 *lpm = NULL;
410 struct rte_lpm6_config config;
412 int16_t next_hop_return[10];
415 config.max_rules = MAX_RULES;
416 config.number_tbl8s = NUMBER_TBL8S;
419 /* rte_lpm6_lookup: lpm == NULL */
420 status = rte_lpm6_lookup_bulk_func(NULL, ip, next_hop_return, 10);
421 TEST_LPM_ASSERT(status < 0);
423 /*Create vaild lpm to use in rest of test. */
424 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
425 TEST_LPM_ASSERT(lpm != NULL);
427 /* rte_lpm6_lookup: ip = NULL */
428 status = rte_lpm6_lookup_bulk_func(lpm, NULL, next_hop_return, 10);
429 TEST_LPM_ASSERT(status < 0);
431 /* rte_lpm6_lookup: next_hop = NULL */
432 status = rte_lpm6_lookup_bulk_func(lpm, ip, NULL, 10);
433 TEST_LPM_ASSERT(status < 0);
441 * Checks that rte_lpm6_delete_bulk_func fails gracefully for incorrect user
447 struct rte_lpm6 *lpm = NULL;
448 struct rte_lpm6_config config;
453 config.max_rules = MAX_RULES;
454 config.number_tbl8s = NUMBER_TBL8S;
457 /* rte_lpm6_delete: lpm == NULL */
458 status = rte_lpm6_delete_bulk_func(NULL, ip, depth, 10);
459 TEST_LPM_ASSERT(status < 0);
461 /*Create vaild lpm to use in rest of test. */
462 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
463 TEST_LPM_ASSERT(lpm != NULL);
465 /* rte_lpm6_delete: ip = NULL */
466 status = rte_lpm6_delete_bulk_func(lpm, NULL, depth, 10);
467 TEST_LPM_ASSERT(status < 0);
469 /* rte_lpm6_delete: next_hop = NULL */
470 status = rte_lpm6_delete_bulk_func(lpm, ip, NULL, 10);
471 TEST_LPM_ASSERT(status < 0);
479 * Call add, lookup and delete for a single rule with depth < 24.
480 * Check all the combinations for the first three bytes that result in a hit.
481 * Delete the rule and check that the same test returs a miss.
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 = 16, next_hop_add = 100, next_hop_return = 0;
493 config.max_rules = MAX_RULES;
494 config.number_tbl8s = NUMBER_TBL8S;
497 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
498 TEST_LPM_ASSERT(lpm != NULL);
500 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
501 TEST_LPM_ASSERT(status == 0);
503 for (i = 0; i < UINT8_MAX; i++) {
505 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
506 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
509 status = rte_lpm6_delete(lpm, ip, depth);
510 TEST_LPM_ASSERT(status == 0);
512 for (i = 0; i < UINT8_MAX; i++) {
514 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
515 TEST_LPM_ASSERT(status == -ENOENT);
524 * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds
525 * another one and expects success.
530 struct rte_lpm6 *lpm = NULL;
531 struct rte_lpm6_config config;
532 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
533 uint8_t depth, next_hop_add = 100;
537 config.max_rules = 127;
538 config.number_tbl8s = NUMBER_TBL8S;
541 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
542 TEST_LPM_ASSERT(lpm != NULL);
544 for (i = 1; i < 128; i++) {
546 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
547 TEST_LPM_ASSERT(status == 0);
551 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
552 TEST_LPM_ASSERT(status == -ENOSPC);
555 status = rte_lpm6_delete(lpm, ip, depth);
556 TEST_LPM_ASSERT(status == 0);
559 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
560 TEST_LPM_ASSERT(status == 0);
568 * Creates an LPM table with a small number of tbl8s and exhaust them in the
569 * middle of the process of creating a rule.
574 struct rte_lpm6 *lpm = NULL;
575 struct rte_lpm6_config config;
576 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
577 uint8_t depth, next_hop_add = 100;
580 config.max_rules = MAX_RULES;
581 config.number_tbl8s = 16;
584 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
585 TEST_LPM_ASSERT(lpm != NULL);
588 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
589 TEST_LPM_ASSERT(status == 0);
593 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
594 TEST_LPM_ASSERT(status == 0);
596 status = rte_lpm6_delete(lpm, ip, depth);
597 TEST_LPM_ASSERT(status == 0);
600 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
601 TEST_LPM_ASSERT(status == 0);
603 status = rte_lpm6_delete(lpm, ip, depth);
604 TEST_LPM_ASSERT(status == 0);
607 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
608 TEST_LPM_ASSERT(status == 0);
610 status = rte_lpm6_delete(lpm, ip, depth);
611 TEST_LPM_ASSERT(status == 0);
614 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
615 TEST_LPM_ASSERT(status == -ENOSPC);
618 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
619 TEST_LPM_ASSERT(status == 0);
627 * Creates an LPM table with a small number of tbl8s and exhaust them in the
628 * middle of the process of adding a rule when there is already an existing rule
629 * in that position and needs to be extended.
634 struct rte_lpm6 *lpm = NULL;
635 struct rte_lpm6_config config;
636 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
637 uint8_t depth, next_hop_add = 100;
640 config.max_rules = MAX_RULES;
641 config.number_tbl8s = 16;
644 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
645 TEST_LPM_ASSERT(lpm != NULL);
648 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
649 TEST_LPM_ASSERT(status == 0);
653 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
654 TEST_LPM_ASSERT(status == 0);
657 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
658 TEST_LPM_ASSERT(status == -ENOSPC);
666 * Creates an LPM table with max_rules = 2 and tries to add 3 rules.
667 * Delete one of the rules and tries to add the third one again.
672 struct rte_lpm6 *lpm = NULL;
673 struct rte_lpm6_config config;
674 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
675 uint8_t depth, next_hop_add = 100;
678 config.max_rules = 2;
679 config.number_tbl8s = NUMBER_TBL8S;
682 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
683 TEST_LPM_ASSERT(lpm != NULL);
686 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
687 TEST_LPM_ASSERT(status == 0);
690 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
691 TEST_LPM_ASSERT(status == 0);
694 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
695 TEST_LPM_ASSERT(status == -ENOSPC);
698 status = rte_lpm6_delete(lpm, ip, depth);
699 TEST_LPM_ASSERT(status == 0);
702 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
703 TEST_LPM_ASSERT(status == 0);
711 * Add 2^16 routes with different first 16 bits and depth 25.
712 * Add one more route with the same depth and check that results in a failure.
713 * After that delete the last rule and create the one that was attempted to be
714 * created. This checks tbl8 exhaustion.
719 struct rte_lpm6 *lpm = NULL;
720 struct rte_lpm6_config config;
721 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
722 uint8_t depth = 25, next_hop_add = 100;
726 config.max_rules = MAX_RULES;
727 config.number_tbl8s = NUMBER_TBL8S;
730 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
731 TEST_LPM_ASSERT(lpm != NULL);
733 for (i = 0; i < 256; i++) {
735 for (j = 0; j < 256; j++) {
737 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
738 TEST_LPM_ASSERT(status == 0);
745 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
746 TEST_LPM_ASSERT(status == -ENOSPC);
751 status = rte_lpm6_delete(lpm, ip, depth);
752 TEST_LPM_ASSERT(status == 0);
757 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
758 TEST_LPM_ASSERT(status == 0);
766 * Call add, lookup and delete for a single rule with depth = 24
771 struct rte_lpm6 *lpm = NULL;
772 struct rte_lpm6_config config;
773 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
774 uint8_t depth = 24, next_hop_add = 100, next_hop_return = 0;
777 config.max_rules = MAX_RULES;
778 config.number_tbl8s = NUMBER_TBL8S;
781 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
782 TEST_LPM_ASSERT(lpm != NULL);
784 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
785 TEST_LPM_ASSERT(status == 0);
787 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
788 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
790 status = rte_lpm6_delete(lpm, ip, depth);
791 TEST_LPM_ASSERT(status == 0);
793 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
794 TEST_LPM_ASSERT(status == -ENOENT);
802 * Call add, lookup and delete for a single rule with depth > 24
807 struct rte_lpm6 *lpm = NULL;
808 struct rte_lpm6_config config;
809 uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0};
810 uint8_t depth = 128, next_hop_add = 100, next_hop_return = 0;
813 config.max_rules = MAX_RULES;
814 config.number_tbl8s = NUMBER_TBL8S;
817 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
818 TEST_LPM_ASSERT(lpm != NULL);
820 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
821 TEST_LPM_ASSERT(status == 0);
823 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
824 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
826 status = rte_lpm6_delete(lpm, ip, depth);
827 TEST_LPM_ASSERT(status == 0);
829 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
830 TEST_LPM_ASSERT(status == -ENOENT);
838 * Use rte_lpm6_add to add rules which effect only the second half of the lpm
839 * table. Use all possible depths ranging from 1..32. Set the next hop = to the
840 * depth. Check lookup hit for on every add and check for lookup miss on the
841 * first half of the lpm table after each add. Finally delete all rules going
842 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
843 * delete. The lookup should return the next_hop_add value related to the
844 * previous depth value (i.e. depth -1).
849 struct rte_lpm6 *lpm = NULL;
850 struct rte_lpm6_config config;
851 uint8_t ip1[] = {127,255,255,255,255,255,255,255,255,
852 255,255,255,255,255,255,255};
853 uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
854 uint8_t depth, next_hop_add, next_hop_return;
857 config.max_rules = MAX_RULES;
858 config.number_tbl8s = NUMBER_TBL8S;
861 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
862 TEST_LPM_ASSERT(lpm != NULL);
864 /* Loop with rte_lpm6_add. */
865 for (depth = 1; depth <= 128; depth++) {
866 /* Let the next_hop_add value = depth. Just for change. */
867 next_hop_add = depth;
869 status = rte_lpm6_add(lpm, ip2, depth, next_hop_add);
870 TEST_LPM_ASSERT(status == 0);
872 /* Check IP in first half of tbl24 which should be empty. */
873 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
874 TEST_LPM_ASSERT(status == -ENOENT);
876 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
877 TEST_LPM_ASSERT((status == 0) &&
878 (next_hop_return == next_hop_add));
881 /* Loop with rte_lpm6_delete. */
882 for (depth = 128; depth >= 1; depth--) {
883 next_hop_add = (uint8_t) (depth - 1);
885 status = rte_lpm6_delete(lpm, ip2, depth);
886 TEST_LPM_ASSERT(status == 0);
888 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
891 TEST_LPM_ASSERT((status == 0) &&
892 (next_hop_return == next_hop_add));
895 TEST_LPM_ASSERT(status == -ENOENT);
898 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
899 TEST_LPM_ASSERT(status == -ENOENT);
908 * - Add & lookup to hit invalid TBL24 entry
909 * - Add & lookup to hit valid TBL24 entry not extended
910 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
911 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
916 struct rte_lpm6 *lpm = NULL;
917 struct rte_lpm6_config config;
918 uint8_t ip[16], ip_1[16], ip_2[16];
919 uint8_t depth, depth_1, depth_2, next_hop_add, next_hop_add_1,
920 next_hop_add_2, next_hop_return;
923 config.max_rules = MAX_RULES;
924 config.number_tbl8s = NUMBER_TBL8S;
927 /* Add & lookup to hit invalid TBL24 entry */
928 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
932 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
933 TEST_LPM_ASSERT(lpm != NULL);
935 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
936 TEST_LPM_ASSERT(status == 0);
938 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
939 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
941 status = rte_lpm6_delete(lpm, ip, depth);
942 TEST_LPM_ASSERT(status == 0);
944 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
945 TEST_LPM_ASSERT(status == -ENOENT);
947 rte_lpm6_delete_all(lpm);
949 /* Add & lookup to hit valid TBL24 entry not extended */
950 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
954 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
955 TEST_LPM_ASSERT(status == 0);
957 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
958 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
963 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
964 TEST_LPM_ASSERT(status == 0);
966 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
967 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
971 status = rte_lpm6_delete(lpm, ip, depth);
972 TEST_LPM_ASSERT(status == 0);
976 status = rte_lpm6_delete(lpm, ip, depth);
977 TEST_LPM_ASSERT(status == 0);
979 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
980 TEST_LPM_ASSERT(status == -ENOENT);
982 rte_lpm6_delete_all(lpm);
984 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
987 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
991 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
992 TEST_LPM_ASSERT(status == 0);
994 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
995 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
997 IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1001 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1002 TEST_LPM_ASSERT(status == 0);
1004 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1005 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1007 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1011 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1012 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1014 status = rte_lpm6_delete(lpm, ip, depth);
1015 TEST_LPM_ASSERT(status == 0);
1017 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1018 TEST_LPM_ASSERT(status == -ENOENT);
1020 rte_lpm6_delete_all(lpm);
1022 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
1025 IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1027 next_hop_add_1 = 101;
1029 IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1031 next_hop_add_2 = 102;
1033 next_hop_return = 0;
1035 status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1);
1036 TEST_LPM_ASSERT(status == 0);
1038 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1039 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1041 status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_2);
1042 TEST_LPM_ASSERT(status == 0);
1044 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1045 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
1047 status = rte_lpm6_delete(lpm, ip_2, depth_2);
1048 TEST_LPM_ASSERT(status == 0);
1050 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1051 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1053 status = rte_lpm6_delete(lpm, ip_1, depth_1);
1054 TEST_LPM_ASSERT(status == 0);
1056 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1057 TEST_LPM_ASSERT(status == -ENOENT);
1065 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
1067 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
1068 * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
1070 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
1071 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
1072 * - Delete a rule that is not present in the TBL24 & lookup
1073 * - Delete a rule that is not present in the TBL8 & lookup
1078 struct rte_lpm6 *lpm = NULL;
1079 struct rte_lpm6_config config;
1081 uint8_t depth, next_hop_add, next_hop_return;
1084 config.max_rules = MAX_RULES;
1085 config.number_tbl8s = NUMBER_TBL8S;
1088 /* Add rule that covers a TBL24 range previously invalid & lookup
1089 * (& delete & lookup)
1091 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1092 TEST_LPM_ASSERT(lpm != NULL);
1094 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1098 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1099 TEST_LPM_ASSERT(status == 0);
1101 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1102 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1104 status = rte_lpm6_delete(lpm, ip, depth);
1105 TEST_LPM_ASSERT(status == 0);
1107 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1108 TEST_LPM_ASSERT(status == -ENOENT);
1110 rte_lpm6_delete_all(lpm);
1112 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1116 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1117 TEST_LPM_ASSERT(status == 0);
1119 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1120 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1122 status = rte_lpm6_delete(lpm, ip, depth);
1123 TEST_LPM_ASSERT(status == 0);
1125 rte_lpm6_delete_all(lpm);
1128 * Add rule that extends a TBL24 valid entry & lookup for both rules
1129 * (& delete & lookup)
1132 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1136 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1137 TEST_LPM_ASSERT(status == 0);
1139 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1143 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1144 TEST_LPM_ASSERT(status == 0);
1146 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1147 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1149 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1152 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1153 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1155 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1158 status = rte_lpm6_delete(lpm, ip, depth);
1159 TEST_LPM_ASSERT(status == 0);
1161 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1162 TEST_LPM_ASSERT(status == -ENOENT);
1164 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1167 status = rte_lpm6_delete(lpm, ip, depth);
1168 TEST_LPM_ASSERT(status == 0);
1170 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1171 TEST_LPM_ASSERT(status == -ENOENT);
1173 rte_lpm6_delete_all(lpm);
1176 * Add rule that updates the next hop in TBL24 & lookup
1177 * (& delete & lookup)
1180 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1184 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1185 TEST_LPM_ASSERT(status == 0);
1187 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1188 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1192 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1193 TEST_LPM_ASSERT(status == 0);
1195 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1196 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1198 status = rte_lpm6_delete(lpm, ip, depth);
1199 TEST_LPM_ASSERT(status == 0);
1201 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1202 TEST_LPM_ASSERT(status == -ENOENT);
1204 rte_lpm6_delete_all(lpm);
1207 * Add rule that updates the next hop in TBL8 & lookup
1208 * (& delete & lookup)
1211 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1215 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1216 TEST_LPM_ASSERT(status == 0);
1218 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1219 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1223 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1224 TEST_LPM_ASSERT(status == 0);
1226 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1227 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1229 status = rte_lpm6_delete(lpm, ip, depth);
1230 TEST_LPM_ASSERT(status == 0);
1232 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1233 TEST_LPM_ASSERT(status == -ENOENT);
1235 rte_lpm6_delete_all(lpm);
1237 /* Delete a rule that is not present in the TBL24 & lookup */
1239 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1243 status = rte_lpm6_delete(lpm, ip, depth);
1244 TEST_LPM_ASSERT(status < 0);
1246 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1247 TEST_LPM_ASSERT(status == -ENOENT);
1249 rte_lpm6_delete_all(lpm);
1251 /* Delete a rule that is not present in the TBL8 & lookup */
1253 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1257 status = rte_lpm6_delete(lpm, ip, depth);
1258 TEST_LPM_ASSERT(status < 0);
1260 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1261 TEST_LPM_ASSERT(status == -ENOENT);
1269 * Add two rules, lookup to hit the more specific one, lookup to hit the less
1270 * specific one delete the less specific rule and lookup previous values again;
1271 * add a more specific rule than the existing rule, lookup again
1276 struct rte_lpm6 *lpm = NULL;
1277 struct rte_lpm6_config config;
1279 uint8_t depth, next_hop_add, next_hop_return;
1282 config.max_rules = MAX_RULES;
1283 config.number_tbl8s = NUMBER_TBL8S;
1286 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1287 TEST_LPM_ASSERT(lpm != NULL);
1289 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1293 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1294 TEST_LPM_ASSERT(status == 0);
1296 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1300 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1301 TEST_LPM_ASSERT(status == 0);
1303 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1304 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1306 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1309 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1310 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1312 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1315 status = rte_lpm6_delete(lpm, ip, depth);
1316 TEST_LPM_ASSERT(status == 0);
1318 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1319 TEST_LPM_ASSERT(status == -ENOENT);
1321 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1324 status = rte_lpm6_delete(lpm, ip, depth);
1325 TEST_LPM_ASSERT(status == 0);
1327 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1328 TEST_LPM_ASSERT(status == -ENOENT);
1336 * Adds 3 rules and look them up through the lookup_bulk function.
1337 * Includes in the lookup a fourth IP address that won't match
1338 * and checks that the result is as expected.
1343 struct rte_lpm6 *lpm = NULL;
1344 struct rte_lpm6_config config;
1345 uint8_t ip_batch[4][16];
1346 uint8_t depth, next_hop_add;
1347 int16_t next_hop_return[4];
1350 config.max_rules = MAX_RULES;
1351 config.number_tbl8s = NUMBER_TBL8S;
1354 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1355 TEST_LPM_ASSERT(lpm != NULL);
1357 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1361 status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add);
1362 TEST_LPM_ASSERT(status == 0);
1364 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1368 status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add);
1369 TEST_LPM_ASSERT(status == 0);
1371 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1375 status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add);
1376 TEST_LPM_ASSERT(status == 0);
1378 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1380 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1381 next_hop_return, 4);
1382 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100
1383 && next_hop_return[1] == 101 && next_hop_return[2] == 102
1384 && next_hop_return[3] == -1);
1392 * Adds 5 rules and look them up.
1393 * Use the delete_bulk function to delete two of them. Lookup again.
1394 * Use the delete_bulk function to delete one more. Lookup again.
1395 * Use the delete_bulk function to delete two more, one invalid. Lookup again.
1396 * Use the delete_bulk function to delete the remaining one. Lookup again.
1401 struct rte_lpm6 *lpm = NULL;
1402 struct rte_lpm6_config config;
1403 uint8_t ip_batch[5][16];
1404 uint8_t depth[5], next_hop_add;
1405 int16_t next_hop_return[5];
1408 config.max_rules = MAX_RULES;
1409 config.number_tbl8s = NUMBER_TBL8S;
1412 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1413 TEST_LPM_ASSERT(lpm != NULL);
1415 /* Adds 5 rules and look them up */
1417 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1421 status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add);
1422 TEST_LPM_ASSERT(status == 0);
1424 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1428 status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add);
1429 TEST_LPM_ASSERT(status == 0);
1431 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1435 status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add);
1436 TEST_LPM_ASSERT(status == 0);
1438 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1442 status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add);
1443 TEST_LPM_ASSERT(status == 0);
1445 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1449 status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add);
1450 TEST_LPM_ASSERT(status == 0);
1452 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1453 next_hop_return, 5);
1454 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101
1455 && next_hop_return[1] == 102 && next_hop_return[2] == 103
1456 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1458 /* Use the delete_bulk function to delete two of them. Lookup again */
1460 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2);
1461 TEST_LPM_ASSERT(status == 0);
1463 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1464 next_hop_return, 5);
1465 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1466 && next_hop_return[1] == -1 && next_hop_return[2] == 103
1467 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1469 /* Use the delete_bulk function to delete one more. Lookup again */
1471 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1);
1472 TEST_LPM_ASSERT(status == 0);
1474 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1475 next_hop_return, 5);
1476 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1477 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1478 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1480 /* Use the delete_bulk function to delete two, one invalid. Lookup again */
1482 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1483 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2);
1484 TEST_LPM_ASSERT(status == 0);
1486 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1487 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1488 next_hop_return, 5);
1489 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1490 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1491 && next_hop_return[3] == -1 && next_hop_return[4] == 105);
1493 /* Use the delete_bulk function to delete the remaining one. Lookup again */
1495 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1);
1496 TEST_LPM_ASSERT(status == 0);
1498 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1499 next_hop_return, 5);
1500 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1501 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1502 && next_hop_return[3] == -1 && next_hop_return[4] == -1);
1510 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
1511 * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension
1517 struct rte_lpm6 *lpm = NULL;
1518 struct rte_lpm6_config config;
1521 uint8_t depth, next_hop_add, next_hop_return;
1524 config.max_rules = MAX_RULES;
1525 config.number_tbl8s = NUMBER_TBL8S;
1528 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1529 TEST_LPM_ASSERT(lpm != NULL);
1531 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1535 for (i = 0; i < 1000; i++) {
1536 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1537 TEST_LPM_ASSERT(status == 0);
1539 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1540 TEST_LPM_ASSERT((status == 0) &&
1541 (next_hop_return == next_hop_add));
1543 status = rte_lpm6_delete(lpm, ip, depth);
1544 TEST_LPM_ASSERT(status == 0);
1546 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1547 TEST_LPM_ASSERT(status == -ENOENT);
1556 * Sequence of operations for find existing lpm table
1559 * - find existing table: hit
1560 * - find non-existing table: miss
1565 struct rte_lpm6 *lpm = NULL, *result = NULL;
1566 struct rte_lpm6_config config;
1568 config.max_rules = 256 * 32;
1569 config.number_tbl8s = NUMBER_TBL8S;
1573 lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1574 TEST_LPM_ASSERT(lpm != NULL);
1576 /* Try to find existing lpm */
1577 result = rte_lpm6_find_existing("lpm_find_existing");
1578 TEST_LPM_ASSERT(result == lpm);
1580 /* Try to find non-existing lpm */
1581 result = rte_lpm6_find_existing("lpm_find_non_existing");
1582 TEST_LPM_ASSERT(result == NULL);
1585 rte_lpm6_delete_all(lpm);
1592 * Add a set of random routes with random depths.
1593 * Lookup different IP addresses that match the routes previously added.
1594 * Checks that the next hop is the expected one.
1595 * The routes, IP addresses and expected result for every case have been
1596 * precalculated by using a python script and stored in a .h file.
1601 struct rte_lpm6 *lpm = NULL;
1602 struct rte_lpm6_config config;
1605 uint8_t depth, next_hop_add, next_hop_return, next_hop_expected;
1608 config.max_rules = MAX_RULES;
1609 config.number_tbl8s = NUMBER_TBL8S;
1612 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1613 TEST_LPM_ASSERT(lpm != NULL);
1615 for (i = 0; i < 1000; i++) {
1616 memcpy(ip, large_route_table[i].ip, 16);
1617 depth = large_route_table[i].depth;
1618 next_hop_add = large_route_table[i].next_hop;
1619 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1620 TEST_LPM_ASSERT(status == 0);
1623 for (i = 0; i < 100000; i++) {
1624 memcpy(ip, large_ips_table[i].ip, 16);
1625 next_hop_expected = large_ips_table[i].next_hop;
1627 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1628 TEST_LPM_ASSERT((status == 0) &&
1629 (next_hop_return == next_hop_expected));
1638 * Test for overwriting of tbl8:
1639 * - add rule /32 and lookup
1640 * - add new rule /24 and lookup
1641 * - add third rule /25 and lookup
1642 * - lookup /32 and /24 rule to ensure the table has not been overwritten.
1647 struct rte_lpm6 *lpm = NULL;
1648 struct rte_lpm6_config config;
1649 uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1650 uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1651 uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1652 uint8_t d_ip_10_32 = 32;
1653 uint8_t d_ip_10_24 = 24;
1654 uint8_t d_ip_20_25 = 25;
1655 uint8_t next_hop_ip_10_32 = 100;
1656 uint8_t next_hop_ip_10_24 = 105;
1657 uint8_t next_hop_ip_20_25 = 111;
1658 uint8_t next_hop_return = 0;
1661 config.max_rules = MAX_RULES;
1662 config.number_tbl8s = NUMBER_TBL8S;
1665 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1666 TEST_LPM_ASSERT(lpm != NULL);
1668 if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32,
1669 next_hop_ip_10_32)) < 0)
1672 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1673 uint8_t test_hop_10_32 = next_hop_return;
1674 TEST_LPM_ASSERT(status == 0);
1675 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1677 if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24,
1678 next_hop_ip_10_24)) < 0)
1681 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1682 uint8_t test_hop_10_24 = next_hop_return;
1683 TEST_LPM_ASSERT(status == 0);
1684 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1686 if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25,
1687 next_hop_ip_20_25)) < 0)
1690 status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return);
1691 uint8_t test_hop_20_25 = next_hop_return;
1692 TEST_LPM_ASSERT(status == 0);
1693 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1695 if (test_hop_10_32 == test_hop_10_24) {
1696 printf("Next hop return equal\n");
1700 if (test_hop_10_24 == test_hop_20_25){
1701 printf("Next hop return equal\n");
1705 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1706 TEST_LPM_ASSERT(status == 0);
1707 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1709 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1710 TEST_LPM_ASSERT(status == 0);
1711 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1719 * Add a rule that reaches the end of the tree.
1720 * Add a rule that is more generic than the first one.
1721 * Check every possible combination that produces a match for the second rule.
1722 * This tests tbl expansion.
1727 struct rte_lpm6 *lpm = NULL;
1728 struct rte_lpm6_config config;
1729 uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0};
1730 uint8_t depth = 128, next_hop_add = 100, next_hop_return;
1734 config.max_rules = MAX_RULES;
1735 config.number_tbl8s = NUMBER_TBL8S;
1738 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1739 TEST_LPM_ASSERT(lpm != NULL);
1743 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1744 TEST_LPM_ASSERT(status == 0);
1748 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1749 TEST_LPM_ASSERT(status == 0);
1751 for (i = 0; i < 256; i++) {
1752 ip[14] = (uint8_t)i;
1753 for (j = 0; j < 256; j++) {
1754 ip[15] = (uint8_t)j;
1755 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1756 if (i == 0 && j == 0)
1757 TEST_LPM_ASSERT(status == 0 && next_hop_return == 128);
1759 TEST_LPM_ASSERT(status == 0 && next_hop_return == 112);
1769 * Lookup performance test
1772 #define ITERATIONS (1 << 10)
1773 #define BATCH_SIZE 100000
1776 print_route_distribution(const struct rules_tbl_entry *table, uint32_t n)
1780 printf("Route distribution per prefix width: \n");
1781 printf("DEPTH QUANTITY (PERCENT)\n");
1782 printf("--------------------------- \n");
1785 for(i = 1; i <= 128; i++) {
1786 unsigned depth_counter = 0;
1787 double percent_hits;
1789 for (j = 0; j < n; j++)
1790 if (table[j].depth == (uint8_t) i)
1793 percent_hits = ((double)depth_counter)/((double)n) * 100;
1794 printf("%.2u%15u (%.2f)\n", i, depth_counter, percent_hits);
1802 struct rte_lpm6 *lpm = NULL;
1803 struct rte_lpm6_config config;
1804 uint64_t begin, total_time;
1806 uint8_t next_hop_add = 0xAA, next_hop_return = 0;
1810 config.max_rules = 1000000;
1811 config.number_tbl8s = NUMBER_TBL8S;
1814 rte_srand(rte_rdtsc());
1816 printf("No. routes = %u\n", (unsigned) NUM_ROUTE_ENTRIES);
1818 print_route_distribution(large_route_table, (uint32_t) NUM_ROUTE_ENTRIES);
1820 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1821 TEST_LPM_ASSERT(lpm != NULL);
1824 begin = rte_rdtsc();
1826 for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1827 if (rte_lpm6_add(lpm, large_route_table[i].ip,
1828 large_route_table[i].depth, next_hop_add) == 0)
1832 total_time = rte_rdtsc() - begin;
1834 printf("Unique added entries = %d\n", status);
1835 printf("Average LPM Add: %g cycles\n",
1836 (double)total_time / NUM_ROUTE_ENTRIES);
1838 /* Measure single Lookup */
1842 for (i = 0; i < ITERATIONS; i ++) {
1843 begin = rte_rdtsc();
1845 for (j = 0; j < NUM_IPS_ENTRIES; j ++) {
1846 if (rte_lpm6_lookup(lpm, large_ips_table[j].ip,
1847 &next_hop_return) != 0)
1851 total_time += rte_rdtsc() - begin;
1854 printf("Average LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1855 (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1856 (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1858 /* Measure bulk Lookup */
1862 uint8_t ip_batch[NUM_IPS_ENTRIES][16];
1863 int16_t next_hops[NUM_IPS_ENTRIES];
1865 for (i = 0; i < NUM_IPS_ENTRIES; i++)
1866 memcpy(ip_batch[i], large_ips_table[i].ip, 16);
1868 for (i = 0; i < ITERATIONS; i ++) {
1870 /* Lookup per batch */
1871 begin = rte_rdtsc();
1872 rte_lpm6_lookup_bulk_func(lpm, ip_batch, next_hops, NUM_IPS_ENTRIES);
1873 total_time += rte_rdtsc() - begin;
1875 for (j = 0; j < NUM_IPS_ENTRIES; j++)
1876 if (next_hops[j] < 0)
1879 printf("BULK LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1880 (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1881 (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1885 begin = rte_rdtsc();
1887 for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1888 /* rte_lpm_delete(lpm, ip, depth) */
1889 status += rte_lpm6_delete(lpm, large_route_table[i].ip,
1890 large_route_table[i].depth);
1893 total_time += rte_rdtsc() - begin;
1895 printf("Average LPM Delete: %g cycles\n",
1896 (double)total_time / NUM_ROUTE_ENTRIES);
1898 rte_lpm6_delete_all(lpm);
1905 * Do all unit and performance tests.
1911 int status = -1, global_status = 0;
1913 for (i = 0; i < NUM_LPM6_TESTS; i++) {
1914 status = tests6[i]();
1917 printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i]));
1918 global_status = status;
1922 return global_status;
1925 #else /* RTE_LIBRTE_LPM */
1930 printf("The LPM library is not included in this build\n");
1934 #endif /* RTE_LIBRTE_LPM */