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.
42 #include "test_xmmt_ops.h"
44 #define TEST_LPM_ASSERT(cond) do { \
46 printf("Error at line %d: \n", __LINE__); \
51 typedef int32_t (*rte_lpm_test)(void);
53 static int32_t test0(void);
54 static int32_t test1(void);
55 static int32_t test2(void);
56 static int32_t test3(void);
57 static int32_t test4(void);
58 static int32_t test5(void);
59 static int32_t test6(void);
60 static int32_t test7(void);
61 static int32_t test8(void);
62 static int32_t test9(void);
63 static int32_t test10(void);
64 static int32_t test11(void);
65 static int32_t test12(void);
66 static int32_t test13(void);
67 static int32_t test14(void);
68 static int32_t test15(void);
69 static int32_t test16(void);
70 static int32_t test17(void);
71 static int32_t test18(void);
73 rte_lpm_test tests[] = {
96 #define NUM_LPM_TESTS (sizeof(tests)/sizeof(tests[0]))
99 #define NUMBER_TBL8S 256
103 * Check that rte_lpm_create fails gracefully for incorrect user input
109 struct rte_lpm *lpm = NULL;
110 struct rte_lpm_config config;
112 config.max_rules = MAX_RULES;
113 config.number_tbl8s = NUMBER_TBL8S;
116 /* rte_lpm_create: lpm name == NULL */
117 lpm = rte_lpm_create(NULL, SOCKET_ID_ANY, &config);
118 TEST_LPM_ASSERT(lpm == NULL);
120 /* rte_lpm_create: max_rules = 0 */
121 /* Note: __func__ inserts the function name, in this case "test0". */
122 config.max_rules = 0;
123 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
124 TEST_LPM_ASSERT(lpm == NULL);
126 /* socket_id < -1 is invalid */
127 config.max_rules = MAX_RULES;
128 lpm = rte_lpm_create(__func__, -2, &config);
129 TEST_LPM_ASSERT(lpm == NULL);
135 * Create lpm table then delete lpm table 100 times
136 * Use a slightly different rules size each time
141 struct rte_lpm *lpm = NULL;
142 struct rte_lpm_config config;
144 config.number_tbl8s = NUMBER_TBL8S;
148 /* rte_lpm_free: Free NULL */
149 for (i = 0; i < 100; i++) {
150 config.max_rules = MAX_RULES - i;
151 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
152 TEST_LPM_ASSERT(lpm != NULL);
157 /* Can not test free so return success */
162 * Call rte_lpm_free for NULL pointer user input. Note: free has no return and
163 * therefore it is impossible to check for failure but this test is added to
164 * increase function coverage metrics and to validate that freeing null does
170 struct rte_lpm *lpm = NULL;
171 struct rte_lpm_config config;
173 config.max_rules = MAX_RULES;
174 config.number_tbl8s = NUMBER_TBL8S;
177 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
178 TEST_LPM_ASSERT(lpm != NULL);
186 * Check that rte_lpm_add fails gracefully for incorrect user input arguments
191 struct rte_lpm *lpm = NULL;
192 struct rte_lpm_config config;
194 config.max_rules = MAX_RULES;
195 config.number_tbl8s = NUMBER_TBL8S;
197 uint32_t ip = IPv4(0, 0, 0, 0), next_hop = 100;
201 /* rte_lpm_add: lpm == NULL */
202 status = rte_lpm_add(NULL, ip, depth, next_hop);
203 TEST_LPM_ASSERT(status < 0);
205 /*Create vaild lpm to use in rest of test. */
206 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
207 TEST_LPM_ASSERT(lpm != NULL);
209 /* rte_lpm_add: depth < 1 */
210 status = rte_lpm_add(lpm, ip, 0, next_hop);
211 TEST_LPM_ASSERT(status < 0);
213 /* rte_lpm_add: depth > MAX_DEPTH */
214 status = rte_lpm_add(lpm, ip, (MAX_DEPTH + 1), next_hop);
215 TEST_LPM_ASSERT(status < 0);
223 * Check that rte_lpm_delete fails gracefully for incorrect user input
229 struct rte_lpm *lpm = NULL;
230 struct rte_lpm_config config;
232 config.max_rules = MAX_RULES;
233 config.number_tbl8s = NUMBER_TBL8S;
235 uint32_t ip = IPv4(0, 0, 0, 0);
239 /* rte_lpm_delete: lpm == NULL */
240 status = rte_lpm_delete(NULL, ip, depth);
241 TEST_LPM_ASSERT(status < 0);
243 /*Create vaild lpm to use in rest of test. */
244 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
245 TEST_LPM_ASSERT(lpm != NULL);
247 /* rte_lpm_delete: depth < 1 */
248 status = rte_lpm_delete(lpm, ip, 0);
249 TEST_LPM_ASSERT(status < 0);
251 /* rte_lpm_delete: depth > MAX_DEPTH */
252 status = rte_lpm_delete(lpm, ip, (MAX_DEPTH + 1));
253 TEST_LPM_ASSERT(status < 0);
261 * Check that rte_lpm_lookup fails gracefully for incorrect user input
267 #if defined(RTE_LIBRTE_LPM_DEBUG)
268 struct rte_lpm *lpm = NULL;
269 struct rte_lpm_config config;
271 config.max_rules = MAX_RULES;
272 config.number_tbl8s = NUMBER_TBL8S;
274 uint32_t ip = IPv4(0, 0, 0, 0), next_hop_return = 0;
277 /* rte_lpm_lookup: lpm == NULL */
278 status = rte_lpm_lookup(NULL, ip, &next_hop_return);
279 TEST_LPM_ASSERT(status < 0);
281 /*Create vaild lpm to use in rest of test. */
282 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
283 TEST_LPM_ASSERT(lpm != NULL);
285 /* rte_lpm_lookup: depth < 1 */
286 status = rte_lpm_lookup(lpm, ip, NULL);
287 TEST_LPM_ASSERT(status < 0);
297 * Call add, lookup and delete for a single rule with depth <= 24
302 struct rte_lpm *lpm = NULL;
303 struct rte_lpm_config config;
305 config.max_rules = MAX_RULES;
306 config.number_tbl8s = NUMBER_TBL8S;
308 uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0;
312 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
313 TEST_LPM_ASSERT(lpm != NULL);
315 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
316 TEST_LPM_ASSERT(status == 0);
318 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
319 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
321 status = rte_lpm_delete(lpm, ip, depth);
322 TEST_LPM_ASSERT(status == 0);
324 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
325 TEST_LPM_ASSERT(status == -ENOENT);
333 * Call add, lookup and delete for a single rule with depth > 24
341 struct rte_lpm *lpm = NULL;
342 struct rte_lpm_config config;
344 config.max_rules = MAX_RULES;
345 config.number_tbl8s = NUMBER_TBL8S;
347 uint32_t ip = IPv4(0, 0, 0, 0), next_hop_add = 100, next_hop_return = 0;
351 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
352 TEST_LPM_ASSERT(lpm != NULL);
354 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
355 TEST_LPM_ASSERT(status == 0);
357 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
358 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
360 ipx4 = vect_set_epi32(ip, ip + 0x100, ip - 0x100, ip);
361 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
362 TEST_LPM_ASSERT(hop[0] == next_hop_add);
363 TEST_LPM_ASSERT(hop[1] == UINT32_MAX);
364 TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
365 TEST_LPM_ASSERT(hop[3] == next_hop_add);
367 status = rte_lpm_delete(lpm, ip, depth);
368 TEST_LPM_ASSERT(status == 0);
370 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
371 TEST_LPM_ASSERT(status == -ENOENT);
379 * Use rte_lpm_add to add rules which effect only the second half of the lpm
380 * table. Use all possible depths ranging from 1..32. Set the next hop = to the
381 * depth. Check lookup hit for on every add and check for lookup miss on the
382 * first half of the lpm table after each add. Finally delete all rules going
383 * backwards (i.e. from depth = 32 ..1) and carry out a lookup after each
384 * delete. The lookup should return the next_hop_add value related to the
385 * previous depth value (i.e. depth -1).
392 struct rte_lpm *lpm = NULL;
393 struct rte_lpm_config config;
395 config.max_rules = MAX_RULES;
396 config.number_tbl8s = NUMBER_TBL8S;
398 uint32_t ip1 = IPv4(127, 255, 255, 255), ip2 = IPv4(128, 0, 0, 0);
399 uint32_t next_hop_add, next_hop_return;
403 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
404 TEST_LPM_ASSERT(lpm != NULL);
406 /* Loop with rte_lpm_add. */
407 for (depth = 1; depth <= 32; depth++) {
408 /* Let the next_hop_add value = depth. Just for change. */
409 next_hop_add = depth;
411 status = rte_lpm_add(lpm, ip2, depth, next_hop_add);
412 TEST_LPM_ASSERT(status == 0);
414 /* Check IP in first half of tbl24 which should be empty. */
415 status = rte_lpm_lookup(lpm, ip1, &next_hop_return);
416 TEST_LPM_ASSERT(status == -ENOENT);
418 status = rte_lpm_lookup(lpm, ip2, &next_hop_return);
419 TEST_LPM_ASSERT((status == 0) &&
420 (next_hop_return == next_hop_add));
422 ipx4 = vect_set_epi32(ip2, ip1, ip2, ip1);
423 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
424 TEST_LPM_ASSERT(hop[0] == UINT32_MAX);
425 TEST_LPM_ASSERT(hop[1] == next_hop_add);
426 TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
427 TEST_LPM_ASSERT(hop[3] == next_hop_add);
430 /* Loop with rte_lpm_delete. */
431 for (depth = 32; depth >= 1; depth--) {
432 next_hop_add = (uint8_t) (depth - 1);
434 status = rte_lpm_delete(lpm, ip2, depth);
435 TEST_LPM_ASSERT(status == 0);
437 status = rte_lpm_lookup(lpm, ip2, &next_hop_return);
440 TEST_LPM_ASSERT((status == 0) &&
441 (next_hop_return == next_hop_add));
443 TEST_LPM_ASSERT(status == -ENOENT);
446 status = rte_lpm_lookup(lpm, ip1, &next_hop_return);
447 TEST_LPM_ASSERT(status == -ENOENT);
449 ipx4 = vect_set_epi32(ip1, ip1, ip2, ip2);
450 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
452 TEST_LPM_ASSERT(hop[0] == next_hop_add);
453 TEST_LPM_ASSERT(hop[1] == next_hop_add);
455 TEST_LPM_ASSERT(hop[0] == UINT32_MAX);
456 TEST_LPM_ASSERT(hop[1] == UINT32_MAX);
458 TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
459 TEST_LPM_ASSERT(hop[3] == UINT32_MAX);
468 * - Add & lookup to hit invalid TBL24 entry
469 * - Add & lookup to hit valid TBL24 entry not extended
470 * - Add & lookup to hit valid extended TBL24 entry with invalid TBL8 entry
471 * - Add & lookup to hit valid extended TBL24 entry with valid TBL8 entry
477 struct rte_lpm *lpm = NULL;
478 struct rte_lpm_config config;
480 config.max_rules = MAX_RULES;
481 config.number_tbl8s = NUMBER_TBL8S;
483 uint32_t ip, ip_1, ip_2;
484 uint8_t depth, depth_1, depth_2;
485 uint32_t next_hop_add, next_hop_add_1, next_hop_add_2, next_hop_return;
488 /* Add & lookup to hit invalid TBL24 entry */
489 ip = IPv4(128, 0, 0, 0);
493 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
494 TEST_LPM_ASSERT(lpm != NULL);
496 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
497 TEST_LPM_ASSERT(status == 0);
499 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
500 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
502 status = rte_lpm_delete(lpm, ip, depth);
503 TEST_LPM_ASSERT(status == 0);
505 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
506 TEST_LPM_ASSERT(status == -ENOENT);
508 rte_lpm_delete_all(lpm);
510 /* Add & lookup to hit valid TBL24 entry not extended */
511 ip = IPv4(128, 0, 0, 0);
515 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
516 TEST_LPM_ASSERT(status == 0);
518 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
519 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
524 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
525 TEST_LPM_ASSERT(status == 0);
527 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
528 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
532 status = rte_lpm_delete(lpm, ip, depth);
533 TEST_LPM_ASSERT(status == 0);
537 status = rte_lpm_delete(lpm, ip, depth);
538 TEST_LPM_ASSERT(status == 0);
540 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
541 TEST_LPM_ASSERT(status == -ENOENT);
543 rte_lpm_delete_all(lpm);
545 /* Add & lookup to hit valid extended TBL24 entry with invalid TBL8
547 ip = IPv4(128, 0, 0, 0);
551 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
552 TEST_LPM_ASSERT(status == 0);
554 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
555 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
557 ip = IPv4(128, 0, 0, 5);
561 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
562 TEST_LPM_ASSERT(status == 0);
564 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
565 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
567 status = rte_lpm_delete(lpm, ip, depth);
568 TEST_LPM_ASSERT(status == 0);
570 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
571 TEST_LPM_ASSERT(status == -ENOENT);
573 ip = IPv4(128, 0, 0, 0);
577 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
578 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
580 status = rte_lpm_delete(lpm, ip, depth);
581 TEST_LPM_ASSERT(status == 0);
583 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
584 TEST_LPM_ASSERT(status == -ENOENT);
586 rte_lpm_delete_all(lpm);
588 /* Add & lookup to hit valid extended TBL24 entry with valid TBL8
590 ip_1 = IPv4(128, 0, 0, 0);
592 next_hop_add_1 = 101;
594 ip_2 = IPv4(128, 0, 0, 5);
596 next_hop_add_2 = 102;
600 status = rte_lpm_add(lpm, ip_1, depth_1, next_hop_add_1);
601 TEST_LPM_ASSERT(status == 0);
603 status = rte_lpm_lookup(lpm, ip_1, &next_hop_return);
604 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
606 status = rte_lpm_add(lpm, ip_2, depth_2, next_hop_add_2);
607 TEST_LPM_ASSERT(status == 0);
609 status = rte_lpm_lookup(lpm, ip_2, &next_hop_return);
610 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_2));
612 status = rte_lpm_delete(lpm, ip_2, depth_2);
613 TEST_LPM_ASSERT(status == 0);
615 status = rte_lpm_lookup(lpm, ip_2, &next_hop_return);
616 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
618 status = rte_lpm_delete(lpm, ip_1, depth_1);
619 TEST_LPM_ASSERT(status == 0);
621 status = rte_lpm_lookup(lpm, ip_1, &next_hop_return);
622 TEST_LPM_ASSERT(status == -ENOENT);
631 * - Add rule that covers a TBL24 range previously invalid & lookup (& delete &
633 * - Add rule that extends a TBL24 invalid entry & lookup (& delete & lookup)
634 * - Add rule that extends a TBL24 valid entry & lookup for both rules (&
636 * - Add rule that updates the next hop in TBL24 & lookup (& delete & lookup)
637 * - Add rule that updates the next hop in TBL8 & lookup (& delete & lookup)
638 * - Delete a rule that is not present in the TBL24 & lookup
639 * - Delete a rule that is not present in the TBL8 & lookup
646 struct rte_lpm *lpm = NULL;
647 struct rte_lpm_config config;
649 config.max_rules = MAX_RULES;
650 config.number_tbl8s = NUMBER_TBL8S;
652 uint32_t ip, next_hop_add, next_hop_return;
656 /* Add rule that covers a TBL24 range previously invalid & lookup
657 * (& delete & lookup) */
658 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
659 TEST_LPM_ASSERT(lpm != NULL);
661 ip = IPv4(128, 0, 0, 0);
665 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
666 TEST_LPM_ASSERT(status == 0);
668 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
669 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
671 status = rte_lpm_delete(lpm, ip, depth);
672 TEST_LPM_ASSERT(status == 0);
674 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
675 TEST_LPM_ASSERT(status == -ENOENT);
677 rte_lpm_delete_all(lpm);
679 ip = IPv4(128, 0, 0, 0);
683 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
684 TEST_LPM_ASSERT(status == 0);
686 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
687 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
689 status = rte_lpm_delete(lpm, ip, depth);
690 TEST_LPM_ASSERT(status == 0);
692 rte_lpm_delete_all(lpm);
694 /* Add rule that extends a TBL24 valid entry & lookup for both rules
695 * (& delete & lookup) */
697 ip = IPv4(128, 0, 0, 0);
701 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
702 TEST_LPM_ASSERT(status == 0);
704 ip = IPv4(128, 0, 0, 10);
708 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
709 TEST_LPM_ASSERT(status == 0);
711 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
712 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
714 ip = IPv4(128, 0, 0, 0);
717 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
718 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
720 ip = IPv4(128, 0, 0, 0);
723 status = rte_lpm_delete(lpm, ip, depth);
724 TEST_LPM_ASSERT(status == 0);
726 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
727 TEST_LPM_ASSERT(status == -ENOENT);
729 ip = IPv4(128, 0, 0, 10);
732 status = rte_lpm_delete(lpm, ip, depth);
733 TEST_LPM_ASSERT(status == 0);
735 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
736 TEST_LPM_ASSERT(status == -ENOENT);
738 rte_lpm_delete_all(lpm);
740 /* Add rule that updates the next hop in TBL24 & lookup
741 * (& delete & lookup) */
743 ip = IPv4(128, 0, 0, 0);
747 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
748 TEST_LPM_ASSERT(status == 0);
750 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
751 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
755 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
756 TEST_LPM_ASSERT(status == 0);
758 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
759 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
761 status = rte_lpm_delete(lpm, ip, depth);
762 TEST_LPM_ASSERT(status == 0);
764 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
765 TEST_LPM_ASSERT(status == -ENOENT);
767 rte_lpm_delete_all(lpm);
769 /* Add rule that updates the next hop in TBL8 & lookup
770 * (& delete & lookup) */
772 ip = IPv4(128, 0, 0, 0);
776 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
777 TEST_LPM_ASSERT(status == 0);
779 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
780 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
784 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
785 TEST_LPM_ASSERT(status == 0);
787 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
788 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
790 status = rte_lpm_delete(lpm, ip, depth);
791 TEST_LPM_ASSERT(status == 0);
793 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
794 TEST_LPM_ASSERT(status == -ENOENT);
796 rte_lpm_delete_all(lpm);
798 /* Delete a rule that is not present in the TBL24 & lookup */
800 ip = IPv4(128, 0, 0, 0);
803 status = rte_lpm_delete(lpm, ip, depth);
804 TEST_LPM_ASSERT(status < 0);
806 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
807 TEST_LPM_ASSERT(status == -ENOENT);
809 rte_lpm_delete_all(lpm);
811 /* Delete a rule that is not present in the TBL8 & lookup */
813 ip = IPv4(128, 0, 0, 0);
816 status = rte_lpm_delete(lpm, ip, depth);
817 TEST_LPM_ASSERT(status < 0);
819 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
820 TEST_LPM_ASSERT(status == -ENOENT);
828 * Add two rules, lookup to hit the more specific one, lookup to hit the less
829 * specific one delete the less specific rule and lookup previous values again;
830 * add a more specific rule than the existing rule, lookup again
837 struct rte_lpm *lpm = NULL;
838 struct rte_lpm_config config;
840 config.max_rules = MAX_RULES;
841 config.number_tbl8s = NUMBER_TBL8S;
843 uint32_t ip, next_hop_add, next_hop_return;
847 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
848 TEST_LPM_ASSERT(lpm != NULL);
850 ip = IPv4(128, 0, 0, 0);
854 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
855 TEST_LPM_ASSERT(status == 0);
857 ip = IPv4(128, 0, 0, 10);
861 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
862 TEST_LPM_ASSERT(status == 0);
864 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
865 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
867 ip = IPv4(128, 0, 0, 0);
870 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
871 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add));
873 ip = IPv4(128, 0, 0, 0);
876 status = rte_lpm_delete(lpm, ip, depth);
877 TEST_LPM_ASSERT(status == 0);
879 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
880 TEST_LPM_ASSERT(status == -ENOENT);
882 ip = IPv4(128, 0, 0, 10);
885 status = rte_lpm_delete(lpm, ip, depth);
886 TEST_LPM_ASSERT(status == 0);
888 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
889 TEST_LPM_ASSERT(status == -ENOENT);
897 * Add an extended rule (i.e. depth greater than 24, lookup (hit), delete,
898 * lookup (miss) in a for loop of 1000 times. This will check tbl8 extension
908 struct rte_lpm *lpm = NULL;
909 struct rte_lpm_config config;
911 config.max_rules = MAX_RULES;
912 config.number_tbl8s = NUMBER_TBL8S;
914 uint32_t ip, i, next_hop_add, next_hop_return;
918 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
919 TEST_LPM_ASSERT(lpm != NULL);
921 ip = IPv4(128, 0, 0, 0);
925 for (i = 0; i < 1000; i++) {
926 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
927 TEST_LPM_ASSERT(status == 0);
929 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
930 TEST_LPM_ASSERT((status == 0) &&
931 (next_hop_return == next_hop_add));
933 ipx4 = vect_set_epi32(ip, ip + 1, ip, ip - 1);
934 rte_lpm_lookupx4(lpm, ipx4, hop, UINT32_MAX);
935 TEST_LPM_ASSERT(hop[0] == UINT32_MAX);
936 TEST_LPM_ASSERT(hop[1] == next_hop_add);
937 TEST_LPM_ASSERT(hop[2] == UINT32_MAX);
938 TEST_LPM_ASSERT(hop[3] == next_hop_add);
940 status = rte_lpm_delete(lpm, ip, depth);
941 TEST_LPM_ASSERT(status == 0);
943 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
944 TEST_LPM_ASSERT(status == -ENOENT);
953 * Add a rule to tbl24, lookup (hit), then add a rule that will extend this
954 * tbl24 entry, lookup (hit). delete the rule that caused the tbl24 extension,
955 * lookup (miss) and repeat for loop of 1000 times. This will check tbl8
956 * extension and contraction.
963 struct rte_lpm *lpm = NULL;
964 struct rte_lpm_config config;
966 config.max_rules = MAX_RULES;
967 config.number_tbl8s = NUMBER_TBL8S;
969 uint32_t ip, i, next_hop_add_1, next_hop_add_2, next_hop_return;
973 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
974 TEST_LPM_ASSERT(lpm != NULL);
976 ip = IPv4(128, 0, 0, 0);
978 next_hop_add_1 = 100;
980 status = rte_lpm_add(lpm, ip, depth, next_hop_add_1);
981 TEST_LPM_ASSERT(status == 0);
983 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
984 TEST_LPM_ASSERT((status == 0) && (next_hop_return == next_hop_add_1));
987 next_hop_add_2 = 101;
989 for (i = 0; i < 1000; i++) {
990 status = rte_lpm_add(lpm, ip, depth, next_hop_add_2);
991 TEST_LPM_ASSERT(status == 0);
993 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
994 TEST_LPM_ASSERT((status == 0) &&
995 (next_hop_return == next_hop_add_2));
997 status = rte_lpm_delete(lpm, ip, depth);
998 TEST_LPM_ASSERT(status == 0);
1000 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
1001 TEST_LPM_ASSERT((status == 0) &&
1002 (next_hop_return == next_hop_add_1));
1007 status = rte_lpm_delete(lpm, ip, depth);
1008 TEST_LPM_ASSERT(status == 0);
1010 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
1011 TEST_LPM_ASSERT(status == -ENOENT);
1019 * Fore TBL8 extension exhaustion. Add 256 rules that require a tbl8 extension.
1020 * No more tbl8 extensions will be allowed. Now add one more rule that required
1021 * a tbl8 extension and get fail.
1027 /* We only use depth = 32 in the loop below so we must make sure
1028 * that we have enough storage for all rules at that depth*/
1030 struct rte_lpm *lpm = NULL;
1031 struct rte_lpm_config config;
1033 config.max_rules = 256 * 32;
1034 config.number_tbl8s = NUMBER_TBL8S;
1036 uint32_t ip, next_hop_add, next_hop_return;
1040 /* Add enough space for 256 rules for every depth */
1041 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1042 TEST_LPM_ASSERT(lpm != NULL);
1046 ip = IPv4(0, 0, 0, 0);
1048 /* Add 256 rules that require a tbl8 extension */
1049 for (; ip <= IPv4(0, 0, 255, 0); ip += 256) {
1050 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
1051 TEST_LPM_ASSERT(status == 0);
1053 status = rte_lpm_lookup(lpm, ip, &next_hop_return);
1054 TEST_LPM_ASSERT((status == 0) &&
1055 (next_hop_return == next_hop_add));
1058 /* All tbl8 extensions have been used above. Try to add one more and
1060 ip = IPv4(1, 0, 0, 0);
1063 status = rte_lpm_add(lpm, ip, depth, next_hop_add);
1064 TEST_LPM_ASSERT(status < 0);
1072 * Sequence of operations for find existing lpm table
1075 * - find existing table: hit
1076 * - find non-existing table: miss
1082 struct rte_lpm *lpm = NULL, *result = NULL;
1083 struct rte_lpm_config config;
1085 config.max_rules = 256 * 32;
1086 config.number_tbl8s = NUMBER_TBL8S;
1090 lpm = rte_lpm_create("lpm_find_existing", SOCKET_ID_ANY, &config);
1091 TEST_LPM_ASSERT(lpm != NULL);
1093 /* Try to find existing lpm */
1094 result = rte_lpm_find_existing("lpm_find_existing");
1095 TEST_LPM_ASSERT(result == lpm);
1097 /* Try to find non-existing lpm */
1098 result = rte_lpm_find_existing("lpm_find_non_existing");
1099 TEST_LPM_ASSERT(result == NULL);
1102 rte_lpm_delete_all(lpm);
1109 * test failure condition of overloading the tbl8 so no more will fit
1110 * Check we get an error return value in that case
1116 struct rte_lpm_config config;
1118 config.max_rules = 256 * 32;
1119 config.number_tbl8s = NUMBER_TBL8S;
1121 struct rte_lpm *lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1123 /* ip loops through all possibilities for top 24 bits of address */
1124 for (ip = 0; ip < 0xFFFFFF; ip++) {
1125 /* add an entry within a different tbl8 each time, since
1126 * depth >24 and the top 24 bits are different */
1127 if (rte_lpm_add(lpm, (ip << 8) + 0xF0, 30, 0) < 0)
1131 if (ip != NUMBER_TBL8S) {
1132 printf("Error, unexpected failure with filling tbl8 groups\n");
1133 printf("Failed after %u additions, expected after %u\n",
1134 (unsigned)ip, (unsigned)NUMBER_TBL8S);
1142 * Test for overwriting of tbl8:
1143 * - add rule /32 and lookup
1144 * - add new rule /24 and lookup
1145 * - add third rule /25 and lookup
1146 * - lookup /32 and /24 rule to ensure the table has not been overwritten.
1151 struct rte_lpm *lpm = NULL;
1152 struct rte_lpm_config config;
1154 config.max_rules = MAX_RULES;
1155 config.number_tbl8s = NUMBER_TBL8S;
1157 const uint32_t ip_10_32 = IPv4(10, 10, 10, 2);
1158 const uint32_t ip_10_24 = IPv4(10, 10, 10, 0);
1159 const uint32_t ip_20_25 = IPv4(10, 10, 20, 2);
1160 const uint8_t d_ip_10_32 = 32,
1163 const uint32_t next_hop_ip_10_32 = 100,
1164 next_hop_ip_10_24 = 105,
1165 next_hop_ip_20_25 = 111;
1166 uint32_t next_hop_return = 0;
1169 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1170 TEST_LPM_ASSERT(lpm != NULL);
1172 if ((status = rte_lpm_add(lpm, ip_10_32, d_ip_10_32,
1173 next_hop_ip_10_32)) < 0)
1176 status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return);
1177 uint32_t test_hop_10_32 = next_hop_return;
1178 TEST_LPM_ASSERT(status == 0);
1179 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1181 if ((status = rte_lpm_add(lpm, ip_10_24, d_ip_10_24,
1182 next_hop_ip_10_24)) < 0)
1185 status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return);
1186 uint32_t test_hop_10_24 = next_hop_return;
1187 TEST_LPM_ASSERT(status == 0);
1188 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1190 if ((status = rte_lpm_add(lpm, ip_20_25, d_ip_20_25,
1191 next_hop_ip_20_25)) < 0)
1194 status = rte_lpm_lookup(lpm, ip_20_25, &next_hop_return);
1195 uint32_t test_hop_20_25 = next_hop_return;
1196 TEST_LPM_ASSERT(status == 0);
1197 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_20_25);
1199 if (test_hop_10_32 == test_hop_10_24) {
1200 printf("Next hop return equal\n");
1204 if (test_hop_10_24 == test_hop_20_25) {
1205 printf("Next hop return equal\n");
1209 status = rte_lpm_lookup(lpm, ip_10_32, &next_hop_return);
1210 TEST_LPM_ASSERT(status == 0);
1211 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_32);
1213 status = rte_lpm_lookup(lpm, ip_10_24, &next_hop_return);
1214 TEST_LPM_ASSERT(status == 0);
1215 TEST_LPM_ASSERT(next_hop_return == next_hop_ip_10_24);
1223 * Test for recycle of tbl8
1224 * - step 1: add a rule with depth=28 (> 24)
1225 * - step 2: add a rule with same 24-bit prefix and depth=23 (< 24)
1226 * - step 3: delete the first rule
1227 * - step 4: check tbl8 is freed
1228 * - step 5: add a rule same as the first one (depth=28)
1229 * - step 6: check same tbl8 is allocated
1230 * - step 7: add a rule with same 24-bit prefix and depth=24
1231 * - step 8: delete the rule (depth=28) added in step 5
1232 * - step 9: check tbl8 is freed
1233 * - step 10: add a rule with same 24-bit prefix and depth = 28
1234 * - setp 11: check same tbl8 is allocated again
1239 #define group_idx next_hop
1240 struct rte_lpm *lpm = NULL;
1241 struct rte_lpm_config config;
1242 uint32_t ip, next_hop;
1244 uint32_t tbl8_group_index;
1246 config.max_rules = MAX_RULES;
1247 config.number_tbl8s = NUMBER_TBL8S;
1250 lpm = rte_lpm_create(__func__, SOCKET_ID_ANY, &config);
1251 TEST_LPM_ASSERT(lpm != NULL);
1253 ip = IPv4(192, 168, 100, 100);
1256 rte_lpm_add(lpm, ip, depth, next_hop);
1258 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1259 tbl8_group_index = lpm->tbl24[ip>>8].group_idx;
1263 rte_lpm_add(lpm, ip, depth, next_hop);
1264 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1267 rte_lpm_delete(lpm, ip, depth);
1269 TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group);
1272 rte_lpm_add(lpm, ip, depth, next_hop);
1274 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1275 TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx);
1279 rte_lpm_add(lpm, ip, depth, next_hop);
1280 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1283 rte_lpm_delete(lpm, ip, depth);
1285 TEST_LPM_ASSERT(!lpm->tbl24[ip>>8].valid_group);
1288 rte_lpm_add(lpm, ip, depth, next_hop);
1290 TEST_LPM_ASSERT(lpm->tbl24[ip>>8].valid_group);
1291 TEST_LPM_ASSERT(tbl8_group_index == lpm->tbl24[ip>>8].group_idx);
1299 * Do all unit tests.
1306 int status, global_status = 0;
1308 for (i = 0; i < NUM_LPM_TESTS; i++) {
1309 status = tests[i]();
1311 printf("ERROR: LPM Test %u: FAIL\n", i);
1312 global_status = status;
1316 return global_status;
1319 REGISTER_TEST_COMMAND(lpm_autotest, test_lpm);