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.
39 #include <rte_string_fns.h>
41 #include <rte_byteorder.h>
44 #include <rte_common.h>
48 #define LEN RTE_ACL_MAX_CATEGORIES
50 struct rte_acl_param acl_param = {
52 .socket_id = SOCKET_ID_ANY,
53 .rule_size = RTE_ACL_IPV4VLAN_RULE_SZ,
54 .max_rule_num = 0x30000,
57 struct rte_acl_ipv4vlan_rule acl_rule = {
58 .data = { .priority = 1, .category_mask = 0xff },
60 .src_port_high = UINT16_MAX,
62 .dst_port_high = UINT16_MAX,
65 /* byteswap to cpu or network order */
67 bswap_test_data(struct ipv4_7tuple *data, int len, int to_be)
71 for (i = 0; i < len; i++) {
74 /* swap all bytes so that they are in network order */
75 data[i].ip_dst = rte_cpu_to_be_32(data[i].ip_dst);
76 data[i].ip_src = rte_cpu_to_be_32(data[i].ip_src);
77 data[i].port_dst = rte_cpu_to_be_16(data[i].port_dst);
78 data[i].port_src = rte_cpu_to_be_16(data[i].port_src);
79 data[i].vlan = rte_cpu_to_be_16(data[i].vlan);
80 data[i].domain = rte_cpu_to_be_16(data[i].domain);
82 data[i].ip_dst = rte_be_to_cpu_32(data[i].ip_dst);
83 data[i].ip_src = rte_be_to_cpu_32(data[i].ip_src);
84 data[i].port_dst = rte_be_to_cpu_16(data[i].port_dst);
85 data[i].port_src = rte_be_to_cpu_16(data[i].port_src);
86 data[i].vlan = rte_be_to_cpu_16(data[i].vlan);
87 data[i].domain = rte_be_to_cpu_16(data[i].domain);
93 * Test scalar and SSE ACL lookup.
96 test_classify_run(struct rte_acl_ctx *acx)
99 uint32_t result, count;
100 uint32_t results[RTE_DIM(acl_test_data) * RTE_ACL_MAX_CATEGORIES];
101 const uint8_t *data[RTE_DIM(acl_test_data)];
103 /* swap all bytes in the data to network order */
104 bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 1);
106 /* store pointers to test data */
107 for (i = 0; i < (int) RTE_DIM(acl_test_data); i++)
108 data[i] = (uint8_t *)&acl_test_data[i];
111 * these will run quite a few times, it's necessary to test code paths
112 * from num=0 to num>8
114 for (count = 0; count < RTE_DIM(acl_test_data); count++) {
115 ret = rte_acl_classify(acx, data, results,
116 count, RTE_ACL_MAX_CATEGORIES);
118 printf("Line %i: SSE classify failed!\n", __LINE__);
122 /* check if we allow everything we should allow */
123 for (i = 0; i < (int) count; i++) {
125 results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW];
126 if (result != acl_test_data[i].allow) {
127 printf("Line %i: Error in allow results at %i "
128 "(expected %"PRIu32" got %"PRIu32")!\n",
129 __LINE__, i, acl_test_data[i].allow,
135 /* check if we deny everything we should deny */
136 for (i = 0; i < (int) count; i++) {
137 result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY];
138 if (result != acl_test_data[i].deny) {
139 printf("Line %i: Error in deny results at %i "
140 "(expected %"PRIu32" got %"PRIu32")!\n",
141 __LINE__, i, acl_test_data[i].deny,
148 /* make a quick check for scalar */
149 ret = rte_acl_classify_scalar(acx, data, results,
150 RTE_DIM(acl_test_data), RTE_ACL_MAX_CATEGORIES);
152 printf("Line %i: SSE classify failed!\n", __LINE__);
156 /* check if we allow everything we should allow */
157 for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) {
158 result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW];
159 if (result != acl_test_data[i].allow) {
160 printf("Line %i: Error in allow results at %i "
161 "(expected %"PRIu32" got %"PRIu32")!\n",
162 __LINE__, i, acl_test_data[i].allow,
168 /* check if we deny everything we should deny */
169 for (i = 0; i < (int) RTE_DIM(acl_test_data); i++) {
170 result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY];
171 if (result != acl_test_data[i].deny) {
172 printf("Line %i: Error in deny results at %i "
173 "(expected %"PRIu32" got %"PRIu32")!\n",
174 __LINE__, i, acl_test_data[i].deny,
183 /* swap data back to cpu order so that next time tests don't fail */
184 bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 0);
189 test_classify_buid(struct rte_acl_ctx *acx)
192 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {
193 offsetof(struct ipv4_7tuple, proto),
194 offsetof(struct ipv4_7tuple, vlan),
195 offsetof(struct ipv4_7tuple, ip_src),
196 offsetof(struct ipv4_7tuple, ip_dst),
197 offsetof(struct ipv4_7tuple, port_src),
200 /* add rules to the context */
201 ret = rte_acl_ipv4vlan_add_rules(acx, acl_test_rules,
202 RTE_DIM(acl_test_rules));
204 printf("Line %i: Adding rules to ACL context failed!\n",
209 /* try building the context */
210 ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
212 printf("Line %i: Building ACL context failed!\n", __LINE__);
219 #define TEST_CLASSIFY_ITER 4
222 * Test scalar and SSE ACL lookup.
227 struct rte_acl_ctx *acx;
230 acx = rte_acl_create(&acl_param);
232 printf("Line %i: Error creating ACL context!\n", __LINE__);
237 for (i = 0; i != TEST_CLASSIFY_ITER; i++) {
242 rte_acl_reset_rules(acx);
244 ret = test_classify_buid(acx);
246 printf("Line %i, iter: %d: "
247 "Adding rules to ACL context failed!\n",
252 ret = test_classify_run(acx);
254 printf("Line %i, iter: %d: %s failed!\n",
255 __LINE__, i, __func__);
259 /* reset rules and make sure that classify still works ok. */
260 rte_acl_reset_rules(acx);
261 ret = test_classify_run(acx);
263 printf("Line %i, iter: %d: %s failed!\n",
264 __LINE__, i, __func__);
274 * Test wrong layout behavior
275 * This test supplies the ACL context with invalid layout, which results in
276 * ACL matching the wrong stuff. However, it should match the wrong stuff
277 * the right way. We switch around source and destination addresses,
278 * source and destination ports, and protocol will point to first byte of
282 test_invalid_layout(void)
284 struct rte_acl_ctx *acx;
287 uint32_t results[RTE_DIM(invalid_layout_data)];
288 const uint8_t *data[RTE_DIM(invalid_layout_data)];
290 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {
291 /* proto points to destination port's first byte */
292 offsetof(struct ipv4_7tuple, port_dst),
294 0, /* VLAN not used */
296 /* src and dst addresses are swapped */
297 offsetof(struct ipv4_7tuple, ip_dst),
298 offsetof(struct ipv4_7tuple, ip_src),
301 * we can't swap ports here, so we will swap
304 offsetof(struct ipv4_7tuple, port_src),
307 acx = rte_acl_create(&acl_param);
309 printf("Line %i: Error creating ACL context!\n", __LINE__);
313 /* putting a lot of rules into the context results in greater
314 * coverage numbers. it doesn't matter if they are identical */
315 for (i = 0; i < 1000; i++) {
316 /* add rules to the context */
317 ret = rte_acl_ipv4vlan_add_rules(acx, invalid_layout_rules,
318 RTE_DIM(invalid_layout_rules));
320 printf("Line %i: Adding rules to ACL context failed!\n",
327 /* try building the context */
328 ret = rte_acl_ipv4vlan_build(acx, layout, 1);
330 printf("Line %i: Building ACL context failed!\n", __LINE__);
335 /* swap all bytes in the data to network order */
336 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 1);
339 for (i = 0; i < (int) RTE_DIM(invalid_layout_data); i++) {
340 data[i] = (uint8_t *)&invalid_layout_data[i];
343 /* classify tuples */
344 ret = rte_acl_classify(acx, data, results,
345 RTE_DIM(results), 1);
347 printf("Line %i: SSE classify failed!\n", __LINE__);
352 for (i = 0; i < (int) RTE_DIM(results); i++) {
353 if (results[i] != invalid_layout_data[i].allow) {
354 printf("Line %i: Wrong results at %i "
355 "(result=%u, should be %u)!\n",
356 __LINE__, i, results[i],
357 invalid_layout_data[i].allow);
362 /* classify tuples (scalar) */
363 ret = rte_acl_classify_scalar(acx, data, results,
364 RTE_DIM(results), 1);
366 printf("Line %i: Scalar classify failed!\n", __LINE__);
371 for (i = 0; i < (int) RTE_DIM(results); i++) {
372 if (results[i] != invalid_layout_data[i].allow) {
373 printf("Line %i: Wrong results at %i "
374 "(result=%u, should be %u)!\n",
375 __LINE__, i, results[i],
376 invalid_layout_data[i].allow);
383 /* swap data back to cpu order so that next time tests don't fail */
384 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
389 /* swap data back to cpu order so that next time tests don't fail */
390 bswap_test_data(invalid_layout_data, RTE_DIM(invalid_layout_data), 0);
398 * Test creating and finding ACL contexts, and adding rules
401 test_create_find_add(void)
403 struct rte_acl_param param;
404 struct rte_acl_ctx *acx, *acx2, *tmp;
405 struct rte_acl_ipv4vlan_rule rules[LEN];
407 const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
409 const char *acx_name = "acx";
410 const char *acx2_name = "acx2";
413 /* create two contexts */
414 memcpy(¶m, &acl_param, sizeof(param));
415 param.max_rule_num = 2;
417 param.name = acx_name;
418 acx = rte_acl_create(¶m);
420 printf("Line %i: Error creating %s!\n", __LINE__, acx_name);
424 param.name = acx2_name;
425 acx2 = rte_acl_create(¶m);
426 if (acx2 == NULL || acx2 == acx) {
427 printf("Line %i: Error creating %s!\n", __LINE__, acx2_name);
432 /* try to create third one, with an existing name */
433 param.name = acx_name;
434 tmp = rte_acl_create(¶m);
436 printf("Line %i: Creating context with existing name "
444 param.name = acx2_name;
445 tmp = rte_acl_create(¶m);
447 printf("Line %i: Creating context with existing "
448 "name test 2 failed!\n",
455 /* try to find existing ACL contexts */
456 tmp = rte_acl_find_existing(acx_name);
458 printf("Line %i: Finding %s failed!\n", __LINE__, acx_name);
464 tmp = rte_acl_find_existing(acx2_name);
466 printf("Line %i: Finding %s failed!\n", __LINE__, acx2_name);
472 /* try to find non-existing context */
473 tmp = rte_acl_find_existing("invalid");
475 printf("Line %i: Non-existent ACL context found!\n", __LINE__);
483 /* create valid (but severely limited) acx */
484 memcpy(¶m, &acl_param, sizeof(param));
485 param.max_rule_num = LEN;
487 acx = rte_acl_create(¶m);
489 printf("Line %i: Error creating %s!\n", __LINE__, param.name);
493 /* create dummy acl */
494 for (i = 0; i < LEN; i++) {
495 memcpy(&rules[i], &acl_rule,
496 sizeof(struct rte_acl_ipv4vlan_rule));
498 rules[i].data.userdata = i + 1;
499 /* one rule per category */
500 rules[i].data.category_mask = 1 << i;
503 /* try filling up the context */
504 ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN);
506 printf("Line %i: Adding %i rules to ACL context failed!\n",
511 /* try adding to a (supposedly) full context */
512 ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1);
514 printf("Line %i: Adding rules to full ACL context should"
515 "have failed!\n", __LINE__);
519 /* try building the context */
520 ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
522 printf("Line %i: Building ACL context failed!\n", __LINE__);
537 * test various invalid rules
540 test_invalid_rules(void)
542 struct rte_acl_ctx *acx;
545 struct rte_acl_ipv4vlan_rule rule;
547 acx = rte_acl_create(&acl_param);
549 printf("Line %i: Error creating ACL context!\n", __LINE__);
553 /* test inverted high/low source and destination ports.
554 * originally, there was a problem with memory consumption when using
557 /* create dummy acl */
558 memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule));
559 rule.data.userdata = 1;
560 rule.dst_port_low = 0xfff0;
561 rule.dst_port_high = 0x0010;
563 /* add rules to context and try to build it */
564 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
566 printf("Line %i: Adding rules to ACL context "
567 "should have failed!\n", __LINE__);
571 rule.dst_port_low = 0x0;
572 rule.dst_port_high = 0xffff;
573 rule.src_port_low = 0xfff0;
574 rule.src_port_high = 0x0010;
576 /* add rules to context and try to build it */
577 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
579 printf("Line %i: Adding rules to ACL context "
580 "should have failed!\n", __LINE__);
584 rule.dst_port_low = 0x0;
585 rule.dst_port_high = 0xffff;
586 rule.src_port_low = 0x0;
587 rule.src_port_high = 0xffff;
589 rule.dst_mask_len = 33;
591 /* add rules to context and try to build it */
592 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
594 printf("Line %i: Adding rules to ACL context "
595 "should have failed!\n", __LINE__);
599 rule.dst_mask_len = 0;
600 rule.src_mask_len = 33;
602 /* add rules to context and try to build it */
603 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
605 printf("Line %i: Adding rules to ACL context "
606 "should have failed!\n", __LINE__);
610 rule.dst_mask_len = 0;
611 rule.src_mask_len = 0;
612 rule.data.userdata = 0;
614 /* try adding this rule (it should fail because userdata is invalid) */
615 ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
617 printf("Line %i: Adding a rule with invalid user data "
618 "should have failed!\n", __LINE__);
634 * test functions by passing invalid or
635 * non-workable parameters.
637 * we do very limited testing of classify functions here
638 * because those are performance-critical and
639 * thus don't do much parameter checking.
642 test_invalid_parameters(void)
644 struct rte_acl_param param;
645 struct rte_acl_ctx *acx;
646 struct rte_acl_ipv4vlan_rule rule;
649 uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
657 acx = rte_acl_create(NULL);
659 printf("Line %i: ACL context creation with NULL param "
660 "should have failed!\n", __LINE__);
666 memcpy(¶m, &acl_param, sizeof(param));
669 acx = rte_acl_create(¶m);
671 printf("Line %i: ACL context creation with zero rule len "
672 "failed!\n", __LINE__);
677 /* zero max rule num */
678 memcpy(¶m, &acl_param, sizeof(param));
679 param.max_rule_num = 0;
681 acx = rte_acl_create(¶m);
683 printf("Line %i: ACL context creation with zero rule num "
684 "failed!\n", __LINE__);
689 /* invalid NUMA node */
690 memcpy(¶m, &acl_param, sizeof(param));
691 param.socket_id = RTE_MAX_NUMA_NODES + 1;
693 acx = rte_acl_create(¶m);
695 printf("Line %i: ACL context creation with invalid NUMA "
696 "should have failed!\n", __LINE__);
702 memcpy(¶m, &acl_param, sizeof(param));
705 acx = rte_acl_create(¶m);
707 printf("Line %i: ACL context creation with NULL name "
708 "should have failed!\n", __LINE__);
714 * rte_acl_find_existing
717 acx = rte_acl_find_existing(NULL);
719 printf("Line %i: NULL ACL context found!\n", __LINE__);
725 * rte_acl_ipv4vlan_add_rules
728 /* initialize everything */
729 memcpy(¶m, &acl_param, sizeof(param));
730 acx = rte_acl_create(¶m);
732 printf("Line %i: ACL context creation failed!\n", __LINE__);
736 memcpy(&rule, &acl_rule, sizeof(rule));
739 result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1);
741 printf("Line %i: Adding rules with NULL ACL context "
742 "should have failed!\n", __LINE__);
748 result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1);
750 printf("Line %i: Adding NULL rule to ACL context "
751 "should have failed!\n", __LINE__);
756 /* zero count (should succeed) */
757 result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0);
759 printf("Line %i: Adding 0 rules to ACL context failed!\n",
765 /* free ACL context */
768 /* set wrong rule_size so that adding any rules would fail */
769 param.rule_size = RTE_ACL_IPV4VLAN_RULE_SZ + 4;
770 acx = rte_acl_create(¶m);
772 printf("Line %i: ACL context creation failed!\n", __LINE__);
776 /* try adding a rule with size different from context rule_size */
777 result = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
779 printf("Line %i: Adding an invalid sized rule "
780 "should have failed!\n", __LINE__);
785 /* free ACL context */
790 * rte_acl_ipv4vlan_build
793 /* reinitialize context */
794 memcpy(¶m, &acl_param, sizeof(param));
795 acx = rte_acl_create(¶m);
797 printf("Line %i: ACL context creation failed!\n", __LINE__);
802 result = rte_acl_ipv4vlan_build(NULL, layout, 1);
804 printf("Line %i: Building with NULL context "
805 "should have failed!\n", __LINE__);
811 result = rte_acl_ipv4vlan_build(acx, NULL, 1);
813 printf("Line %i: Building with NULL layout "
814 "should have failed!\n", __LINE__);
819 /* zero categories (should not fail) */
820 result = rte_acl_ipv4vlan_build(acx, layout, 0);
822 printf("Line %i: Building with 0 categories should fail!\n",
828 /* SSE classify test */
830 /* cover zero categories in classify (should not fail) */
831 result = rte_acl_classify(acx, NULL, NULL, 0, 0);
833 printf("Line %i: SSE classify with zero categories "
834 "failed!\n", __LINE__);
839 /* cover invalid but positive categories in classify */
840 result = rte_acl_classify(acx, NULL, NULL, 0, 3);
842 printf("Line %i: SSE classify with 3 categories "
843 "should have failed!\n", __LINE__);
848 /* scalar classify test */
850 /* cover zero categories in classify (should not fail) */
851 result = rte_acl_classify_scalar(acx, NULL, NULL, 0, 0);
853 printf("Line %i: Scalar classify with zero categories "
854 "failed!\n", __LINE__);
859 /* cover invalid but positive categories in classify */
860 result = rte_acl_classify_scalar(acx, NULL, NULL, 0, 3);
862 printf("Line %i: Scalar classify with 3 categories "
863 "should have failed!\n", __LINE__);
868 /* free ACL context */
873 * make sure void functions don't crash with NULL parameters
884 * Various tests that don't test much but improve coverage
889 struct rte_acl_param param;
890 struct rte_acl_ctx *acx;
893 memcpy(¶m, &acl_param, sizeof(param));
895 acx = rte_acl_create(¶m);
897 printf("Line %i: Error creating ACL context!\n", __LINE__);
901 /* dump context with rules - useful for coverage */
914 if (test_invalid_parameters() < 0)
916 if (test_invalid_rules() < 0)
918 if (test_create_find_add() < 0)
920 if (test_invalid_layout() < 0)
924 if (test_classify() < 0)
930 static struct test_command acl_cmd = {
931 .command = "acl_autotest",
932 .callback = test_acl,
934 REGISTER_TEST_COMMAND(acl_cmd);