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.
41 #include <rte_string_fns.h>
43 #include <rte_byteorder.h>
46 #include <rte_common.h>
50 #define LEN RTE_ACL_MAX_CATEGORIES
52 struct rte_acl_param acl_param = {
54 .socket_id = SOCKET_ID_ANY,
55 .rule_size = RTE_ACL_IPV4VLAN_RULE_SZ,
56 .max_rule_num = 0x30000,
59 struct rte_acl_ipv4vlan_rule acl_rule = {
60 .data = { .priority = 1, .category_mask = 0xff },
62 .src_port_high = UINT16_MAX,
64 .dst_port_high = UINT16_MAX,
67 /* byteswap to cpu or network order */
69 bswap_test_data(struct ipv4_7tuple *data, int len, int to_be)
73 for (i = 0; i < len; i++) {
76 /* swap all bytes so that they are in network order */
77 data[i].ip_dst = rte_cpu_to_be_32(data[i].ip_dst);
78 data[i].ip_src = rte_cpu_to_be_32(data[i].ip_src);
79 data[i].port_dst = rte_cpu_to_be_16(data[i].port_dst);
80 data[i].port_src = rte_cpu_to_be_16(data[i].port_src);
81 data[i].vlan = rte_cpu_to_be_16(data[i].vlan);
82 data[i].domain = rte_cpu_to_be_16(data[i].domain);
84 data[i].ip_dst = rte_be_to_cpu_32(data[i].ip_dst);
85 data[i].ip_src = rte_be_to_cpu_32(data[i].ip_src);
86 data[i].port_dst = rte_be_to_cpu_16(data[i].port_dst);
87 data[i].port_src = rte_be_to_cpu_16(data[i].port_src);
88 data[i].vlan = rte_be_to_cpu_16(data[i].vlan);
89 data[i].domain = rte_be_to_cpu_16(data[i].domain);
95 * Test scalar and SSE ACL lookup.
98 test_classify_run(struct rte_acl_ctx *acx)
101 uint32_t result, count;
102 uint32_t results[RTE_DIM(acl_test_data) * RTE_ACL_MAX_CATEGORIES];
103 const uint8_t *data[RTE_DIM(acl_test_data)];
105 /* swap all bytes in the data to network order */
106 bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 1);
108 /* store pointers to test data */
109 for (i = 0; i < (int) RTE_DIM(acl_test_data); i++)
110 data[i] = (uint8_t *)&acl_test_data[i];
113 * these will run quite a few times, it's necessary to test code paths
114 * from num=0 to num>8
116 for (count = 0; count < RTE_DIM(acl_test_data); count++) {
117 ret = rte_acl_classify(acx, data, results,
118 count, RTE_ACL_MAX_CATEGORIES);
120 printf("Line %i: SSE classify failed!\n", __LINE__);
124 /* check if we allow everything we should allow */
125 for (i = 0; i < (int) count; i++) {
127 results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW];
128 if (result != acl_test_data[i].allow) {
129 printf("Line %i: Error in allow results at %i "
130 "(expected %"PRIu32" got %"PRIu32")!\n",
131 __LINE__, i, acl_test_data[i].allow,
137 /* check if we deny everything we should deny */
138 for (i = 0; i < (int) count; i++) {
139 result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY];
140 if (result != acl_test_data[i].deny) {
141 printf("Line %i: Error in deny results at %i "
142 "(expected %"PRIu32" got %"PRIu32")!\n",
143 __LINE__, i, acl_test_data[i].deny,
150 /* make a quick check for scalar */
151 ret = rte_acl_classify_scalar(acx, data, results,
152 RTE_DIM(acl_test_data), RTE_ACL_MAX_CATEGORIES);
154 printf("Line %i: SSE classify failed!\n", __LINE__);
158 /* check if we allow everything we should allow */
159 for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) {
160 result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW];
161 if (result != acl_test_data[i].allow) {
162 printf("Line %i: Error in allow results at %i "
163 "(expected %"PRIu32" got %"PRIu32")!\n",
164 __LINE__, i, acl_test_data[i].allow,
170 /* check if we deny everything we should deny */
171 for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) {
172 result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY];
173 if (result != acl_test_data[i].deny) {
174 printf("Line %i: Error in deny results at %i "
175 "(expected %"PRIu32" got %"PRIu32")!\n",
176 __LINE__, i, acl_test_data[i].deny,
185 /* swap data back to cpu order so that next time tests don't fail */
186 bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 0);
191 test_classify_buid(struct rte_acl_ctx *acx)
194 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {
195 offsetof(struct ipv4_7tuple, proto),
196 offsetof(struct ipv4_7tuple, vlan),
197 offsetof(struct ipv4_7tuple, ip_src),
198 offsetof(struct ipv4_7tuple, ip_dst),
199 offsetof(struct ipv4_7tuple, port_src),
202 /* add rules to the context */
203 ret = rte_acl_ipv4vlan_add_rules(acx, acl_test_rules,
204 RTE_DIM(acl_test_rules));
206 printf("Line %i: Adding rules to ACL context failed!\n",
211 /* try building the context */
212 ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
214 printf("Line %i: Building ACL context failed!\n", __LINE__);
221 #define TEST_CLASSIFY_ITER 4
224 * Test scalar and SSE ACL lookup.
229 struct rte_acl_ctx *acx;
232 acx = rte_acl_create(&acl_param);
234 printf("Line %i: Error creating ACL context!\n", __LINE__);
239 for (i = 0; i != TEST_CLASSIFY_ITER; i++) {
244 rte_acl_reset_rules(acx);
246 ret = test_classify_buid(acx);
248 printf("Line %i, iter: %d: "
249 "Adding rules to ACL context failed!\n",
254 ret = test_classify_run(acx);
256 printf("Line %i, iter: %d: %s failed!\n",
257 __LINE__, i, __func__);
261 /* reset rules and make sure that classify still works ok. */
262 rte_acl_reset_rules(acx);
263 ret = test_classify_run(acx);
265 printf("Line %i, iter: %d: %s failed!\n",
266 __LINE__, i, __func__);
276 * Test wrong layout behavior
277 * This test supplies the ACL context with invalid layout, which results in
278 * ACL matching the wrong stuff. However, it should match the wrong stuff
279 * the right way. We switch around source and destination addresses,
280 * source and destination ports, and protocol will point to first byte of
284 test_invalid_layout(void)
286 struct rte_acl_ctx *acx;
289 uint32_t results[RTE_DIM(invalid_layout_data)];
290 const uint8_t *data[RTE_DIM(invalid_layout_data)];
292 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {
293 /* proto points to destination port's first byte */
294 offsetof(struct ipv4_7tuple, port_dst),
296 0, /* VLAN not used */
298 /* src and dst addresses are swapped */
299 offsetof(struct ipv4_7tuple, ip_dst),
300 offsetof(struct ipv4_7tuple, ip_src),
303 * we can't swap ports here, so we will swap
306 offsetof(struct ipv4_7tuple, port_src),
309 acx = rte_acl_create(&acl_param);
311 printf("Line %i: Error creating ACL context!\n", __LINE__);
315 /* putting a lot of rules into the context results in greater
316 * coverage numbers. it doesn't matter if they are identical */
317 for (i = 0; i < 1000; i++) {
318 /* add rules to the context */
319 ret = rte_acl_ipv4vlan_add_rules(acx, invalid_layout_rules,
320 RTE_DIM(invalid_layout_rules));
322 printf("Line %i: Adding rules to ACL context failed!\n",
329 /* try building the context */
330 ret = rte_acl_ipv4vlan_build(acx, layout, 1);
332 printf("Line %i: Building ACL context failed!\n", __LINE__);
337 /* swap all bytes in the data to network order */
338 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 1);
341 for (i = 0; i < (int) RTE_DIM(invalid_layout_data); i++) {
342 data[i] = (uint8_t *)&invalid_layout_data[i];
345 /* classify tuples */
346 ret = rte_acl_classify(acx, data, results,
347 RTE_DIM(results), 1);
349 printf("Line %i: SSE classify failed!\n", __LINE__);
354 for (i = 0; i < (int) RTE_DIM(results); i++) {
355 if (results[i] != invalid_layout_data[i].allow) {
356 printf("Line %i: Wrong results at %i "
357 "(result=%u, should be %u)!\n",
358 __LINE__, i, results[i],
359 invalid_layout_data[i].allow);
364 /* classify tuples (scalar) */
365 ret = rte_acl_classify_scalar(acx, data, results,
366 RTE_DIM(results), 1);
368 printf("Line %i: Scalar classify failed!\n", __LINE__);
373 for (i = 0; i < (int) RTE_DIM(results); i++) {
374 if (results[i] != invalid_layout_data[i].allow) {
375 printf("Line %i: Wrong results at %i "
376 "(result=%u, should be %u)!\n",
377 __LINE__, i, results[i],
378 invalid_layout_data[i].allow);
385 /* swap data back to cpu order so that next time tests don't fail */
386 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
391 /* swap data back to cpu order so that next time tests don't fail */
392 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
400 * Test creating and finding ACL contexts, and adding rules
403 test_create_find_add(void)
405 struct rte_acl_param param;
406 struct rte_acl_ctx *acx, *acx2, *tmp;
407 struct rte_acl_ipv4vlan_rule rules[LEN];
409 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
411 const char *acx_name = "acx";
412 const char *acx2_name = "acx2";
415 /* create two contexts */
416 memcpy(¶m, &acl_param, sizeof(param));
417 param.max_rule_num = 2;
419 param.name = acx_name;
420 acx = rte_acl_create(¶m);
422 printf("Line %i: Error creating %s!\n", __LINE__, acx_name);
426 param.name = acx2_name;
427 acx2 = rte_acl_create(¶m);
428 if (acx2 == NULL || acx2 == acx) {
429 printf("Line %i: Error creating %s!\n", __LINE__, acx2_name);
434 /* try to create third one, with an existing name */
435 param.name = acx_name;
436 tmp = rte_acl_create(¶m);
438 printf("Line %i: Creating context with existing name "
446 param.name = acx2_name;
447 tmp = rte_acl_create(¶m);
449 printf("Line %i: Creating context with existing "
450 "name test 2 failed!\n",
457 /* try to find existing ACL contexts */
458 tmp = rte_acl_find_existing(acx_name);
460 printf("Line %i: Finding %s failed!\n", __LINE__, acx_name);
466 tmp = rte_acl_find_existing(acx2_name);
468 printf("Line %i: Finding %s failed!\n", __LINE__, acx2_name);
474 /* try to find non-existing context */
475 tmp = rte_acl_find_existing("invalid");
477 printf("Line %i: Non-existent ACL context found!\n", __LINE__);
485 /* create valid (but severely limited) acx */
486 memcpy(¶m, &acl_param, sizeof(param));
487 param.max_rule_num = LEN;
489 acx = rte_acl_create(¶m);
491 printf("Line %i: Error creating %s!\n", __LINE__, param.name);
495 /* create dummy acl */
496 for (i = 0; i < LEN; i++) {
497 memcpy(&rules[i], &acl_rule,
498 sizeof(struct rte_acl_ipv4vlan_rule));
500 rules[i].data.userdata = i + 1;
501 /* one rule per category */
502 rules[i].data.category_mask = 1 << i;
505 /* try filling up the context */
506 ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN);
508 printf("Line %i: Adding %i rules to ACL context failed!\n",
513 /* try adding to a (supposedly) full context */
514 ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1);
516 printf("Line %i: Adding rules to full ACL context should"
517 "have failed!\n", __LINE__);
521 /* try building the context */
522 ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
524 printf("Line %i: Building ACL context failed!\n", __LINE__);
539 * test various invalid rules
542 test_invalid_rules(void)
544 struct rte_acl_ctx *acx;
547 struct rte_acl_ipv4vlan_rule rule;
549 acx = rte_acl_create(&acl_param);
551 printf("Line %i: Error creating ACL context!\n", __LINE__);
555 /* test inverted high/low source and destination ports.
556 * originally, there was a problem with memory consumption when using
559 /* create dummy acl */
560 memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule));
561 rule.data.userdata = 1;
562 rule.dst_port_low = 0xfff0;
563 rule.dst_port_high = 0x0010;
565 /* add rules to context and try to build it */
566 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
568 printf("Line %i: Adding rules to ACL context "
569 "should have failed!\n", __LINE__);
573 rule.dst_port_low = 0x0;
574 rule.dst_port_high = 0xffff;
575 rule.src_port_low = 0xfff0;
576 rule.src_port_high = 0x0010;
578 /* add rules to context and try to build it */
579 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
581 printf("Line %i: Adding rules to ACL context "
582 "should have failed!\n", __LINE__);
586 rule.dst_port_low = 0x0;
587 rule.dst_port_high = 0xffff;
588 rule.src_port_low = 0x0;
589 rule.src_port_high = 0xffff;
591 rule.dst_mask_len = 33;
593 /* add rules to context and try to build it */
594 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
596 printf("Line %i: Adding rules to ACL context "
597 "should have failed!\n", __LINE__);
601 rule.dst_mask_len = 0;
602 rule.src_mask_len = 33;
604 /* add rules to context and try to build it */
605 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
607 printf("Line %i: Adding rules to ACL context "
608 "should have failed!\n", __LINE__);
612 rule.dst_mask_len = 0;
613 rule.src_mask_len = 0;
614 rule.data.userdata = 0;
616 /* try adding this rule (it should fail because userdata is invalid) */
617 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
619 printf("Line %i: Adding a rule with invalid user data "
620 "should have failed!\n", __LINE__);
636 * test functions by passing invalid or
637 * non-workable parameters.
639 * we do very limited testing of classify functions here
640 * because those are performance-critical and
641 * thus don't do much parameter checking.
644 test_invalid_parameters(void)
646 struct rte_acl_param param;
647 struct rte_acl_ctx *acx;
648 struct rte_acl_ipv4vlan_rule rule;
651 uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
659 acx = rte_acl_create(NULL);
661 printf("Line %i: ACL context creation with NULL param "
662 "should have failed!\n", __LINE__);
668 memcpy(¶m, &acl_param, sizeof(param));
671 acx = rte_acl_create(¶m);
673 printf("Line %i: ACL context creation with zero rule len "
674 "failed!\n", __LINE__);
679 /* zero max rule num */
680 memcpy(¶m, &acl_param, sizeof(param));
681 param.max_rule_num = 0;
683 acx = rte_acl_create(¶m);
685 printf("Line %i: ACL context creation with zero rule num "
686 "failed!\n", __LINE__);
691 /* invalid NUMA node */
692 memcpy(¶m, &acl_param, sizeof(param));
693 param.socket_id = RTE_MAX_NUMA_NODES + 1;
695 acx = rte_acl_create(¶m);
697 printf("Line %i: ACL context creation with invalid NUMA "
698 "should have failed!\n", __LINE__);
704 memcpy(¶m, &acl_param, sizeof(param));
707 acx = rte_acl_create(¶m);
709 printf("Line %i: ACL context creation with NULL name "
710 "should have failed!\n", __LINE__);
716 * rte_acl_find_existing
719 acx = rte_acl_find_existing(NULL);
721 printf("Line %i: NULL ACL context found!\n", __LINE__);
727 * rte_acl_ipv4vlan_add_rules
730 /* initialize everything */
731 memcpy(¶m, &acl_param, sizeof(param));
732 acx = rte_acl_create(¶m);
734 printf("Line %i: ACL context creation failed!\n", __LINE__);
738 memcpy(&rule, &acl_rule, sizeof(rule));
741 result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1);
743 printf("Line %i: Adding rules with NULL ACL context "
744 "should have failed!\n", __LINE__);
750 result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1);
752 printf("Line %i: Adding NULL rule to ACL context "
753 "should have failed!\n", __LINE__);
758 /* zero count (should succeed) */
759 result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0);
761 printf("Line %i: Adding 0 rules to ACL context failed!\n",
767 /* free ACL context */
770 /* set wrong rule_size so that adding any rules would fail */
771 param.rule_size = RTE_ACL_IPV4VLAN_RULE_SZ + 4;
772 acx = rte_acl_create(¶m);
774 printf("Line %i: ACL context creation failed!\n", __LINE__);
778 /* try adding a rule with size different from context rule_size */
779 result = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
781 printf("Line %i: Adding an invalid sized rule "
782 "should have failed!\n", __LINE__);
787 /* free ACL context */
792 * rte_acl_ipv4vlan_build
795 /* reinitialize context */
796 memcpy(¶m, &acl_param, sizeof(param));
797 acx = rte_acl_create(¶m);
799 printf("Line %i: ACL context creation failed!\n", __LINE__);
804 result = rte_acl_ipv4vlan_build(NULL, layout, 1);
806 printf("Line %i: Building with NULL context "
807 "should have failed!\n", __LINE__);
813 result = rte_acl_ipv4vlan_build(acx, NULL, 1);
815 printf("Line %i: Building with NULL layout "
816 "should have failed!\n", __LINE__);
821 /* zero categories (should not fail) */
822 result = rte_acl_ipv4vlan_build(acx, layout, 0);
824 printf("Line %i: Building with 0 categories should fail!\n",
830 /* SSE classify test */
832 /* cover zero categories in classify (should not fail) */
833 result = rte_acl_classify(acx, NULL, NULL, 0, 0);
835 printf("Line %i: SSE classify with zero categories "
836 "failed!\n", __LINE__);
841 /* cover invalid but positive categories in classify */
842 result = rte_acl_classify(acx, NULL, NULL, 0, 3);
844 printf("Line %i: SSE classify with 3 categories "
845 "should have failed!\n", __LINE__);
850 /* scalar classify test */
852 /* cover zero categories in classify (should not fail) */
853 result = rte_acl_classify_scalar(acx, NULL, NULL, 0, 0);
855 printf("Line %i: Scalar classify with zero categories "
856 "failed!\n", __LINE__);
861 /* cover invalid but positive categories in classify */
862 result = rte_acl_classify_scalar(acx, NULL, NULL, 0, 3);
864 printf("Line %i: Scalar classify with 3 categories "
865 "should have failed!\n", __LINE__);
870 /* free ACL context */
875 * make sure void functions don't crash with NULL parameters
886 * Various tests that don't test much but improve coverage
891 struct rte_acl_param param;
892 struct rte_acl_ctx *acx;
895 memcpy(¶m, &acl_param, sizeof(param));
897 acx = rte_acl_create(¶m);
899 printf("Line %i: Error creating ACL context!\n", __LINE__);
903 /* dump context with rules - useful for coverage */
916 if (test_invalid_parameters() < 0)
918 if (test_invalid_rules() < 0)
920 if (test_create_find_add() < 0)
922 if (test_invalid_layout() < 0)
926 if (test_classify() < 0)
936 printf("This binary was not compiled with ACL support!\n");
940 #endif /* RTE_LIBRTE_ACL */