4 * Copyright(c) 2010-2014 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.
38 #include <sys/queue.h>
44 #include <rte_common.h>
45 #include <rte_cycles.h>
46 #include <rte_memory.h>
47 #include <rte_random.h>
48 #include <rte_branch_prediction.h>
52 #include "test_lpm6_routes.h"
54 #define TEST_LPM_ASSERT(cond) do { \
56 printf("Error at line %d: \n", __LINE__); \
61 typedef int32_t (* rte_lpm6_test)(void);
63 static int32_t test0(void);
64 static int32_t test1(void);
65 static int32_t test2(void);
66 static int32_t test3(void);
67 static int32_t test4(void);
68 static int32_t test5(void);
69 static int32_t test6(void);
70 static int32_t test7(void);
71 static int32_t test8(void);
72 static int32_t test9(void);
73 static int32_t test10(void);
74 static int32_t test11(void);
75 static int32_t test12(void);
76 static int32_t test13(void);
77 static int32_t test14(void);
78 static int32_t test15(void);
79 static int32_t test16(void);
80 static int32_t test17(void);
81 static int32_t test18(void);
82 static int32_t test19(void);
83 static int32_t test20(void);
84 static int32_t test21(void);
85 static int32_t test22(void);
86 static int32_t test23(void);
87 static int32_t test24(void);
88 static int32_t test25(void);
89 static int32_t test26(void);
90 static int32_t test27(void);
91 static int32_t perf_test(void);
93 rte_lpm6_test tests6[] = {
126 #define NUM_LPM6_TESTS (sizeof(tests6)/sizeof(tests6[0]))
127 #define RTE_LPM6_TBL24_NUM_ENTRIES (1 << 24)
128 #define RTE_LPM6_LOOKUP_SUCCESS 0x04000000
129 #define MAX_DEPTH 128
130 #define MAX_RULES 1000000
131 #define NUMBER_TBL8S (1 << 16)
132 #define MAX_NUM_TBL8S (1 << 21)
136 IPv6(uint8_t *ip, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5,
137 uint8_t b6, uint8_t b7, uint8_t b8, uint8_t b9, uint8_t b10,
138 uint8_t b11, uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15,
160 * Check that rte_lpm6_create fails gracefully for incorrect user input
166 struct rte_lpm6 *lpm = NULL;
167 struct rte_lpm6_config config;
169 config.max_rules = MAX_RULES;
170 config.number_tbl8s = NUMBER_TBL8S;
173 /* rte_lpm6_create: lpm name == NULL */
174 lpm = rte_lpm6_create(NULL, SOCKET_ID_ANY, &config);
175 TEST_LPM_ASSERT(lpm == NULL);
177 /* rte_lpm6_create: max_rules = 0 */
178 /* Note: __func__ inserts the function name, in this case "test0". */
179 config.max_rules = 0;
180 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
181 TEST_LPM_ASSERT(lpm == NULL);
183 /* socket_id < -1 is invalid */
184 config.max_rules = MAX_RULES;
185 lpm = rte_lpm6_create(__func__, -2, &config);
186 TEST_LPM_ASSERT(lpm == NULL);
188 /* rte_lpm6_create: number_tbl8s is bigger than the maximum */
189 config.number_tbl8s = MAX_NUM_TBL8S + 1;
190 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
191 TEST_LPM_ASSERT(lpm == NULL);
193 /* rte_lpm6_create: config = NULL */
194 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, NULL);
195 TEST_LPM_ASSERT(lpm == NULL);
201 * Creates two different LPM tables. Tries to create a third one with the same
202 * name as the first one and expects the create function to return the same
208 struct rte_lpm6 *lpm1 = NULL, *lpm2 = NULL, *lpm3 = NULL;
209 struct rte_lpm6_config config;
211 config.max_rules = MAX_RULES;
212 config.number_tbl8s = NUMBER_TBL8S;
215 /* rte_lpm6_create: lpm name == LPM1 */
216 lpm1 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
217 TEST_LPM_ASSERT(lpm1 != NULL);
219 /* rte_lpm6_create: lpm name == LPM2 */
220 lpm2 = rte_lpm6_create("LPM2", SOCKET_ID_ANY, &config);
221 TEST_LPM_ASSERT(lpm2 != NULL);
223 /* rte_lpm6_create: lpm name == LPM2 */
224 lpm3 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
225 TEST_LPM_ASSERT(lpm3 == lpm1);
234 * Create lpm table then delete lpm table 100 times
235 * Use a slightly different rules size each time
240 struct rte_lpm6 *lpm = NULL;
241 struct rte_lpm6_config config;
244 config.number_tbl8s = NUMBER_TBL8S;
247 /* rte_lpm6_free: Free NULL */
248 for (i = 0; i < 100; i++) {
249 config.max_rules = MAX_RULES - i;
250 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
251 TEST_LPM_ASSERT(lpm != NULL);
256 /* Can not test free so return success */
261 * Call rte_lpm6_free for NULL pointer user input. Note: free has no return and
262 * therefore it is impossible to check for failure but this test is added to
263 * increase function coverage metrics and to validate that freeing null does
269 struct rte_lpm6 *lpm = NULL;
270 struct rte_lpm6_config config;
272 config.max_rules = MAX_RULES;
273 config.number_tbl8s = NUMBER_TBL8S;
276 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
277 TEST_LPM_ASSERT(lpm != NULL);
285 * Check that rte_lpm6_add fails gracefully for incorrect user input arguments
290 struct rte_lpm6 *lpm = NULL;
291 struct rte_lpm6_config config;
293 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
294 uint8_t depth = 24, next_hop = 100;
297 config.max_rules = MAX_RULES;
298 config.number_tbl8s = NUMBER_TBL8S;
301 /* rte_lpm6_add: lpm == NULL */
302 status = rte_lpm6_add(NULL, ip, depth, next_hop);
303 TEST_LPM_ASSERT(status < 0);
305 /*Create vaild lpm to use in rest of test. */
306 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
307 TEST_LPM_ASSERT(lpm != NULL);
309 /* rte_lpm6_add: depth < 1 */
310 status = rte_lpm6_add(lpm, ip, 0, next_hop);
311 TEST_LPM_ASSERT(status < 0);
313 /* rte_lpm6_add: depth > MAX_DEPTH */
314 status = rte_lpm6_add(lpm, ip, (MAX_DEPTH + 1), next_hop);
315 TEST_LPM_ASSERT(status < 0);
323 * Check that rte_lpm6_delete fails gracefully for incorrect user input
329 struct rte_lpm6 *lpm = NULL;
330 struct rte_lpm6_config config;
331 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
335 config.max_rules = MAX_RULES;
336 config.number_tbl8s = NUMBER_TBL8S;
339 /* rte_lpm_delete: lpm == NULL */
340 status = rte_lpm6_delete(NULL, ip, depth);
341 TEST_LPM_ASSERT(status < 0);
343 /*Create vaild lpm to use in rest of test. */
344 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
345 TEST_LPM_ASSERT(lpm != NULL);
347 /* rte_lpm_delete: depth < 1 */
348 status = rte_lpm6_delete(lpm, ip, 0);
349 TEST_LPM_ASSERT(status < 0);
351 /* rte_lpm_delete: depth > MAX_DEPTH */
352 status = rte_lpm6_delete(lpm, ip, (MAX_DEPTH + 1));
353 TEST_LPM_ASSERT(status < 0);
361 * Check that rte_lpm6_lookup fails gracefully for incorrect user input
367 struct rte_lpm6 *lpm = NULL;
368 struct rte_lpm6_config config;
369 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
370 uint8_t next_hop_return = 0;
373 config.max_rules = MAX_RULES;
374 config.number_tbl8s = NUMBER_TBL8S;
377 /* rte_lpm6_lookup: lpm == NULL */
378 status = rte_lpm6_lookup(NULL, ip, &next_hop_return);
379 TEST_LPM_ASSERT(status < 0);
381 /*Create vaild lpm to use in rest of test. */
382 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
383 TEST_LPM_ASSERT(lpm != NULL);
385 /* rte_lpm6_lookup: ip = NULL */
386 status = rte_lpm6_lookup(lpm, NULL, &next_hop_return);
387 TEST_LPM_ASSERT(status < 0);
389 /* rte_lpm6_lookup: next_hop = NULL */
390 status = rte_lpm6_lookup(lpm, ip, NULL);
391 TEST_LPM_ASSERT(status < 0);
399 * Checks that rte_lpm6_lookup_bulk_func fails gracefully for incorrect user
405 struct rte_lpm6 *lpm = NULL;
406 struct rte_lpm6_config config;
408 int16_t next_hop_return[10];
411 config.max_rules = MAX_RULES;
412 config.number_tbl8s = NUMBER_TBL8S;
415 /* rte_lpm6_lookup: lpm == NULL */
416 status = rte_lpm6_lookup_bulk_func(NULL, ip, next_hop_return, 10);
417 TEST_LPM_ASSERT(status < 0);
419 /*Create vaild lpm to use in rest of test. */
420 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
421 TEST_LPM_ASSERT(lpm != NULL);
423 /* rte_lpm6_lookup: ip = NULL */
424 status = rte_lpm6_lookup_bulk_func(lpm, NULL, next_hop_return, 10);
425 TEST_LPM_ASSERT(status < 0);
427 /* rte_lpm6_lookup: next_hop = NULL */
428 status = rte_lpm6_lookup_bulk_func(lpm, ip, NULL, 10);
429 TEST_LPM_ASSERT(status < 0);
437 * Checks that rte_lpm6_delete_bulk_func fails gracefully for incorrect user
443 struct rte_lpm6 *lpm = NULL;
444 struct rte_lpm6_config config;
449 config.max_rules = MAX_RULES;
450 config.number_tbl8s = NUMBER_TBL8S;
453 /* rte_lpm6_delete: lpm == NULL */
454 status = rte_lpm6_delete_bulk_func(NULL, ip, depth, 10);
455 TEST_LPM_ASSERT(status < 0);
457 /*Create vaild lpm to use in rest of test. */
458 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
459 TEST_LPM_ASSERT(lpm != NULL);
461 /* rte_lpm6_delete: ip = NULL */
462 status = rte_lpm6_delete_bulk_func(lpm, NULL, depth, 10);
463 TEST_LPM_ASSERT(status < 0);
465 /* rte_lpm6_delete: next_hop = NULL */
466 status = rte_lpm6_delete_bulk_func(lpm, ip, NULL, 10);
467 TEST_LPM_ASSERT(status < 0);
475 * Call add, lookup and delete for a single rule with depth < 24.
476 * Check all the combinations for the first three bytes that result in a hit.
477 * Delete the rule and check that the same test returs a miss.
482 struct rte_lpm6 *lpm = NULL;
483 struct rte_lpm6_config config;
484 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
485 uint8_t depth = 16, next_hop_add = 100, next_hop_return = 0;
489 config.max_rules = MAX_RULES;
490 config.number_tbl8s = NUMBER_TBL8S;
493 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
494 TEST_LPM_ASSERT(lpm != NULL);
496 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
497 TEST_LPM_ASSERT(status == 0);
499 for (i = 0; i < UINT8_MAX; i++) {
501 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
502 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
505 status = rte_lpm6_delete(lpm, ip, depth);
506 TEST_LPM_ASSERT(status == 0);
508 for (i = 0; i < UINT8_MAX; i++) {
510 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
511 TEST_LPM_ASSERT(status == -ENOENT);
520 * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds
521 * another one and expects success.
526 struct rte_lpm6 *lpm = NULL;
527 struct rte_lpm6_config config;
528 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
529 uint8_t depth, next_hop_add = 100;
533 config.max_rules = 127;
534 config.number_tbl8s = NUMBER_TBL8S;
537 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
538 TEST_LPM_ASSERT(lpm != NULL);
540 for (i = 1; i < 128; i++) {
542 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
543 TEST_LPM_ASSERT(status == 0);
547 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
548 TEST_LPM_ASSERT(status == -ENOSPC);
551 status = rte_lpm6_delete(lpm, ip, depth);
552 TEST_LPM_ASSERT(status == 0);
555 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
556 TEST_LPM_ASSERT(status == 0);
564 * Creates an LPM table with a small number of tbl8s and exhaust them in the
565 * middle of the process of creating a rule.
570 struct rte_lpm6 *lpm = NULL;
571 struct rte_lpm6_config config;
572 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
573 uint8_t depth, next_hop_add = 100;
576 config.max_rules = MAX_RULES;
577 config.number_tbl8s = 16;
580 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
581 TEST_LPM_ASSERT(lpm != NULL);
584 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
585 TEST_LPM_ASSERT(status == 0);
589 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
590 TEST_LPM_ASSERT(status == 0);
592 status = rte_lpm6_delete(lpm, ip, depth);
593 TEST_LPM_ASSERT(status == 0);
596 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
597 TEST_LPM_ASSERT(status == 0);
599 status = rte_lpm6_delete(lpm, ip, depth);
600 TEST_LPM_ASSERT(status == 0);
603 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
604 TEST_LPM_ASSERT(status == 0);
606 status = rte_lpm6_delete(lpm, ip, depth);
607 TEST_LPM_ASSERT(status == 0);
610 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
611 TEST_LPM_ASSERT(status == -ENOSPC);
614 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
615 TEST_LPM_ASSERT(status == 0);
623 * Creates an LPM table with a small number of tbl8s and exhaust them in the
624 * middle of the process of adding a rule when there is already an existing rule
625 * in that position and needs to be extended.
630 struct rte_lpm6 *lpm = NULL;
631 struct rte_lpm6_config config;
632 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
633 uint8_t depth, next_hop_add = 100;
636 config.max_rules = MAX_RULES;
637 config.number_tbl8s = 16;
640 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
641 TEST_LPM_ASSERT(lpm != NULL);
644 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
645 TEST_LPM_ASSERT(status == 0);
649 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
650 TEST_LPM_ASSERT(status == 0);
653 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
654 TEST_LPM_ASSERT(status == -ENOSPC);
662 * Creates an LPM table with max_rules = 2 and tries to add 3 rules.
663 * Delete one of the rules and tries to add the third one again.
668 struct rte_lpm6 *lpm = NULL;
669 struct rte_lpm6_config config;
670 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
671 uint8_t depth, next_hop_add = 100;
674 config.max_rules = 2;
675 config.number_tbl8s = NUMBER_TBL8S;
678 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
679 TEST_LPM_ASSERT(lpm != NULL);
682 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
683 TEST_LPM_ASSERT(status == 0);
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 == -ENOSPC);
694 status = rte_lpm6_delete(lpm, ip, depth);
695 TEST_LPM_ASSERT(status == 0);
698 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
699 TEST_LPM_ASSERT(status == 0);
707 * Add 2^16 routes with different first 16 bits and depth 25.
708 * Add one more route with the same depth and check that results in a failure.
709 * After that delete the last rule and create the one that was attempted to be
710 * created. This checks tbl8 exhaustion.
715 struct rte_lpm6 *lpm = NULL;
716 struct rte_lpm6_config config;
717 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
718 uint8_t depth = 25, next_hop_add = 100;
722 config.max_rules = MAX_RULES;
723 config.number_tbl8s = NUMBER_TBL8S;
726 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
727 TEST_LPM_ASSERT(lpm != NULL);
729 for (i = 0; i < 256; i++) {
731 for (j = 0; j < 256; j++) {
733 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
734 TEST_LPM_ASSERT(status == 0);
741 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
742 TEST_LPM_ASSERT(status == -ENOSPC);
747 status = rte_lpm6_delete(lpm, ip, depth);
748 TEST_LPM_ASSERT(status == 0);
753 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
754 TEST_LPM_ASSERT(status == 0);
762 * Call add, lookup and delete for a single rule with depth = 24
767 struct rte_lpm6 *lpm = NULL;
768 struct rte_lpm6_config config;
769 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
770 uint8_t depth = 24, next_hop_add = 100, next_hop_return = 0;
773 config.max_rules = MAX_RULES;
774 config.number_tbl8s = NUMBER_TBL8S;
777 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
778 TEST_LPM_ASSERT(lpm != NULL);
780 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
781 TEST_LPM_ASSERT(status == 0);
783 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
784 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
786 status = rte_lpm6_delete(lpm, ip, depth);
787 TEST_LPM_ASSERT(status == 0);
789 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
790 TEST_LPM_ASSERT(status == -ENOENT);
798 * Call add, lookup and delete for a single rule with depth > 24
803 struct rte_lpm6 *lpm = NULL;
804 struct rte_lpm6_config config;
805 uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0};
806 uint8_t depth = 128, next_hop_add = 100, next_hop_return = 0;
809 config.max_rules = MAX_RULES;
810 config.number_tbl8s = NUMBER_TBL8S;
813 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
814 TEST_LPM_ASSERT(lpm != NULL);
816 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
817 TEST_LPM_ASSERT(status == 0);
819 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
820 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
822 status = rte_lpm6_delete(lpm, ip, depth);
823 TEST_LPM_ASSERT(status == 0);
825 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
826 TEST_LPM_ASSERT(status == -ENOENT);
834 * Use rte_lpm6_add to add rules which effect only the second half of the lpm
835 * table. Use all possible depths ranging from 1..32. Set the next hop = to the
836 * depth. Check lookup hit for on every add and check for lookup miss on the
837 * first half of the lpm table after each add. Finally delete all rules going
838 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
839 * delete. The lookup should return the next_hop_add value related to the
840 * previous depth value (i.e. depth -1).
845 struct rte_lpm6 *lpm = NULL;
846 struct rte_lpm6_config config;
847 uint8_t ip1[] = {127,255,255,255,255,255,255,255,255,
848 255,255,255,255,255,255,255};
849 uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
850 uint8_t depth, next_hop_add, next_hop_return;
853 config.max_rules = MAX_RULES;
854 config.number_tbl8s = NUMBER_TBL8S;
857 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
858 TEST_LPM_ASSERT(lpm != NULL);
860 /* Loop with rte_lpm6_add. */
861 for (depth = 1; depth <= 128; depth++) {
862 /* Let the next_hop_add value = depth. Just for change. */
863 next_hop_add = depth;
865 status = rte_lpm6_add(lpm, ip2, depth, next_hop_add);
866 TEST_LPM_ASSERT(status == 0);
868 /* Check IP in first half of tbl24 which should be empty. */
869 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
870 TEST_LPM_ASSERT(status == -ENOENT);
872 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
873 TEST_LPM_ASSERT((status == 0) &&
874 (next_hop_return == next_hop_add));
877 /* Loop with rte_lpm6_delete. */
878 for (depth = 128; depth >= 1; depth--) {
879 next_hop_add = (uint8_t) (depth - 1);
881 status = rte_lpm6_delete(lpm, ip2, depth);
882 TEST_LPM_ASSERT(status == 0);
884 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
887 TEST_LPM_ASSERT((status == 0) &&
888 (next_hop_return == next_hop_add));
891 TEST_LPM_ASSERT(status == -ENOENT);
894 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
895 TEST_LPM_ASSERT(status == -ENOENT);
904 * - Add & lookup to hit invalid TBL24 entry
905 * - Add & lookup to hit valid TBL24 entry not extended
906 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
907 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
912 struct rte_lpm6 *lpm = NULL;
913 struct rte_lpm6_config config;
914 uint8_t ip[16], ip_1[16], ip_2[16];
915 uint8_t depth, depth_1, depth_2, next_hop_add, next_hop_add_1,
916 next_hop_add_2, next_hop_return;
919 config.max_rules = MAX_RULES;
920 config.number_tbl8s = NUMBER_TBL8S;
923 /* Add & lookup to hit invalid TBL24 entry */
924 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
928 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
929 TEST_LPM_ASSERT(lpm != NULL);
931 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
932 TEST_LPM_ASSERT(status == 0);
934 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
935 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
937 status = rte_lpm6_delete(lpm, ip, depth);
938 TEST_LPM_ASSERT(status == 0);
940 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
941 TEST_LPM_ASSERT(status == -ENOENT);
943 rte_lpm6_delete_all(lpm);
945 /* Add & lookup to hit valid TBL24 entry not extended */
946 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
950 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
951 TEST_LPM_ASSERT(status == 0);
953 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
954 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
959 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
960 TEST_LPM_ASSERT(status == 0);
962 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
963 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
967 status = rte_lpm6_delete(lpm, ip, depth);
968 TEST_LPM_ASSERT(status == 0);
972 status = rte_lpm6_delete(lpm, ip, depth);
973 TEST_LPM_ASSERT(status == 0);
975 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
976 TEST_LPM_ASSERT(status == -ENOENT);
978 rte_lpm6_delete_all(lpm);
980 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
983 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
987 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
988 TEST_LPM_ASSERT(status == 0);
990 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
991 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
993 IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
997 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
998 TEST_LPM_ASSERT(status == 0);
1000 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1001 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1003 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1007 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1008 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1010 status = rte_lpm6_delete(lpm, ip, depth);
1011 TEST_LPM_ASSERT(status == 0);
1013 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1014 TEST_LPM_ASSERT(status == -ENOENT);
1016 rte_lpm6_delete_all(lpm);
1018 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
1021 IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1023 next_hop_add_1 = 101;
1025 IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1027 next_hop_add_2 = 102;
1029 next_hop_return = 0;
1031 status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1);
1032 TEST_LPM_ASSERT(status == 0);
1034 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1035 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1037 status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_2);
1038 TEST_LPM_ASSERT(status == 0);
1040 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1041 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
1043 status = rte_lpm6_delete(lpm, ip_2, depth_2);
1044 TEST_LPM_ASSERT(status == 0);
1046 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1047 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1049 status = rte_lpm6_delete(lpm, ip_1, depth_1);
1050 TEST_LPM_ASSERT(status == 0);
1052 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1053 TEST_LPM_ASSERT(status == -ENOENT);
1061 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
1063 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
1064 * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
1066 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
1067 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
1068 * - Delete a rule that is not present in the TBL24 & lookup
1069 * - Delete a rule that is not present in the TBL8 & lookup
1074 struct rte_lpm6 *lpm = NULL;
1075 struct rte_lpm6_config config;
1077 uint8_t depth, next_hop_add, next_hop_return;
1080 config.max_rules = MAX_RULES;
1081 config.number_tbl8s = NUMBER_TBL8S;
1084 /* Add rule that covers a TBL24 range previously invalid & lookup
1085 * (& delete & lookup)
1087 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1088 TEST_LPM_ASSERT(lpm != NULL);
1090 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1094 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1095 TEST_LPM_ASSERT(status == 0);
1097 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1098 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1100 status = rte_lpm6_delete(lpm, ip, depth);
1101 TEST_LPM_ASSERT(status == 0);
1103 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1104 TEST_LPM_ASSERT(status == -ENOENT);
1106 rte_lpm6_delete_all(lpm);
1108 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1112 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1113 TEST_LPM_ASSERT(status == 0);
1115 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1116 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1118 status = rte_lpm6_delete(lpm, ip, depth);
1119 TEST_LPM_ASSERT(status == 0);
1121 rte_lpm6_delete_all(lpm);
1124 * Add rule that extends a TBL24 valid entry & lookup for both rules
1125 * (& delete & lookup)
1128 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1132 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1133 TEST_LPM_ASSERT(status == 0);
1135 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1139 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1140 TEST_LPM_ASSERT(status == 0);
1142 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1143 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1145 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1148 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1149 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1151 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1154 status = rte_lpm6_delete(lpm, ip, depth);
1155 TEST_LPM_ASSERT(status == 0);
1157 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1158 TEST_LPM_ASSERT(status == -ENOENT);
1160 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1163 status = rte_lpm6_delete(lpm, ip, depth);
1164 TEST_LPM_ASSERT(status == 0);
1166 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1167 TEST_LPM_ASSERT(status == -ENOENT);
1169 rte_lpm6_delete_all(lpm);
1172 * Add rule that updates the next hop in TBL24 & lookup
1173 * (& delete & lookup)
1176 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1180 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1181 TEST_LPM_ASSERT(status == 0);
1183 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1184 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1188 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1189 TEST_LPM_ASSERT(status == 0);
1191 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1192 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1194 status = rte_lpm6_delete(lpm, ip, depth);
1195 TEST_LPM_ASSERT(status == 0);
1197 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1198 TEST_LPM_ASSERT(status == -ENOENT);
1200 rte_lpm6_delete_all(lpm);
1203 * Add rule that updates the next hop in TBL8 & lookup
1204 * (& delete & lookup)
1207 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1211 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1212 TEST_LPM_ASSERT(status == 0);
1214 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1215 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1219 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1220 TEST_LPM_ASSERT(status == 0);
1222 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1223 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1225 status = rte_lpm6_delete(lpm, ip, depth);
1226 TEST_LPM_ASSERT(status == 0);
1228 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1229 TEST_LPM_ASSERT(status == -ENOENT);
1231 rte_lpm6_delete_all(lpm);
1233 /* Delete a rule that is not present in the TBL24 & lookup */
1235 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1239 status = rte_lpm6_delete(lpm, ip, depth);
1240 TEST_LPM_ASSERT(status < 0);
1242 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1243 TEST_LPM_ASSERT(status == -ENOENT);
1245 rte_lpm6_delete_all(lpm);
1247 /* Delete a rule that is not present in the TBL8 & lookup */
1249 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1253 status = rte_lpm6_delete(lpm, ip, depth);
1254 TEST_LPM_ASSERT(status < 0);
1256 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1257 TEST_LPM_ASSERT(status == -ENOENT);
1265 * Add two rules, lookup to hit the more specific one, lookup to hit the less
1266 * specific one delete the less specific rule and lookup previous values again;
1267 * add a more specific rule than the existing rule, lookup again
1272 struct rte_lpm6 *lpm = NULL;
1273 struct rte_lpm6_config config;
1275 uint8_t depth, next_hop_add, next_hop_return;
1278 config.max_rules = MAX_RULES;
1279 config.number_tbl8s = NUMBER_TBL8S;
1282 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1283 TEST_LPM_ASSERT(lpm != NULL);
1285 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1289 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1290 TEST_LPM_ASSERT(status == 0);
1292 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1296 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1297 TEST_LPM_ASSERT(status == 0);
1299 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1300 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1302 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1305 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1306 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1308 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1311 status = rte_lpm6_delete(lpm, ip, depth);
1312 TEST_LPM_ASSERT(status == 0);
1314 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1315 TEST_LPM_ASSERT(status == -ENOENT);
1317 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1320 status = rte_lpm6_delete(lpm, ip, depth);
1321 TEST_LPM_ASSERT(status == 0);
1323 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1324 TEST_LPM_ASSERT(status == -ENOENT);
1332 * Adds 3 rules and look them up through the lookup_bulk function.
1333 * Includes in the lookup a fourth IP address that won't match
1334 * and checks that the result is as expected.
1339 struct rte_lpm6 *lpm = NULL;
1340 struct rte_lpm6_config config;
1341 uint8_t ip_batch[4][16];
1342 uint8_t depth, next_hop_add;
1343 int16_t next_hop_return[4];
1346 config.max_rules = MAX_RULES;
1347 config.number_tbl8s = NUMBER_TBL8S;
1350 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1351 TEST_LPM_ASSERT(lpm != NULL);
1353 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1357 status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add);
1358 TEST_LPM_ASSERT(status == 0);
1360 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1364 status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add);
1365 TEST_LPM_ASSERT(status == 0);
1367 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1371 status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add);
1372 TEST_LPM_ASSERT(status == 0);
1374 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1376 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1377 next_hop_return, 4);
1378 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100
1379 && next_hop_return[1] == 101 && next_hop_return[2] == 102
1380 && next_hop_return[3] == -1);
1388 * Adds 5 rules and look them up.
1389 * Use the delete_bulk function to delete two of them. Lookup again.
1390 * Use the delete_bulk function to delete one more. Lookup again.
1391 * Use the delete_bulk function to delete two more, one invalid. Lookup again.
1392 * Use the delete_bulk function to delete the remaining one. Lookup again.
1397 struct rte_lpm6 *lpm = NULL;
1398 struct rte_lpm6_config config;
1399 uint8_t ip_batch[5][16];
1400 uint8_t depth[5], next_hop_add;
1401 int16_t next_hop_return[5];
1404 config.max_rules = MAX_RULES;
1405 config.number_tbl8s = NUMBER_TBL8S;
1408 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1409 TEST_LPM_ASSERT(lpm != NULL);
1411 /* Adds 5 rules and look them up */
1413 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1417 status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add);
1418 TEST_LPM_ASSERT(status == 0);
1420 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1424 status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add);
1425 TEST_LPM_ASSERT(status == 0);
1427 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1431 status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add);
1432 TEST_LPM_ASSERT(status == 0);
1434 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1438 status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add);
1439 TEST_LPM_ASSERT(status == 0);
1441 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1445 status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add);
1446 TEST_LPM_ASSERT(status == 0);
1448 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1449 next_hop_return, 5);
1450 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101
1451 && next_hop_return[1] == 102 && next_hop_return[2] == 103
1452 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1454 /* Use the delete_bulk function to delete two of them. Lookup again */
1456 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2);
1457 TEST_LPM_ASSERT(status == 0);
1459 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1460 next_hop_return, 5);
1461 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1462 && next_hop_return[1] == -1 && next_hop_return[2] == 103
1463 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1465 /* Use the delete_bulk function to delete one more. Lookup again */
1467 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1);
1468 TEST_LPM_ASSERT(status == 0);
1470 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1471 next_hop_return, 5);
1472 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1473 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1474 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1476 /* Use the delete_bulk function to delete two, one invalid. Lookup again */
1478 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1479 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2);
1480 TEST_LPM_ASSERT(status == 0);
1482 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1483 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1484 next_hop_return, 5);
1485 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1486 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1487 && next_hop_return[3] == -1 && next_hop_return[4] == 105);
1489 /* Use the delete_bulk function to delete the remaining one. Lookup again */
1491 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1);
1492 TEST_LPM_ASSERT(status == 0);
1494 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1495 next_hop_return, 5);
1496 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1497 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1498 && next_hop_return[3] == -1 && next_hop_return[4] == -1);
1506 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
1507 * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension
1513 struct rte_lpm6 *lpm = NULL;
1514 struct rte_lpm6_config config;
1517 uint8_t depth, next_hop_add, next_hop_return;
1520 config.max_rules = MAX_RULES;
1521 config.number_tbl8s = NUMBER_TBL8S;
1524 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1525 TEST_LPM_ASSERT(lpm != NULL);
1527 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1531 for (i = 0; i < 1000; i++) {
1532 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1533 TEST_LPM_ASSERT(status == 0);
1535 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1536 TEST_LPM_ASSERT((status == 0) &&
1537 (next_hop_return == next_hop_add));
1539 status = rte_lpm6_delete(lpm, ip, depth);
1540 TEST_LPM_ASSERT(status == 0);
1542 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1543 TEST_LPM_ASSERT(status == -ENOENT);
1552 * Sequence of operations for find existing lpm table
1555 * - find existing table: hit
1556 * - find non-existing table: miss
1561 struct rte_lpm6 *lpm = NULL, *result = NULL;
1562 struct rte_lpm6_config config;
1564 config.max_rules = 256 * 32;
1565 config.number_tbl8s = NUMBER_TBL8S;
1569 lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1570 TEST_LPM_ASSERT(lpm != NULL);
1572 /* Try to find existing lpm */
1573 result = rte_lpm6_find_existing("lpm_find_existing");
1574 TEST_LPM_ASSERT(result == lpm);
1576 /* Try to find non-existing lpm */
1577 result = rte_lpm6_find_existing("lpm_find_non_existing");
1578 TEST_LPM_ASSERT(result == NULL);
1581 rte_lpm6_delete_all(lpm);
1588 * Add a set of random routes with random depths.
1589 * Lookup different IP addresses that match the routes previously added.
1590 * Checks that the next hop is the expected one.
1591 * The routes, IP addresses and expected result for every case have been
1592 * precalculated by using a python script and stored in a .h file.
1597 struct rte_lpm6 *lpm = NULL;
1598 struct rte_lpm6_config config;
1601 uint8_t depth, next_hop_add, next_hop_return, next_hop_expected;
1604 config.max_rules = MAX_RULES;
1605 config.number_tbl8s = NUMBER_TBL8S;
1608 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1609 TEST_LPM_ASSERT(lpm != NULL);
1611 for (i = 0; i < 1000; i++) {
1612 memcpy(ip, large_route_table[i].ip, 16);
1613 depth = large_route_table[i].depth;
1614 next_hop_add = large_route_table[i].next_hop;
1615 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1616 TEST_LPM_ASSERT(status == 0);
1619 for (i = 0; i < 100000; i++) {
1620 memcpy(ip, large_ips_table[i].ip, 16);
1621 next_hop_expected = large_ips_table[i].next_hop;
1623 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1624 TEST_LPM_ASSERT((status == 0) &&
1625 (next_hop_return == next_hop_expected));
1634 * Test for overwriting of tbl8:
1635 * - add rule /32 and lookup
1636 * - add new rule /24 and lookup
1637 * - add third rule /25 and lookup
1638 * - lookup /32 and /24 rule to ensure the table has not been overwritten.
1643 struct rte_lpm6 *lpm = NULL;
1644 struct rte_lpm6_config config;
1645 uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1646 uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1647 uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1648 uint8_t d_ip_10_32 = 32;
1649 uint8_t d_ip_10_24 = 24;
1650 uint8_t d_ip_20_25 = 25;
1651 uint8_t next_hop_ip_10_32 = 100;
1652 uint8_t next_hop_ip_10_24 = 105;
1653 uint8_t next_hop_ip_20_25 = 111;
1654 uint8_t next_hop_return = 0;
1657 config.max_rules = MAX_RULES;
1658 config.number_tbl8s = NUMBER_TBL8S;
1661 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1662 TEST_LPM_ASSERT(lpm != NULL);
1664 if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32,
1665 next_hop_ip_10_32)) < 0)
1668 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1669 uint8_t test_hop_10_32 = next_hop_return;
1670 TEST_LPM_ASSERT(status == 0);
1671 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1673 if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24,
1674 next_hop_ip_10_24)) < 0)
1677 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1678 uint8_t test_hop_10_24 = next_hop_return;
1679 TEST_LPM_ASSERT(status == 0);
1680 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1682 if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25,
1683 next_hop_ip_20_25)) < 0)
1686 status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return);
1687 uint8_t test_hop_20_25 = next_hop_return;
1688 TEST_LPM_ASSERT(status == 0);
1689 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1691 if (test_hop_10_32 == test_hop_10_24) {
1692 printf("Next hop return equal\n");
1696 if (test_hop_10_24 == test_hop_20_25){
1697 printf("Next hop return equal\n");
1701 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1702 TEST_LPM_ASSERT(status == 0);
1703 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1705 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1706 TEST_LPM_ASSERT(status == 0);
1707 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1715 * Add a rule that reaches the end of the tree.
1716 * Add a rule that is more generic than the first one.
1717 * Check every possible combination that produces a match for the second rule.
1718 * This tests tbl expansion.
1723 struct rte_lpm6 *lpm = NULL;
1724 struct rte_lpm6_config config;
1725 uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0};
1726 uint8_t depth = 128, next_hop_add = 100, next_hop_return;
1730 config.max_rules = MAX_RULES;
1731 config.number_tbl8s = NUMBER_TBL8S;
1734 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1735 TEST_LPM_ASSERT(lpm != NULL);
1739 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1740 TEST_LPM_ASSERT(status == 0);
1744 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1745 TEST_LPM_ASSERT(status == 0);
1747 for (i = 0; i < 256; i++) {
1748 ip[14] = (uint8_t)i;
1749 for (j = 0; j < 256; j++) {
1750 ip[15] = (uint8_t)j;
1751 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1752 if (i == 0 && j == 0)
1753 TEST_LPM_ASSERT(status == 0 && next_hop_return == 128);
1755 TEST_LPM_ASSERT(status == 0 && next_hop_return == 112);
1765 * Lookup performance test
1768 #define ITERATIONS (1 << 10)
1769 #define BATCH_SIZE 100000
1772 print_route_distribution(const struct rules_tbl_entry *table, uint32_t n)
1776 printf("Route distribution per prefix width: \n");
1777 printf("DEPTH QUANTITY (PERCENT)\n");
1778 printf("--------------------------- \n");
1781 for(i = 1; i <= 128; i++) {
1782 unsigned depth_counter = 0;
1783 double percent_hits;
1785 for (j = 0; j < n; j++)
1786 if (table[j].depth == (uint8_t) i)
1789 percent_hits = ((double)depth_counter)/((double)n) * 100;
1790 printf("%.2u%15u (%.2f)\n", i, depth_counter, percent_hits);
1798 struct rte_lpm6 *lpm = NULL;
1799 struct rte_lpm6_config config;
1800 uint64_t begin, total_time;
1802 uint8_t next_hop_add = 0xAA, next_hop_return = 0;
1806 config.max_rules = 1000000;
1807 config.number_tbl8s = NUMBER_TBL8S;
1810 rte_srand(rte_rdtsc());
1812 printf("No. routes = %u\n", (unsigned) NUM_ROUTE_ENTRIES);
1814 print_route_distribution(large_route_table, (uint32_t) NUM_ROUTE_ENTRIES);
1816 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1817 TEST_LPM_ASSERT(lpm != NULL);
1820 begin = rte_rdtsc();
1822 for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1823 if (rte_lpm6_add(lpm, large_route_table[i].ip,
1824 large_route_table[i].depth, next_hop_add) == 0)
1828 total_time = rte_rdtsc() - begin;
1830 printf("Unique added entries = %d\n", status);
1831 printf("Average LPM Add: %g cycles\n",
1832 (double)total_time / NUM_ROUTE_ENTRIES);
1834 /* Measure single Lookup */
1838 for (i = 0; i < ITERATIONS; i ++) {
1839 begin = rte_rdtsc();
1841 for (j = 0; j < NUM_IPS_ENTRIES; j ++) {
1842 if (rte_lpm6_lookup(lpm, large_ips_table[j].ip,
1843 &next_hop_return) != 0)
1847 total_time += rte_rdtsc() - begin;
1850 printf("Average LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1851 (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1852 (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1854 /* Measure bulk Lookup */
1858 uint8_t ip_batch[NUM_IPS_ENTRIES][16];
1859 int16_t next_hops[NUM_IPS_ENTRIES];
1861 for (i = 0; i < NUM_IPS_ENTRIES; i++)
1862 memcpy(ip_batch[i], large_ips_table[i].ip, 16);
1864 for (i = 0; i < ITERATIONS; i ++) {
1866 /* Lookup per batch */
1867 begin = rte_rdtsc();
1868 rte_lpm6_lookup_bulk_func(lpm, ip_batch, next_hops, NUM_IPS_ENTRIES);
1869 total_time += rte_rdtsc() - begin;
1871 for (j = 0; j < NUM_IPS_ENTRIES; j++)
1872 if (next_hops[j] < 0)
1875 printf("BULK LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1876 (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1877 (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1881 begin = rte_rdtsc();
1883 for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1884 /* rte_lpm_delete(lpm, ip, depth) */
1885 status += rte_lpm6_delete(lpm, large_route_table[i].ip,
1886 large_route_table[i].depth);
1889 total_time += rte_rdtsc() - begin;
1891 printf("Average LPM Delete: %g cycles\n",
1892 (double)total_time / NUM_ROUTE_ENTRIES);
1894 rte_lpm6_delete_all(lpm);
1901 * Do all unit and performance tests.
1907 int status = -1, global_status = 0;
1909 for (i = 0; i < NUM_LPM6_TESTS; i++) {
1910 status = tests6[i]();
1913 printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i]));
1914 global_status = status;
1918 return global_status;
1921 static struct test_command lpm6_cmd = {
1922 .command = "lpm6_autotest",
1923 .callback = test_lpm6,
1925 REGISTER_TEST_COMMAND(lpm6_cmd);