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.
38 #include <sys/queue.h>
39 #include <cmdline_parse.h>
47 #include <rte_common.h>
48 #include <rte_cycles.h>
49 #include <rte_memory.h>
50 #include <rte_random.h>
51 #include <rte_branch_prediction.h>
55 #include "test_lpm6_routes.h"
57 #define TEST_LPM_ASSERT(cond) do { \
59 printf("Error at line %d: \n", __LINE__); \
64 typedef int32_t (* rte_lpm6_test)(void);
66 static int32_t test0(void);
67 static int32_t test1(void);
68 static int32_t test2(void);
69 static int32_t test3(void);
70 static int32_t test4(void);
71 static int32_t test5(void);
72 static int32_t test6(void);
73 static int32_t test7(void);
74 static int32_t test8(void);
75 static int32_t test9(void);
76 static int32_t test10(void);
77 static int32_t test11(void);
78 static int32_t test12(void);
79 static int32_t test13(void);
80 static int32_t test14(void);
81 static int32_t test15(void);
82 static int32_t test16(void);
83 static int32_t test17(void);
84 static int32_t test18(void);
85 static int32_t test19(void);
86 static int32_t test20(void);
87 static int32_t test21(void);
88 static int32_t test22(void);
89 static int32_t test23(void);
90 static int32_t test24(void);
91 static int32_t test25(void);
92 static int32_t test26(void);
93 static int32_t test27(void);
94 static int32_t perf_test(void);
96 rte_lpm6_test tests6[] = {
129 #define NUM_LPM6_TESTS (sizeof(tests6)/sizeof(tests6[0]))
130 #define RTE_LPM6_TBL24_NUM_ENTRIES (1 << 24)
131 #define RTE_LPM6_LOOKUP_SUCCESS 0x04000000
132 #define MAX_DEPTH 128
133 #define MAX_RULES 1000000
134 #define NUMBER_TBL8S (1 << 16)
135 #define MAX_NUM_TBL8S (1 << 21)
139 IPv6(uint8_t *ip, uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint8_t b5,
140 uint8_t b6, uint8_t b7, uint8_t b8, uint8_t b9, uint8_t b10,
141 uint8_t b11, uint8_t b12, uint8_t b13, uint8_t b14, uint8_t b15,
163 * Check that rte_lpm6_create fails gracefully for incorrect user input
169 struct rte_lpm6 *lpm = NULL;
170 struct rte_lpm6_config config;
172 config.max_rules = MAX_RULES;
173 config.number_tbl8s = NUMBER_TBL8S;
176 /* rte_lpm6_create: lpm name == NULL */
177 lpm = rte_lpm6_create(NULL, SOCKET_ID_ANY, &config);
178 TEST_LPM_ASSERT(lpm == NULL);
180 /* rte_lpm6_create: max_rules = 0 */
181 /* Note: __func__ inserts the function name, in this case "test0". */
182 config.max_rules = 0;
183 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
184 TEST_LPM_ASSERT(lpm == NULL);
186 /* socket_id < -1 is invalid */
187 config.max_rules = MAX_RULES;
188 lpm = rte_lpm6_create(__func__, -2, &config);
189 TEST_LPM_ASSERT(lpm == NULL);
191 /* rte_lpm6_create: number_tbl8s is bigger than the maximum */
192 config.number_tbl8s = MAX_NUM_TBL8S + 1;
193 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
194 TEST_LPM_ASSERT(lpm == NULL);
196 /* rte_lpm6_create: config = NULL */
197 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, NULL);
198 TEST_LPM_ASSERT(lpm == NULL);
204 * Creates two different LPM tables. Tries to create a third one with the same
205 * name as the first one and expects the create function to return the same
211 struct rte_lpm6 *lpm1 = NULL, *lpm2 = NULL, *lpm3 = NULL;
212 struct rte_lpm6_config config;
214 config.max_rules = MAX_RULES;
215 config.number_tbl8s = NUMBER_TBL8S;
218 /* rte_lpm6_create: lpm name == LPM1 */
219 lpm1 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
220 TEST_LPM_ASSERT(lpm1 != NULL);
222 /* rte_lpm6_create: lpm name == LPM2 */
223 lpm2 = rte_lpm6_create("LPM2", SOCKET_ID_ANY, &config);
224 TEST_LPM_ASSERT(lpm2 != NULL);
226 /* rte_lpm6_create: lpm name == LPM2 */
227 lpm3 = rte_lpm6_create("LPM1", SOCKET_ID_ANY, &config);
228 TEST_LPM_ASSERT(lpm3 == lpm1);
237 * Create lpm table then delete lpm table 100 times
238 * Use a slightly different rules size each time
243 struct rte_lpm6 *lpm = NULL;
244 struct rte_lpm6_config config;
247 config.number_tbl8s = NUMBER_TBL8S;
250 /* rte_lpm6_free: Free NULL */
251 for (i = 0; i < 100; i++) {
252 config.max_rules = MAX_RULES - i;
253 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
254 TEST_LPM_ASSERT(lpm != NULL);
259 /* Can not test free so return success */
264 * Call rte_lpm6_free for NULL pointer user input. Note: free has no return and
265 * therefore it is impossible to check for failure but this test is added to
266 * increase function coverage metrics and to validate that freeing null does
272 struct rte_lpm6 *lpm = NULL;
273 struct rte_lpm6_config config;
275 config.max_rules = MAX_RULES;
276 config.number_tbl8s = NUMBER_TBL8S;
279 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
280 TEST_LPM_ASSERT(lpm != NULL);
288 * Check that rte_lpm6_add fails gracefully for incorrect user input arguments
293 struct rte_lpm6 *lpm = NULL;
294 struct rte_lpm6_config config;
296 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
297 uint8_t depth = 24, next_hop = 100;
300 config.max_rules = MAX_RULES;
301 config.number_tbl8s = NUMBER_TBL8S;
304 /* rte_lpm6_add: lpm == NULL */
305 status = rte_lpm6_add(NULL, ip, depth, next_hop);
306 TEST_LPM_ASSERT(status < 0);
308 /*Create vaild lpm to use in rest of test. */
309 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
310 TEST_LPM_ASSERT(lpm != NULL);
312 /* rte_lpm6_add: depth < 1 */
313 status = rte_lpm6_add(lpm, ip, 0, next_hop);
314 TEST_LPM_ASSERT(status < 0);
316 /* rte_lpm6_add: depth > MAX_DEPTH */
317 status = rte_lpm6_add(lpm, ip, (MAX_DEPTH + 1), next_hop);
318 TEST_LPM_ASSERT(status < 0);
326 * Check that rte_lpm6_delete fails gracefully for incorrect user input
332 struct rte_lpm6 *lpm = NULL;
333 struct rte_lpm6_config config;
334 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
338 config.max_rules = MAX_RULES;
339 config.number_tbl8s = NUMBER_TBL8S;
342 /* rte_lpm_delete: lpm == NULL */
343 status = rte_lpm6_delete(NULL, ip, depth);
344 TEST_LPM_ASSERT(status < 0);
346 /*Create vaild lpm to use in rest of test. */
347 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
348 TEST_LPM_ASSERT(lpm != NULL);
350 /* rte_lpm_delete: depth < 1 */
351 status = rte_lpm6_delete(lpm, ip, 0);
352 TEST_LPM_ASSERT(status < 0);
354 /* rte_lpm_delete: depth > MAX_DEPTH */
355 status = rte_lpm6_delete(lpm, ip, (MAX_DEPTH + 1));
356 TEST_LPM_ASSERT(status < 0);
364 * Check that rte_lpm6_lookup fails gracefully for incorrect user input
370 struct rte_lpm6 *lpm = NULL;
371 struct rte_lpm6_config config;
372 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
373 uint8_t next_hop_return = 0;
376 config.max_rules = MAX_RULES;
377 config.number_tbl8s = NUMBER_TBL8S;
380 /* rte_lpm6_lookup: lpm == NULL */
381 status = rte_lpm6_lookup(NULL, ip, &next_hop_return);
382 TEST_LPM_ASSERT(status < 0);
384 /*Create vaild lpm to use in rest of test. */
385 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
386 TEST_LPM_ASSERT(lpm != NULL);
388 /* rte_lpm6_lookup: ip = NULL */
389 status = rte_lpm6_lookup(lpm, NULL, &next_hop_return);
390 TEST_LPM_ASSERT(status < 0);
392 /* rte_lpm6_lookup: next_hop = NULL */
393 status = rte_lpm6_lookup(lpm, ip, NULL);
394 TEST_LPM_ASSERT(status < 0);
402 * Checks that rte_lpm6_lookup_bulk_func fails gracefully for incorrect user
408 struct rte_lpm6 *lpm = NULL;
409 struct rte_lpm6_config config;
411 int16_t next_hop_return[10];
414 config.max_rules = MAX_RULES;
415 config.number_tbl8s = NUMBER_TBL8S;
418 /* rte_lpm6_lookup: lpm == NULL */
419 status = rte_lpm6_lookup_bulk_func(NULL, ip, next_hop_return, 10);
420 TEST_LPM_ASSERT(status < 0);
422 /*Create vaild lpm to use in rest of test. */
423 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
424 TEST_LPM_ASSERT(lpm != NULL);
426 /* rte_lpm6_lookup: ip = NULL */
427 status = rte_lpm6_lookup_bulk_func(lpm, NULL, next_hop_return, 10);
428 TEST_LPM_ASSERT(status < 0);
430 /* rte_lpm6_lookup: next_hop = NULL */
431 status = rte_lpm6_lookup_bulk_func(lpm, ip, NULL, 10);
432 TEST_LPM_ASSERT(status < 0);
440 * Checks that rte_lpm6_delete_bulk_func fails gracefully for incorrect user
446 struct rte_lpm6 *lpm = NULL;
447 struct rte_lpm6_config config;
452 config.max_rules = MAX_RULES;
453 config.number_tbl8s = NUMBER_TBL8S;
456 /* rte_lpm6_delete: lpm == NULL */
457 status = rte_lpm6_delete_bulk_func(NULL, ip, depth, 10);
458 TEST_LPM_ASSERT(status < 0);
460 /*Create vaild lpm to use in rest of test. */
461 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
462 TEST_LPM_ASSERT(lpm != NULL);
464 /* rte_lpm6_delete: ip = NULL */
465 status = rte_lpm6_delete_bulk_func(lpm, NULL, depth, 10);
466 TEST_LPM_ASSERT(status < 0);
468 /* rte_lpm6_delete: next_hop = NULL */
469 status = rte_lpm6_delete_bulk_func(lpm, ip, NULL, 10);
470 TEST_LPM_ASSERT(status < 0);
478 * Call add, lookup and delete for a single rule with depth < 24.
479 * Check all the combinations for the first three bytes that result in a hit.
480 * Delete the rule and check that the same test returs a miss.
485 struct rte_lpm6 *lpm = NULL;
486 struct rte_lpm6_config config;
487 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
488 uint8_t depth = 16, next_hop_add = 100, next_hop_return = 0;
492 config.max_rules = MAX_RULES;
493 config.number_tbl8s = NUMBER_TBL8S;
496 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
497 TEST_LPM_ASSERT(lpm != NULL);
499 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
500 TEST_LPM_ASSERT(status == 0);
502 for (i = 0; i < UINT8_MAX; i++) {
504 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
505 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
508 status = rte_lpm6_delete(lpm, ip, depth);
509 TEST_LPM_ASSERT(status == 0);
511 for (i = 0; i < UINT8_MAX; i++) {
513 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
514 TEST_LPM_ASSERT(status == -ENOENT);
523 * Adds max_rules + 1 and expects a failure. Deletes a rule, then adds
524 * another one and expects success.
529 struct rte_lpm6 *lpm = NULL;
530 struct rte_lpm6_config config;
531 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
532 uint8_t depth, next_hop_add = 100;
536 config.max_rules = 127;
537 config.number_tbl8s = NUMBER_TBL8S;
540 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
541 TEST_LPM_ASSERT(lpm != NULL);
543 for (i = 1; i < 128; i++) {
545 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
546 TEST_LPM_ASSERT(status == 0);
550 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
551 TEST_LPM_ASSERT(status == -ENOSPC);
554 status = rte_lpm6_delete(lpm, ip, depth);
555 TEST_LPM_ASSERT(status == 0);
558 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
559 TEST_LPM_ASSERT(status == 0);
567 * Creates an LPM table with a small number of tbl8s and exhaust them in the
568 * middle of the process of creating a rule.
573 struct rte_lpm6 *lpm = NULL;
574 struct rte_lpm6_config config;
575 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
576 uint8_t depth, next_hop_add = 100;
579 config.max_rules = MAX_RULES;
580 config.number_tbl8s = 16;
583 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
584 TEST_LPM_ASSERT(lpm != NULL);
587 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
588 TEST_LPM_ASSERT(status == 0);
592 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
593 TEST_LPM_ASSERT(status == 0);
595 status = rte_lpm6_delete(lpm, ip, depth);
596 TEST_LPM_ASSERT(status == 0);
599 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
600 TEST_LPM_ASSERT(status == 0);
602 status = rte_lpm6_delete(lpm, ip, depth);
603 TEST_LPM_ASSERT(status == 0);
606 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
607 TEST_LPM_ASSERT(status == 0);
609 status = rte_lpm6_delete(lpm, ip, depth);
610 TEST_LPM_ASSERT(status == 0);
613 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
614 TEST_LPM_ASSERT(status == -ENOSPC);
617 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
618 TEST_LPM_ASSERT(status == 0);
626 * Creates an LPM table with a small number of tbl8s and exhaust them in the
627 * middle of the process of adding a rule when there is already an existing rule
628 * in that position and needs to be extended.
633 struct rte_lpm6 *lpm = NULL;
634 struct rte_lpm6_config config;
635 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
636 uint8_t depth, next_hop_add = 100;
639 config.max_rules = MAX_RULES;
640 config.number_tbl8s = 16;
643 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
644 TEST_LPM_ASSERT(lpm != NULL);
647 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
648 TEST_LPM_ASSERT(status == 0);
652 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
653 TEST_LPM_ASSERT(status == 0);
656 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
657 TEST_LPM_ASSERT(status == -ENOSPC);
665 * Creates an LPM table with max_rules = 2 and tries to add 3 rules.
666 * Delete one of the rules and tries to add the third one again.
671 struct rte_lpm6 *lpm = NULL;
672 struct rte_lpm6_config config;
673 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
674 uint8_t depth, next_hop_add = 100;
677 config.max_rules = 2;
678 config.number_tbl8s = NUMBER_TBL8S;
681 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
682 TEST_LPM_ASSERT(lpm != NULL);
685 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
686 TEST_LPM_ASSERT(status == 0);
689 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
690 TEST_LPM_ASSERT(status == 0);
693 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
694 TEST_LPM_ASSERT(status == -ENOSPC);
697 status = rte_lpm6_delete(lpm, ip, depth);
698 TEST_LPM_ASSERT(status == 0);
701 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
702 TEST_LPM_ASSERT(status == 0);
710 * Add 2^16 routes with different first 16 bits and depth 25.
711 * Add one more route with the same depth and check that results in a failure.
712 * After that delete the last rule and create the one that was attempted to be
713 * created. This checks tbl8 exhaustion.
718 struct rte_lpm6 *lpm = NULL;
719 struct rte_lpm6_config config;
720 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
721 uint8_t depth = 25, next_hop_add = 100;
725 config.max_rules = MAX_RULES;
726 config.number_tbl8s = NUMBER_TBL8S;
729 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
730 TEST_LPM_ASSERT(lpm != NULL);
732 for (i = 0; i < 256; i++) {
734 for (j = 0; j < 256; j++) {
736 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
737 TEST_LPM_ASSERT(status == 0);
744 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
745 TEST_LPM_ASSERT(status == -ENOSPC);
750 status = rte_lpm6_delete(lpm, ip, depth);
751 TEST_LPM_ASSERT(status == 0);
756 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
757 TEST_LPM_ASSERT(status == 0);
765 * Call add, lookup and delete for a single rule with depth = 24
770 struct rte_lpm6 *lpm = NULL;
771 struct rte_lpm6_config config;
772 uint8_t ip[] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
773 uint8_t depth = 24, next_hop_add = 100, next_hop_return = 0;
776 config.max_rules = MAX_RULES;
777 config.number_tbl8s = NUMBER_TBL8S;
780 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
781 TEST_LPM_ASSERT(lpm != NULL);
783 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
784 TEST_LPM_ASSERT(status == 0);
786 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
787 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
789 status = rte_lpm6_delete(lpm, ip, depth);
790 TEST_LPM_ASSERT(status == 0);
792 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
793 TEST_LPM_ASSERT(status == -ENOENT);
801 * Call add, lookup and delete for a single rule with depth > 24
806 struct rte_lpm6 *lpm = NULL;
807 struct rte_lpm6_config config;
808 uint8_t ip[] = {12,12,1,0,0,0,0,0,0,0,0,0,0,0,0,0};
809 uint8_t depth = 128, next_hop_add = 100, next_hop_return = 0;
812 config.max_rules = MAX_RULES;
813 config.number_tbl8s = NUMBER_TBL8S;
816 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
817 TEST_LPM_ASSERT(lpm != NULL);
819 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
820 TEST_LPM_ASSERT(status == 0);
822 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
823 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
825 status = rte_lpm6_delete(lpm, ip, depth);
826 TEST_LPM_ASSERT(status == 0);
828 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
829 TEST_LPM_ASSERT(status == -ENOENT);
837 * Use rte_lpm6_add to add rules which effect only the second half of the lpm
838 * table. Use all possible depths ranging from 1..32. Set the next hop = to the
839 * depth. Check lookup hit for on every add and check for lookup miss on the
840 * first half of the lpm table after each add. Finally delete all rules going
841 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
842 * delete. The lookup should return the next_hop_add value related to the
843 * previous depth value (i.e. depth -1).
848 struct rte_lpm6 *lpm = NULL;
849 struct rte_lpm6_config config;
850 uint8_t ip1[] = {127,255,255,255,255,255,255,255,255,
851 255,255,255,255,255,255,255};
852 uint8_t ip2[] = {128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
853 uint8_t depth, next_hop_add, next_hop_return;
856 config.max_rules = MAX_RULES;
857 config.number_tbl8s = NUMBER_TBL8S;
860 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
861 TEST_LPM_ASSERT(lpm != NULL);
863 /* Loop with rte_lpm6_add. */
864 for (depth = 1; depth <= 128; depth++) {
865 /* Let the next_hop_add value = depth. Just for change. */
866 next_hop_add = depth;
868 status = rte_lpm6_add(lpm, ip2, depth, next_hop_add);
869 TEST_LPM_ASSERT(status == 0);
871 /* Check IP in first half of tbl24 which should be empty. */
872 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
873 TEST_LPM_ASSERT(status == -ENOENT);
875 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
876 TEST_LPM_ASSERT((status == 0) &&
877 (next_hop_return == next_hop_add));
880 /* Loop with rte_lpm6_delete. */
881 for (depth = 128; depth >= 1; depth--) {
882 next_hop_add = (uint8_t) (depth - 1);
884 status = rte_lpm6_delete(lpm, ip2, depth);
885 TEST_LPM_ASSERT(status == 0);
887 status = rte_lpm6_lookup(lpm, ip2, &next_hop_return);
890 TEST_LPM_ASSERT((status == 0) &&
891 (next_hop_return == next_hop_add));
894 TEST_LPM_ASSERT(status == -ENOENT);
897 status = rte_lpm6_lookup(lpm, ip1, &next_hop_return);
898 TEST_LPM_ASSERT(status == -ENOENT);
907 * - Add & lookup to hit invalid TBL24 entry
908 * - Add & lookup to hit valid TBL24 entry not extended
909 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
910 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
915 struct rte_lpm6 *lpm = NULL;
916 struct rte_lpm6_config config;
917 uint8_t ip[16], ip_1[16], ip_2[16];
918 uint8_t depth, depth_1, depth_2, next_hop_add, next_hop_add_1,
919 next_hop_add_2, next_hop_return;
922 config.max_rules = MAX_RULES;
923 config.number_tbl8s = NUMBER_TBL8S;
926 /* Add & lookup to hit invalid TBL24 entry */
927 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
931 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
932 TEST_LPM_ASSERT(lpm != NULL);
934 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
935 TEST_LPM_ASSERT(status == 0);
937 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
938 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
940 status = rte_lpm6_delete(lpm, ip, depth);
941 TEST_LPM_ASSERT(status == 0);
943 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
944 TEST_LPM_ASSERT(status == -ENOENT);
946 rte_lpm6_delete_all(lpm);
948 /* Add & lookup to hit valid TBL24 entry not extended */
949 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
953 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
954 TEST_LPM_ASSERT(status == 0);
956 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
957 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
962 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
963 TEST_LPM_ASSERT(status == 0);
965 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
966 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
970 status = rte_lpm6_delete(lpm, ip, depth);
971 TEST_LPM_ASSERT(status == 0);
975 status = rte_lpm6_delete(lpm, ip, depth);
976 TEST_LPM_ASSERT(status == 0);
978 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
979 TEST_LPM_ASSERT(status == -ENOENT);
981 rte_lpm6_delete_all(lpm);
983 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
986 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
990 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
991 TEST_LPM_ASSERT(status == 0);
993 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
994 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
996 IPv6(ip, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1000 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1001 TEST_LPM_ASSERT(status == 0);
1003 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1004 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1006 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1010 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1011 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1013 status = rte_lpm6_delete(lpm, ip, depth);
1014 TEST_LPM_ASSERT(status == 0);
1016 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1017 TEST_LPM_ASSERT(status == -ENOENT);
1019 rte_lpm6_delete_all(lpm);
1021 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
1024 IPv6(ip_1, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1026 next_hop_add_1 = 101;
1028 IPv6(ip_2, 128, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1030 next_hop_add_2 = 102;
1032 next_hop_return = 0;
1034 status = rte_lpm6_add(lpm, ip_1, depth_1, next_hop_add_1);
1035 TEST_LPM_ASSERT(status == 0);
1037 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1038 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1040 status = rte_lpm6_add(lpm, ip_2, depth_2, next_hop_add_2);
1041 TEST_LPM_ASSERT(status == 0);
1043 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1044 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
1046 status = rte_lpm6_delete(lpm, ip_2, depth_2);
1047 TEST_LPM_ASSERT(status == 0);
1049 status = rte_lpm6_lookup(lpm, ip_2, &next_hop_return);
1050 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
1052 status = rte_lpm6_delete(lpm, ip_1, depth_1);
1053 TEST_LPM_ASSERT(status == 0);
1055 status = rte_lpm6_lookup(lpm, ip_1, &next_hop_return);
1056 TEST_LPM_ASSERT(status == -ENOENT);
1064 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
1066 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
1067 * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
1069 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
1070 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
1071 * - Delete a rule that is not present in the TBL24 & lookup
1072 * - Delete a rule that is not present in the TBL8 & lookup
1077 struct rte_lpm6 *lpm = NULL;
1078 struct rte_lpm6_config config;
1080 uint8_t depth, next_hop_add, next_hop_return;
1083 config.max_rules = MAX_RULES;
1084 config.number_tbl8s = NUMBER_TBL8S;
1087 /* Add rule that covers a TBL24 range previously invalid & lookup
1088 * (& delete & lookup)
1090 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1091 TEST_LPM_ASSERT(lpm != NULL);
1093 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1097 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1098 TEST_LPM_ASSERT(status == 0);
1100 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1101 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1103 status = rte_lpm6_delete(lpm, ip, depth);
1104 TEST_LPM_ASSERT(status == 0);
1106 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1107 TEST_LPM_ASSERT(status == -ENOENT);
1109 rte_lpm6_delete_all(lpm);
1111 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1115 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1116 TEST_LPM_ASSERT(status == 0);
1118 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1119 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1121 status = rte_lpm6_delete(lpm, ip, depth);
1122 TEST_LPM_ASSERT(status == 0);
1124 rte_lpm6_delete_all(lpm);
1127 * Add rule that extends a TBL24 valid entry & lookup for both rules
1128 * (& delete & lookup)
1131 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1135 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1136 TEST_LPM_ASSERT(status == 0);
1138 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1142 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1143 TEST_LPM_ASSERT(status == 0);
1145 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1146 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1148 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1151 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1152 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1154 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1157 status = rte_lpm6_delete(lpm, ip, depth);
1158 TEST_LPM_ASSERT(status == 0);
1160 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1161 TEST_LPM_ASSERT(status == -ENOENT);
1163 IPv6(ip, 128, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1166 status = rte_lpm6_delete(lpm, ip, depth);
1167 TEST_LPM_ASSERT(status == 0);
1169 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1170 TEST_LPM_ASSERT(status == -ENOENT);
1172 rte_lpm6_delete_all(lpm);
1175 * Add rule that updates the next hop in TBL24 & lookup
1176 * (& delete & lookup)
1179 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1183 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1184 TEST_LPM_ASSERT(status == 0);
1186 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1187 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1191 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1192 TEST_LPM_ASSERT(status == 0);
1194 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1195 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1197 status = rte_lpm6_delete(lpm, ip, depth);
1198 TEST_LPM_ASSERT(status == 0);
1200 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1201 TEST_LPM_ASSERT(status == -ENOENT);
1203 rte_lpm6_delete_all(lpm);
1206 * Add rule that updates the next hop in TBL8 & lookup
1207 * (& delete & lookup)
1210 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1214 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1215 TEST_LPM_ASSERT(status == 0);
1217 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1218 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1222 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1223 TEST_LPM_ASSERT(status == 0);
1225 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1226 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1228 status = rte_lpm6_delete(lpm, ip, depth);
1229 TEST_LPM_ASSERT(status == 0);
1231 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1232 TEST_LPM_ASSERT(status == -ENOENT);
1234 rte_lpm6_delete_all(lpm);
1236 /* Delete a rule that is not present in the TBL24 & lookup */
1238 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1242 status = rte_lpm6_delete(lpm, ip, depth);
1243 TEST_LPM_ASSERT(status < 0);
1245 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1246 TEST_LPM_ASSERT(status == -ENOENT);
1248 rte_lpm6_delete_all(lpm);
1250 /* Delete a rule that is not present in the TBL8 & lookup */
1252 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1256 status = rte_lpm6_delete(lpm, ip, depth);
1257 TEST_LPM_ASSERT(status < 0);
1259 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1260 TEST_LPM_ASSERT(status == -ENOENT);
1268 * Add two rules, lookup to hit the more specific one, lookup to hit the less
1269 * specific one delete the less specific rule and lookup previous values again;
1270 * add a more specific rule than the existing rule, lookup again
1275 struct rte_lpm6 *lpm = NULL;
1276 struct rte_lpm6_config config;
1278 uint8_t depth, next_hop_add, next_hop_return;
1281 config.max_rules = MAX_RULES;
1282 config.number_tbl8s = NUMBER_TBL8S;
1285 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1286 TEST_LPM_ASSERT(lpm != NULL);
1288 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1292 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1293 TEST_LPM_ASSERT(status == 0);
1295 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1299 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1300 TEST_LPM_ASSERT(status == 0);
1302 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1303 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1305 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1308 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1309 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
1311 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1314 status = rte_lpm6_delete(lpm, ip, depth);
1315 TEST_LPM_ASSERT(status == 0);
1317 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1318 TEST_LPM_ASSERT(status == -ENOENT);
1320 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10);
1323 status = rte_lpm6_delete(lpm, ip, depth);
1324 TEST_LPM_ASSERT(status == 0);
1326 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1327 TEST_LPM_ASSERT(status == -ENOENT);
1335 * Adds 3 rules and look them up through the lookup_bulk function.
1336 * Includes in the lookup a fourth IP address that won't match
1337 * and checks that the result is as expected.
1342 struct rte_lpm6 *lpm = NULL;
1343 struct rte_lpm6_config config;
1344 uint8_t ip_batch[4][16];
1345 uint8_t depth, next_hop_add;
1346 int16_t next_hop_return[4];
1349 config.max_rules = MAX_RULES;
1350 config.number_tbl8s = NUMBER_TBL8S;
1353 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1354 TEST_LPM_ASSERT(lpm != NULL);
1356 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1360 status = rte_lpm6_add(lpm, ip_batch[0], depth, next_hop_add);
1361 TEST_LPM_ASSERT(status == 0);
1363 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1367 status = rte_lpm6_add(lpm, ip_batch[1], depth, next_hop_add);
1368 TEST_LPM_ASSERT(status == 0);
1370 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1374 status = rte_lpm6_add(lpm, ip_batch[2], depth, next_hop_add);
1375 TEST_LPM_ASSERT(status == 0);
1377 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1379 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1380 next_hop_return, 4);
1381 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 100
1382 && next_hop_return[1] == 101 && next_hop_return[2] == 102
1383 && next_hop_return[3] == -1);
1391 * Adds 5 rules and look them up.
1392 * Use the delete_bulk function to delete two of them. Lookup again.
1393 * Use the delete_bulk function to delete one more. Lookup again.
1394 * Use the delete_bulk function to delete two more, one invalid. Lookup again.
1395 * Use the delete_bulk function to delete the remaining one. Lookup again.
1400 struct rte_lpm6 *lpm = NULL;
1401 struct rte_lpm6_config config;
1402 uint8_t ip_batch[5][16];
1403 uint8_t depth[5], next_hop_add;
1404 int16_t next_hop_return[5];
1407 config.max_rules = MAX_RULES;
1408 config.number_tbl8s = NUMBER_TBL8S;
1411 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1412 TEST_LPM_ASSERT(lpm != NULL);
1414 /* Adds 5 rules and look them up */
1416 IPv6(ip_batch[0], 128, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1420 status = rte_lpm6_add(lpm, ip_batch[0], depth[0], next_hop_add);
1421 TEST_LPM_ASSERT(status == 0);
1423 IPv6(ip_batch[1], 128, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1427 status = rte_lpm6_add(lpm, ip_batch[1], depth[1], next_hop_add);
1428 TEST_LPM_ASSERT(status == 0);
1430 IPv6(ip_batch[2], 128, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1434 status = rte_lpm6_add(lpm, ip_batch[2], depth[2], next_hop_add);
1435 TEST_LPM_ASSERT(status == 0);
1437 IPv6(ip_batch[3], 128, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1441 status = rte_lpm6_add(lpm, ip_batch[3], depth[3], next_hop_add);
1442 TEST_LPM_ASSERT(status == 0);
1444 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1448 status = rte_lpm6_add(lpm, ip_batch[4], depth[4], next_hop_add);
1449 TEST_LPM_ASSERT(status == 0);
1451 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1452 next_hop_return, 5);
1453 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == 101
1454 && next_hop_return[1] == 102 && next_hop_return[2] == 103
1455 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1457 /* Use the delete_bulk function to delete two of them. Lookup again */
1459 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[0], depth, 2);
1460 TEST_LPM_ASSERT(status == 0);
1462 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1463 next_hop_return, 5);
1464 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1465 && next_hop_return[1] == -1 && next_hop_return[2] == 103
1466 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1468 /* Use the delete_bulk function to delete one more. Lookup again */
1470 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[2], depth, 1);
1471 TEST_LPM_ASSERT(status == 0);
1473 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1474 next_hop_return, 5);
1475 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1476 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1477 && next_hop_return[3] == 104 && next_hop_return[4] == 105);
1479 /* Use the delete_bulk function to delete two, one invalid. Lookup again */
1481 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1482 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[3], depth, 2);
1483 TEST_LPM_ASSERT(status == 0);
1485 IPv6(ip_batch[4], 128, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1486 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1487 next_hop_return, 5);
1488 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1489 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1490 && next_hop_return[3] == -1 && next_hop_return[4] == 105);
1492 /* Use the delete_bulk function to delete the remaining one. Lookup again */
1494 status = rte_lpm6_delete_bulk_func(lpm, &ip_batch[4], depth, 1);
1495 TEST_LPM_ASSERT(status == 0);
1497 status = rte_lpm6_lookup_bulk_func(lpm, ip_batch,
1498 next_hop_return, 5);
1499 TEST_LPM_ASSERT(status == 0 && next_hop_return[0] == -1
1500 && next_hop_return[1] == -1 && next_hop_return[2] == -1
1501 && next_hop_return[3] == -1 && next_hop_return[4] == -1);
1509 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
1510 * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension
1516 struct rte_lpm6 *lpm = NULL;
1517 struct rte_lpm6_config config;
1520 uint8_t depth, next_hop_add, next_hop_return;
1523 config.max_rules = MAX_RULES;
1524 config.number_tbl8s = NUMBER_TBL8S;
1527 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1528 TEST_LPM_ASSERT(lpm != NULL);
1530 IPv6(ip, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
1534 for (i = 0; i < 1000; i++) {
1535 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1536 TEST_LPM_ASSERT(status == 0);
1538 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1539 TEST_LPM_ASSERT((status == 0) &&
1540 (next_hop_return == next_hop_add));
1542 status = rte_lpm6_delete(lpm, ip, depth);
1543 TEST_LPM_ASSERT(status == 0);
1545 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1546 TEST_LPM_ASSERT(status == -ENOENT);
1555 * Sequence of operations for find existing lpm table
1558 * - find existing table: hit
1559 * - find non-existing table: miss
1564 struct rte_lpm6 *lpm = NULL, *result = NULL;
1565 struct rte_lpm6_config config;
1567 config.max_rules = 256 * 32;
1568 config.number_tbl8s = NUMBER_TBL8S;
1572 lpm = rte_lpm6_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1573 TEST_LPM_ASSERT(lpm != NULL);
1575 /* Try to find existing lpm */
1576 result = rte_lpm6_find_existing("lpm_find_existing");
1577 TEST_LPM_ASSERT(result == lpm);
1579 /* Try to find non-existing lpm */
1580 result = rte_lpm6_find_existing("lpm_find_non_existing");
1581 TEST_LPM_ASSERT(result == NULL);
1584 rte_lpm6_delete_all(lpm);
1591 * Add a set of random routes with random depths.
1592 * Lookup different IP addresses that match the routes previously added.
1593 * Checks that the next hop is the expected one.
1594 * The routes, IP addresses and expected result for every case have been
1595 * precalculated by using a python script and stored in a .h file.
1600 struct rte_lpm6 *lpm = NULL;
1601 struct rte_lpm6_config config;
1604 uint8_t depth, next_hop_add, next_hop_return, next_hop_expected;
1607 config.max_rules = MAX_RULES;
1608 config.number_tbl8s = NUMBER_TBL8S;
1611 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1612 TEST_LPM_ASSERT(lpm != NULL);
1614 for (i = 0; i < 1000; i++) {
1615 memcpy(ip, large_route_table[i].ip, 16);
1616 depth = large_route_table[i].depth;
1617 next_hop_add = large_route_table[i].next_hop;
1618 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1619 TEST_LPM_ASSERT(status == 0);
1622 for (i = 0; i < 100000; i++) {
1623 memcpy(ip, large_ips_table[i].ip, 16);
1624 next_hop_expected = large_ips_table[i].next_hop;
1626 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1627 TEST_LPM_ASSERT((status == 0) &&
1628 (next_hop_return == next_hop_expected));
1637 * Test for overwriting of tbl8:
1638 * - add rule /32 and lookup
1639 * - add new rule /24 and lookup
1640 * - add third rule /25 and lookup
1641 * - lookup /32 and /24 rule to ensure the table has not been overwritten.
1646 struct rte_lpm6 *lpm = NULL;
1647 struct rte_lpm6_config config;
1648 uint8_t ip_10_32[] = {10, 10, 10, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1649 uint8_t ip_10_24[] = {10, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1650 uint8_t ip_20_25[] = {10, 10, 20, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1651 uint8_t d_ip_10_32 = 32;
1652 uint8_t d_ip_10_24 = 24;
1653 uint8_t d_ip_20_25 = 25;
1654 uint8_t next_hop_ip_10_32 = 100;
1655 uint8_t next_hop_ip_10_24 = 105;
1656 uint8_t next_hop_ip_20_25 = 111;
1657 uint8_t next_hop_return = 0;
1660 config.max_rules = MAX_RULES;
1661 config.number_tbl8s = NUMBER_TBL8S;
1664 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1665 TEST_LPM_ASSERT(lpm != NULL);
1667 if ((status = rte_lpm6_add(lpm, ip_10_32, d_ip_10_32,
1668 next_hop_ip_10_32)) < 0)
1671 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1672 uint8_t test_hop_10_32 = next_hop_return;
1673 TEST_LPM_ASSERT(status == 0);
1674 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1676 if ((status = rte_lpm6_add(lpm, ip_10_24, d_ip_10_24,
1677 next_hop_ip_10_24)) < 0)
1680 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1681 uint8_t test_hop_10_24 = next_hop_return;
1682 TEST_LPM_ASSERT(status == 0);
1683 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1685 if ((status = rte_lpm6_add(lpm, ip_20_25, d_ip_20_25,
1686 next_hop_ip_20_25)) < 0)
1689 status = rte_lpm6_lookup(lpm, ip_20_25, &next_hop_return);
1690 uint8_t test_hop_20_25 = next_hop_return;
1691 TEST_LPM_ASSERT(status == 0);
1692 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1694 if (test_hop_10_32 == test_hop_10_24) {
1695 printf("Next hop return equal\n");
1699 if (test_hop_10_24 == test_hop_20_25){
1700 printf("Next hop return equal\n");
1704 status = rte_lpm6_lookup(lpm, ip_10_32, &next_hop_return);
1705 TEST_LPM_ASSERT(status == 0);
1706 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1708 status = rte_lpm6_lookup(lpm, ip_10_24, &next_hop_return);
1709 TEST_LPM_ASSERT(status == 0);
1710 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1718 * Add a rule that reaches the end of the tree.
1719 * Add a rule that is more generic than the first one.
1720 * Check every possible combination that produces a match for the second rule.
1721 * This tests tbl expansion.
1726 struct rte_lpm6 *lpm = NULL;
1727 struct rte_lpm6_config config;
1728 uint8_t ip[] = {128,128,128,128,128,128,128,128,128,128,128,128,128,128,0,0};
1729 uint8_t depth = 128, next_hop_add = 100, next_hop_return;
1733 config.max_rules = MAX_RULES;
1734 config.number_tbl8s = NUMBER_TBL8S;
1737 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1738 TEST_LPM_ASSERT(lpm != NULL);
1742 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1743 TEST_LPM_ASSERT(status == 0);
1747 status = rte_lpm6_add(lpm, ip, depth, next_hop_add);
1748 TEST_LPM_ASSERT(status == 0);
1750 for (i = 0; i < 256; i++) {
1751 ip[14] = (uint8_t)i;
1752 for (j = 0; j < 256; j++) {
1753 ip[15] = (uint8_t)j;
1754 status = rte_lpm6_lookup(lpm, ip, &next_hop_return);
1755 if (i == 0 && j == 0)
1756 TEST_LPM_ASSERT(status == 0 && next_hop_return == 128);
1758 TEST_LPM_ASSERT(status == 0 && next_hop_return == 112);
1768 * Lookup performance test
1771 #define ITERATIONS (1 << 10)
1772 #define BATCH_SIZE 100000
1775 print_route_distribution(const struct rules_tbl_entry *table, uint32_t n)
1779 printf("Route distribution per prefix width: \n");
1780 printf("DEPTH QUANTITY (PERCENT)\n");
1781 printf("--------------------------- \n");
1784 for(i = 1; i <= 128; i++) {
1785 unsigned depth_counter = 0;
1786 double percent_hits;
1788 for (j = 0; j < n; j++)
1789 if (table[j].depth == (uint8_t) i)
1792 percent_hits = ((double)depth_counter)/((double)n) * 100;
1793 printf("%.2u%15u (%.2f)\n", i, depth_counter, percent_hits);
1801 struct rte_lpm6 *lpm = NULL;
1802 struct rte_lpm6_config config;
1803 uint64_t begin, total_time;
1805 uint8_t next_hop_add = 0xAA, next_hop_return = 0;
1809 config.max_rules = 1000000;
1810 config.number_tbl8s = NUMBER_TBL8S;
1813 rte_srand(rte_rdtsc());
1815 printf("No. routes = %u\n", (unsigned) NUM_ROUTE_ENTRIES);
1817 print_route_distribution(large_route_table, (uint32_t) NUM_ROUTE_ENTRIES);
1819 lpm = rte_lpm6_create(__func__, SOCKET_ID_ANY, &config);
1820 TEST_LPM_ASSERT(lpm != NULL);
1823 begin = rte_rdtsc();
1825 for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1826 if (rte_lpm6_add(lpm, large_route_table[i].ip,
1827 large_route_table[i].depth, next_hop_add) == 0)
1831 total_time = rte_rdtsc() - begin;
1833 printf("Unique added entries = %d\n", status);
1834 printf("Average LPM Add: %g cycles\n",
1835 (double)total_time / NUM_ROUTE_ENTRIES);
1837 /* Measure single Lookup */
1841 for (i = 0; i < ITERATIONS; i ++) {
1842 begin = rte_rdtsc();
1844 for (j = 0; j < NUM_IPS_ENTRIES; j ++) {
1845 if (rte_lpm6_lookup(lpm, large_ips_table[j].ip,
1846 &next_hop_return) != 0)
1850 total_time += rte_rdtsc() - begin;
1853 printf("Average LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1854 (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1855 (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1857 /* Measure bulk Lookup */
1861 uint8_t ip_batch[NUM_IPS_ENTRIES][16];
1862 int16_t next_hops[NUM_IPS_ENTRIES];
1864 for (i = 0; i < NUM_IPS_ENTRIES; i++)
1865 memcpy(ip_batch[i], large_ips_table[i].ip, 16);
1867 for (i = 0; i < ITERATIONS; i ++) {
1869 /* Lookup per batch */
1870 begin = rte_rdtsc();
1871 rte_lpm6_lookup_bulk_func(lpm, ip_batch, next_hops, NUM_IPS_ENTRIES);
1872 total_time += rte_rdtsc() - begin;
1874 for (j = 0; j < NUM_IPS_ENTRIES; j++)
1875 if (next_hops[j] < 0)
1878 printf("BULK LPM Lookup: %.1f cycles (fails = %.1f%%)\n",
1879 (double)total_time / ((double)ITERATIONS * BATCH_SIZE),
1880 (count * 100.0) / (double)(ITERATIONS * BATCH_SIZE));
1884 begin = rte_rdtsc();
1886 for (i = 0; i < NUM_ROUTE_ENTRIES; i++) {
1887 /* rte_lpm_delete(lpm, ip, depth) */
1888 status += rte_lpm6_delete(lpm, large_route_table[i].ip,
1889 large_route_table[i].depth);
1892 total_time += rte_rdtsc() - begin;
1894 printf("Average LPM Delete: %g cycles\n",
1895 (double)total_time / NUM_ROUTE_ENTRIES);
1897 rte_lpm6_delete_all(lpm);
1904 * Do all unit and performance tests.
1910 int status = -1, global_status = 0;
1912 for (i = 0; i < NUM_LPM6_TESTS; i++) {
1913 status = tests6[i]();
1916 printf("ERROR: LPM Test %s: FAIL\n", RTE_STR(tests6[i]));
1917 global_status = status;
1921 return global_status;
1924 #else /* RTE_LIBRTE_LPM */
1929 printf("The LPM library is not included in this build\n");
1933 #endif /* RTE_LIBRTE_LPM */