From 0100a515b5631b5a598e75bdf838870caab50470 Mon Sep 17 00:00:00 2001 From: Intel Date: Tue, 12 Mar 2013 12:03:00 +0100 Subject: [PATCH] pmac: integration without lib This library could be used for pattern matching and ACL. Code of librte_pmac is not released as Open Source. Signed-off-by: Intel --- app/Makefile | 3 + app/test/Makefile | 2 + app/test/autotest_data.py | 19 + app/test/commands.c | 7 +- app/test/test.h | 2 + app/test/test_pmac_acl.c | 888 ++++++++++ app/test/test_pmac_acl.h | 634 +++++++ app/test/test_pmac_pm.c | 1550 +++++++++++++++++ app/test/test_pmac_pm.h | 230 +++ lib/Makefile | 1 + lib/librte_eal/common/include/rte_log.h | 1 + .../common/include/rte_tailq_elem.h | 4 + mk/rte.app.mk | 4 + 13 files changed, 3344 insertions(+), 1 deletion(-) create mode 100644 app/test/test_pmac_acl.c create mode 100644 app/test/test_pmac_acl.h create mode 100644 app/test/test_pmac_pm.c create mode 100644 app/test/test_pmac_pm.h diff --git a/app/Makefile b/app/Makefile index 4af5631320..7a019ab0cf 100644 --- a/app/Makefile +++ b/app/Makefile @@ -36,5 +36,8 @@ DIRS-$(CONFIG_RTE_APP_TEST) += test DIRS-$(CONFIG_RTE_TEST_PMD) += test-pmd DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += cmdline_test DIRS-$(CONFIG_RTE_LIBRTE_EAL_LINUXAPP) += dump_cfg +DIRS-$(CONFIG_RTE_LIBRTE_PMAC) += test-pm +DIRS-$(CONFIG_RTE_LIBRTE_PMAC) += test-acl + include $(RTE_SDK)/mk/rte.subdir.mk diff --git a/app/test/Makefile b/app/test/Makefile index 543db4a3ac..01241765bb 100644 --- a/app/test/Makefile +++ b/app/test/Makefile @@ -84,6 +84,8 @@ SRCS-$(CONFIG_RTE_APP_TEST) += test_cmdline_ipaddr.c SRCS-$(CONFIG_RTE_APP_TEST) += test_cmdline_cirbuf.c SRCS-$(CONFIG_RTE_APP_TEST) += test_cmdline_string.c SRCS-$(CONFIG_RTE_APP_TEST) += test_cmdline_lib.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_pmac_pm.c +SRCS-$(CONFIG_RTE_APP_TEST) += test_pmac_acl.c CFLAGS += -O3 CFLAGS += $(WERROR_FLAGS) diff --git a/app/test/autotest_data.py b/app/test/autotest_data.py index 7a15b35de2..7c5b96449d 100644 --- a/app/test/autotest_data.py +++ b/app/test/autotest_data.py @@ -291,6 +291,25 @@ parallel_test_group_list = [ }, ] }, +{ + "Prefix" : "group_7", + "Memory" : "400", + "Tests" : + [ + { + "Name" : "Access list control autotest", + "Command" : "acl_autotest", + "Func" : default_autotest, + "Report" : None, + }, + { + "Name" : "Pattern match autotest", + "Command" : "pm_autotest", + "Func" : default_autotest, + "Report" : None, + }, + ] +}, ] # tests that should not be run when any other tests are running diff --git a/app/test/commands.c b/app/test/commands.c index b42ca34ae9..705671c600 100644 --- a/app/test/commands.c +++ b/app/test/commands.c @@ -165,6 +165,10 @@ static void cmd_autotest_parsed(void *parsed_result, ret |= test_memcpy_perf(); if (all || !strcmp(res->autotest, "func_reentrancy_autotest")) ret |= test_func_reentrancy(); + if (all || !strcmp(res->autotest, "pm_autotest")) + ret |= test_pmac_pm(); + if (all || !strcmp(res->autotest, "acl_autotest")) + ret |= test_pmac_acl(); if (ret == 0) printf("Test OK\n"); @@ -192,7 +196,8 @@ cmdline_parse_token_string_t cmd_autotest_autotest = "version_autotest#eal_fs_autotest#" "cmdline_autotest#func_reentrancy_autotest#" "mempool_perf_autotest#hash_perf_autotest#" - "memcpy_perf_autotest#" + "memcpy_perf_autotest#pm_autotest#" + "acl_autotest#" "all_autotests"); cmdline_parse_inst_t cmd_autotest = { diff --git a/app/test/test.h b/app/test/test.h index 538c39fe21..ef62ba06ff 100644 --- a/app/test/test.h +++ b/app/test/test.h @@ -85,6 +85,8 @@ int test_version(void); int test_eal_fs(void); int test_cmdline(void); int test_func_reentrancy(void); +int test_pmac_pm(void); +int test_pmac_acl(void); int test_pci_run; diff --git a/app/test/test_pmac_acl.c b/app/test/test_pmac_acl.c new file mode 100644 index 0000000000..fe7172bcc6 --- /dev/null +++ b/app/test/test_pmac_acl.c @@ -0,0 +1,888 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +#include +#include + +#include "test.h" + +#ifdef RTE_LIBRTE_PMAC + +#include +#include +#include + +#include "test_pmac_acl.h" + +#define LEN RTE_ACL_MAX_CATEGORIES + +struct rte_acl_param acl_param = { + .name = "acl_ctx", + .socket_id = SOCKET_ID_ANY, + .rule_size = sizeof(struct rte_acl_ipv4vlan_rule), + .max_rule_num = 0x30000, +}; + +struct rte_acl_ipv4vlan_rule acl_rule = { + .data = { .priority = 1, .category_mask = 0xff }, + .src_port_low = 0, + .src_port_high = UINT16_MAX, + .dst_port_low = 0, + .dst_port_high = UINT16_MAX, +}; + +/* byteswap to cpu or network order */ +static void +bswap_test_data(struct ipv4_7tuple * data, int len, int to_be) +{ + int i; + + for (i = 0; i < len; i++) { + + if (to_be) { + /* swap all bytes so that they are in network order */ + data[i].ip_dst = rte_cpu_to_be_32(data[i].ip_dst); + data[i].ip_src = rte_cpu_to_be_32(data[i].ip_src); + data[i].port_dst = rte_cpu_to_be_16(data[i].port_dst); + data[i].port_src = rte_cpu_to_be_16(data[i].port_src); + data[i].vlan = rte_cpu_to_be_16(data[i].vlan); + data[i].domain = rte_cpu_to_be_16(data[i].domain); + } + else { + data[i].ip_dst = rte_be_to_cpu_32(data[i].ip_dst); + data[i].ip_src = rte_be_to_cpu_32(data[i].ip_src); + data[i].port_dst = rte_be_to_cpu_16(data[i].port_dst); + data[i].port_src = rte_be_to_cpu_16(data[i].port_src); + data[i].vlan = rte_be_to_cpu_16(data[i].vlan); + data[i].domain = rte_be_to_cpu_16(data[i].domain); + } + } +} + +/* + * Test scalar and SSE ACL lookup. + */ +static int +test_classify(void) +{ + struct rte_acl_ctx * acx; + int ret, i; + uint32_t result, count; + + uint32_t results[DIM(acl_test_data) * RTE_ACL_MAX_CATEGORIES]; + + const uint8_t * data[DIM(acl_test_data)]; + + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = { + offsetof(struct ipv4_7tuple, proto), + offsetof(struct ipv4_7tuple, vlan), + offsetof(struct ipv4_7tuple, ip_src), + offsetof(struct ipv4_7tuple, ip_dst), + offsetof(struct ipv4_7tuple, port_src), + }; + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* add rules to the context */ + ret = rte_acl_ipv4vlan_add_rules(acx, acl_test_rules, + DIM(acl_test_rules)); + if (ret != 0) { + printf("Line %i: Adding rules to ACL context failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* try building the context */ + ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES); + if (ret != 0) { + printf("Line %i: Building ACL context failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* swap all bytes in the data to network order */ + bswap_test_data(acl_test_data, DIM(acl_test_data), 1); + + /* store pointers to test data */ + for (i = 0; i < (int) DIM(acl_test_data); i++) + data[i] = (uint8_t *)&acl_test_data[i]; + + /** + * these will run quite a few times, it's necessary to test code paths + * from num=0 to num>8 + */ + for (count = 0; count < DIM(acl_test_data); count++) { + ret = rte_acl_classify(acx, data, results, + count, RTE_ACL_MAX_CATEGORIES); + if (ret != 0) { + printf("Line %i: SSE classify failed!\n", __LINE__); + goto err; + } + + /* check if we allow everything we should allow */ + for (i = 0; i < (int) count; i++) { + result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW]; + if (result != acl_test_data[i].allow) { + printf("Line %i: Error in allow results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].allow, + result); + goto err; + } + } + + /* check if we deny everything we should deny */ + for (i = 0; i < (int) count; i++) { + result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY]; + if (result != acl_test_data[i].deny) { + printf("Line %i: Error in deny results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].deny, + result); + goto err; + } + } + } + + /* make a quick check for scalar */ + ret = rte_acl_classify_scalar(acx, data, results, + DIM(acl_test_data), RTE_ACL_MAX_CATEGORIES); + if (ret != 0) { + printf("Line %i: SSE classify failed!\n", __LINE__); + goto err; + } + + /* check if we allow everything we should allow */ + for (i = 0; i < (int) DIM(acl_test_data); i++) { + result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_ALLOW]; + if (result != acl_test_data[i].allow) { + printf("Line %i: Error in allow results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].allow, + result); + goto err; + } + } + + /* check if we deny everything we should deny */ + for (i = 0; i < (int) DIM(acl_test_data); i++) { + result = results[i * RTE_ACL_MAX_CATEGORIES + ACL_DENY]; + if (result != acl_test_data[i].deny) { + printf("Line %i: Error in deny results at %i " + "(expected %"PRIu32" got %"PRIu32")!\n", + __LINE__, i, acl_test_data[i].deny, + result); + goto err; + } + } + + /* free ACL context */ + rte_acl_free(acx); + + /* swap data back to cpu order so that next time tests don't fail */ + bswap_test_data(acl_test_data, DIM(acl_test_data), 0); + + return 0; +err: + + /* swap data back to cpu order so that next time tests don't fail */ + bswap_test_data(acl_test_data, DIM(acl_test_data), 0); + + rte_acl_free(acx); + + return -1; +} + +/* + * Test wrong layout behavior + * This test supplies the ACL context with invalid layout, which results in + * ACL matching the wrong stuff. However, it should match the wrong stuff + * the right way. We switch around source and destination addresses, + * source and destination ports, and protocol will point to first byte of + * destination port. + */ +static int +test_invalid_layout(void) +{ + struct rte_acl_ctx * acx; + int ret, i; + + uint32_t results[DIM(invalid_layout_data)]; + const uint8_t * data[DIM(invalid_layout_data)]; + + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = { + /* proto points to destination port's first byte */ + offsetof(struct ipv4_7tuple, port_dst), + + 0, /* VLAN not used */ + + /* src and dst addresses are swapped */ + offsetof(struct ipv4_7tuple, ip_dst), + offsetof(struct ipv4_7tuple, ip_src), + + /* we can't swap ports here, so we will swap them in the data */ + offsetof(struct ipv4_7tuple, port_src), + }; + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* putting a lot of rules into the context results in greater + * coverage numbers. it doesn't matter if they are identical */ + for (i = 0; i < 1000; i++) { + /* add rules to the context */ + ret = rte_acl_ipv4vlan_add_rules(acx, invalid_layout_rules, + DIM(invalid_layout_rules)); + if (ret != 0) { + printf("Line %i: Adding rules to ACL context failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + } + + /* try building the context */ + ret = rte_acl_ipv4vlan_build(acx, layout, 1); + if (ret != 0) { + printf("Line %i: Building ACL context failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* swap all bytes in the data to network order */ + bswap_test_data(invalid_layout_data, DIM(invalid_layout_data), 1); + + /* prepare data */ + for (i = 0; i < (int) DIM(invalid_layout_data); i++) { + data[i] = (uint8_t *)&invalid_layout_data[i]; + } + + /* classify tuples */ + ret = rte_acl_classify(acx, data, results, + DIM(results), 1); + if (ret != 0) { + printf("Line %i: SSE classify failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + for (i = 0; i < (int) DIM(results); i++) { + if (results[i] != invalid_layout_data[i].allow) { + printf("Line %i: Wrong results at %i (result=%u, should be %u)!\n", + __LINE__, i, results[i], invalid_layout_data[i].allow); + goto err; + } + } + + /* classify tuples (scalar) */ + ret = rte_acl_classify_scalar(acx, data, results, + DIM(results), 1); + if (ret != 0) { + printf("Line %i: Scalar classify failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + for (i = 0; i < (int) DIM(results); i++) { + if (results[i] != invalid_layout_data[i].allow) { + printf("Line %i: Wrong results at %i (result=%u, should be %u)!\n", + __LINE__, i, results[i], invalid_layout_data[i].allow); + goto err; + } + } + + rte_acl_free(acx); + + /* swap data back to cpu order so that next time tests don't fail */ + bswap_test_data(invalid_layout_data, DIM(invalid_layout_data), 0); + + return 0; +err: + + /* swap data back to cpu order so that next time tests don't fail */ + bswap_test_data(invalid_layout_data, DIM(invalid_layout_data), 0); + + rte_acl_free(acx); + + return -1; +} + +/* + * Test creating and finding ACL contexts, and adding rules + */ +static int +test_create_find_add(void) +{ + struct rte_acl_param param; + struct rte_acl_ctx * acx, *acx2, *tmp; + struct rte_acl_ipv4vlan_rule rules[LEN]; + + const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0}; + + const char * acx_name = "acx"; + const char * acx2_name = "acx2"; + int i, ret; + + /* create two contexts */ + memcpy(¶m, &acl_param, sizeof(param)); + param.max_rule_num = 2; + + param.name = acx_name; + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: Error creating %s!\n", __LINE__, acx_name); + return -1; + } + + param.name = acx2_name; + acx2 = rte_acl_create(¶m); + if (acx2 == NULL || acx2 == acx) { + printf("Line %i: Error creating %s!\n", __LINE__, acx2_name); + rte_acl_free(acx); + return -1; + } + + /* try to create third one, with an existing name */ + param.name = acx_name; + tmp = rte_acl_create(¶m); + if (tmp != acx) { + printf("Line %i: Creating context with existing name test failed!\n", + __LINE__); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + param.name = acx2_name; + tmp = rte_acl_create(¶m); + if (tmp != acx2) { + printf("Line %i: Creating context with existing name test 2 failed!\n", + __LINE__); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + /* try to find existing PM contexts */ + tmp = rte_acl_find_existing(acx_name); + if (tmp != acx) { + printf("Line %i: Finding %s failed!\n", __LINE__, acx_name); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + tmp = rte_acl_find_existing(acx2_name); + if (tmp != acx2) { + printf("Line %i: Finding %s failed!\n", __LINE__, acx2_name); + if (tmp) + rte_acl_free(tmp); + goto err; + } + + /* try to find non-existing context */ + tmp = rte_acl_find_existing("invalid"); + if (tmp != NULL) { + printf("Line %i: Non-existent PM context found!\n", __LINE__); + goto err; + } + + /* free context */ + rte_acl_free(acx); + + + /* create valid (but severely limited) acx */ + memcpy(¶m, &acl_param, sizeof(param)); + param.max_rule_num = LEN; + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: Error creating %s!\n", __LINE__, param.name); + goto err; + } + + /* create dummy acl */ + for (i = 0; i < LEN; i++) { + memcpy(&rules[i], &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule)); + rules[i].data.userdata = i + 1; /* skip zero */ + rules[i].data.category_mask = 1 << i; /* one rule per category */ + } + + /* try filling up the context */ + ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN); + if (ret != 0) { + printf("Line %i: Adding %i rules to ACL context failed!\n", + __LINE__, LEN); + goto err; + } + + /* try adding to a (supposedly) full context */ + ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1); + if (ret == 0) { + printf("Line %i: Adding rules to full ACL context should" + "have failed!\n", __LINE__); + goto err; + } + + /* try building the context */ + ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES); + if (ret != 0) { + printf("Line %i: Building ACL context failed!\n", __LINE__); + goto err; + } + + rte_acl_free(acx); + rte_acl_free(acx2); + + return 0; +err: + rte_acl_free(acx); + rte_acl_free(acx2); + return -1; +} + +/* + * test various invalid rules + */ +static int +test_invalid_rules(void) +{ + struct rte_acl_ctx * acx; + int ret; + + struct rte_acl_ipv4vlan_rule rule; + + acx = rte_acl_create(&acl_param); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* test inverted high/low source and destination ports. + * originally, there was a problem with memory consumption when using + * such rules. + */ + /* create dummy acl */ + memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule)); + rule.data.userdata = 1; + rule.dst_port_low = 0xfff0; + rule.dst_port_high = 0x0010; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rule.dst_port_low = 0x0; + rule.dst_port_high = 0xffff; + rule.src_port_low = 0xfff0; + rule.src_port_high = 0x0010; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rule.dst_port_low = 0x0; + rule.dst_port_high = 0xffff; + rule.src_port_low = 0x0; + rule.src_port_high = 0xffff; + + rule.dst_mask_len = 33; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rule.dst_mask_len = 0; + rule.src_mask_len = 33; + + /* add rules to context and try to build it */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding rules to ACL context " + "should have failed!\n", __LINE__); + goto err; + } + + rule.dst_mask_len = 0; + rule.src_mask_len = 0; + rule.data.userdata = 0; + + /* try adding this rule (it should fail because userdata is invalid) */ + ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (ret == 0) { + printf("Line %i: Adding a rule with invalid user data " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + rte_acl_free(acx); + + return 0; + +err: + rte_acl_free(acx); + + return -1; +} + +/* + * test functions by passing invalid or + * non-workable parameters. + * + * we do very limited testing of classify functions here + * because those are performance-critical and + * thus don't do much parameter checking. + */ +static int +test_invalid_parameters(void) +{ + struct rte_acl_param param; + struct rte_acl_ctx * acx; + struct rte_acl_ipv4vlan_rule rule; + int result; + + uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0}; + + + /** + * rte_ac_create() + */ + + /* NULL param */ + acx = rte_acl_create(NULL); + if (acx != NULL) { + printf("Line %i: ACL context creation with NULL param " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* zero rule size */ + memcpy(¶m, &acl_param, sizeof(param)); + param.rule_size = 0; + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation with zero rule len " + "failed!\n", __LINE__); + return -1; + } + else + rte_acl_free(acx); + + /* zero max rule num */ + memcpy(¶m, &acl_param, sizeof(param)); + param.max_rule_num = 0; + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation with zero rule num " + "failed!\n", __LINE__); + return -1; + } + else + rte_acl_free(acx); + + /* invalid NUMA node */ + memcpy(¶m, &acl_param, sizeof(param)); + param.socket_id = RTE_MAX_NUMA_NODES + 1; + + acx = rte_acl_create(¶m); + if (acx != NULL) { + printf("Line %i: ACL context creation with invalid NUMA " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* NULL name */ + memcpy(¶m, &acl_param, sizeof(param)); + param.name = NULL; + + acx = rte_acl_create(¶m); + if (acx != NULL) { + printf("Line %i: ACL context creation with NULL name " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /** + * rte_acl_find_existing + */ + + acx = rte_acl_find_existing(NULL); + if (acx != NULL) { + printf("Line %i: NULL ACL context found!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /** + * rte_acl_ipv4vlan_add_rules + */ + + /* initialize everything */ + memcpy(¶m, &acl_param, sizeof(param)); + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation failed!\n", __LINE__); + return -1; + } + + memcpy(&rule, &acl_rule, sizeof(rule)); + + /* NULL context */ + result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1); + if (result == 0) { + printf("Line %i: Adding rules with NULL ACL context " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* NULL rule */ + result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1); + if (result == 0) { + printf("Line %i: Adding NULL rule to ACL context " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* zero count (should succeed) */ + result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0); + if (result != 0) { + printf("Line %i: Adding 0 rules to ACL context failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* free ACL context */ + rte_acl_free(acx); + + /* set wrong rule_size so that adding any rules would fail */ + param.rule_size = sizeof(struct rte_acl_ipv4vlan_rule) + 4; + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation failed!\n", __LINE__); + return -1; + } + + /* try adding a rule with size different from context rule_size */ + result = rte_acl_ipv4vlan_add_rules(acx, &rule, 1); + if (result == 0) { + printf("Line %i: Adding an invalid sized rule " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* free ACL context */ + rte_acl_free(acx); + + + /** + * rte_acl_ipv4vlan_build + */ + + /* reinitialize context */ + memcpy(¶m, &acl_param, sizeof(param)); + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: ACL context creation failed!\n", __LINE__); + return -1; + } + + /* NULL context */ + result = rte_acl_ipv4vlan_build(NULL, layout, 1); + if (result == 0) { + printf("Line %i: Building with NULL context " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* NULL layout */ + result = rte_acl_ipv4vlan_build(acx, NULL, 1); + if (result == 0) { + printf("Line %i: Building with NULL layout " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* zero categories (should not fail) */ + result = rte_acl_ipv4vlan_build(acx, layout, 0); + if (result != 0) { + printf("Line %i: Building with 0 categories failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* SSE classify test */ + + /* cover zero categories in classify (should not fail) */ + result = rte_acl_classify(acx, NULL, NULL, 0, 0); + if (result != 0) { + printf("Line %i: SSE classify with zero categories " + "failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* cover invalid but positive categories in classify */ + result = rte_acl_classify(acx, NULL, NULL, 0, 3); + if (result == 0) { + printf("Line %i: SSE classify with 3 categories " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* scalar classify test */ + + /* cover zero categories in classify (should not fail) */ + result = rte_acl_classify_scalar(acx, NULL, NULL, 0, 0); + if (result != 0) { + printf("Line %i: Scalar classify with zero categories " + "failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* cover invalid but positive categories in classify */ + result = rte_acl_classify_scalar(acx, NULL, NULL, 0, 3); + if (result == 0) { + printf("Line %i: Scalar classify with 3 categories " + "should have failed!\n", __LINE__); + rte_acl_free(acx); + return -1; + } + + /* free ACL context */ + rte_acl_free(acx); + + + /** + * make sure void functions don't crash with NULL parameters + */ + + rte_acl_free(NULL); + + rte_acl_dump(NULL); + + return 0; +} + +/** + * Various tests that don't test much but improve coverage + */ +static int +test_misc(void) +{ + struct rte_acl_param param; + struct rte_acl_ctx * acx; + + /* create context */ + memcpy(¶m, &acl_param, sizeof(param)); + + acx = rte_acl_create(¶m); + if (acx == NULL) { + printf("Line %i: Error creating ACL context!\n", __LINE__); + return -1; + } + + /* dump context with rules - useful for coverage */ + rte_acl_list_dump(); + + rte_acl_dump(acx); + + rte_acl_free(acx); + + return 0; +} + +int +test_pmac_acl(void) +{ + if (test_invalid_parameters() < 0) + return -1; + if (test_invalid_rules() < 0) + return -1; + if (test_create_find_add() < 0) + return -1; + if (test_invalid_layout() < 0) + return -1; + if (test_misc() < 0) + return -1; + if (test_classify() < 0) + return -1; + + return 0; +} +#else + +int +test_pmac_acl(void) +{ + printf("This binary was not compiled with PMAC support!\n"); + return 0; +} + +#endif /* RTE_LIBRTE_PMAC */ diff --git a/app/test/test_pmac_acl.h b/app/test/test_pmac_acl.h new file mode 100644 index 0000000000..2e9f4059bd --- /dev/null +++ b/app/test/test_pmac_acl.h @@ -0,0 +1,634 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TEST_PMAC_ACL_H_ +#define TEST_PMAC_ACL_H_ + +struct ipv4_7tuple { + uint16_t vlan; + uint16_t domain; + uint8_t proto; + uint32_t ip_src; + uint32_t ip_dst; + uint16_t port_src; + uint16_t port_dst; + uint32_t allow; + uint32_t deny; +}; + +/* rules for invalid layout test */ +struct rte_acl_ipv4vlan_rule invalid_layout_rules[] = { + /* test src and dst address */ + { + .data = {.userdata = 1, .category_mask = 1}, + .src_addr = IPv4(10,0,0,0), + .src_mask_len = 24, + }, + { + .data = {.userdata = 2, .category_mask = 1}, + .dst_addr = IPv4(10,0,0,0), + .dst_mask_len = 24, + }, + /* test src and dst ports */ + { + .data = {.userdata = 3, .category_mask = 1}, + .dst_port_low = 100, + .dst_port_high = 100, + }, + { + .data = {.userdata = 4, .category_mask = 1}, + .src_port_low = 100, + .src_port_high = 100, + }, + /* test proto */ + { + .data = {.userdata = 5, .category_mask = 1}, + .proto = 0xf, + .proto_mask = 0xf + }, + { + .data = {.userdata = 6, .category_mask = 1}, + .dst_port_low = 0xf, + .dst_port_high = 0xf, + } +}; + +/* these might look odd because they don't match up the rules. This is + * intentional, as the invalid layout test presumes returning the correct + * results using the wrong data layout. + */ +struct ipv4_7tuple invalid_layout_data[] = { + {.ip_src = IPv4(10,0,1,0)}, /* should not match */ + {.ip_src = IPv4(10,0,0,1), .allow = 2}, /* should match 2 */ + {.port_src = 100, .allow = 4}, /* should match 4 */ + {.port_dst = 0xf, .allow = 6}, /* should match 6 */ +}; + +#define ACL_ALLOW 0 +#define ACL_DENY 1 +#define ACL_ALLOW_MASK 0x1 +#define ACL_DENY_MASK 0x2 + +/* ruleset for ACL unit test */ +struct rte_acl_ipv4vlan_rule acl_test_rules[] = { +/* destination IP addresses */ + /* matches all packets traveling to 192.168.0.0/16 */ + { + .data = {.userdata = 1, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .dst_addr = IPv4(192,168,0,0), + .dst_mask_len = 16, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling to 192.168.1.0/24 */ + { + .data = {.userdata = 2, .category_mask = ACL_ALLOW_MASK, + .priority = 3}, + .dst_addr = IPv4(192,168,1,0), + .dst_mask_len = 24, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling to 192.168.1.50 */ + { + .data = {.userdata = 3, .category_mask = ACL_DENY_MASK, + .priority = 2}, + .dst_addr = IPv4(192,168,1,50), + .dst_mask_len = 32, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* source IP addresses */ + /* matches all packets traveling from 10.0.0.0/8 */ + { + .data = {.userdata = 4, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .src_addr = IPv4(10,0,0,0), + .src_mask_len = 8, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling from 10.1.1.0/24 */ + { + .data = {.userdata = 5, .category_mask = ACL_ALLOW_MASK, + .priority = 3}, + .src_addr = IPv4(10,1,1,0), + .src_mask_len = 24, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets traveling from 10.1.1.1 */ + { + .data = {.userdata = 6, .category_mask = ACL_DENY_MASK, + .priority = 2}, + .src_addr = IPv4(10,1,1,1), + .src_mask_len = 32, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* VLAN tag */ + /* matches all packets with lower 7 bytes of VLAN tag equal to 0x64 */ + { + .data = {.userdata = 7, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .vlan = 0x64, + .vlan_mask = 0x7f, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with VLAN tags that have 0x5 in them */ + { + .data = {.userdata = 8, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .vlan = 0x5, + .vlan_mask = 0x5, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with VLAN tag 5 */ + { + .data = {.userdata = 9, .category_mask = ACL_DENY_MASK, + .priority = 3}, + .vlan = 0x5, + .vlan_mask = 0xffff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* VLAN domain */ + /* matches all packets with lower 7 bytes of domain equal to 0x64 */ + { + .data = {.userdata = 10, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .domain = 0x64, + .domain_mask = 0x7f, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with domains that have 0x5 in them */ + { + .data = {.userdata = 11, .category_mask = ACL_ALLOW_MASK, + .priority = 3}, + .domain = 0x5, + .domain_mask = 0x5, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with domain 5 */ + { + .data = {.userdata = 12, .category_mask = ACL_DENY_MASK, + .priority = 3}, + .domain = 0x5, + .domain_mask = 0xffff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* destination port */ + /* matches everything with dst port 80 */ + { + .data = {.userdata = 13, .category_mask = ACL_ALLOW_MASK, + .priority = 3}, + .dst_port_low = 80, + .dst_port_high = 80, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + /* matches everything with dst port 22-1023 */ + { + .data = {.userdata = 14, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .dst_port_low = 22, + .dst_port_high = 1023, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + /* matches everything with dst port 1020 */ + { + .data = {.userdata = 15, .category_mask = ACL_DENY_MASK, + .priority = 3}, + .dst_port_low = 1020, + .dst_port_high = 1020, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + /* matches everything with dst portrange 1000-2000 */ + { + .data = {.userdata = 16, .category_mask = ACL_DENY_MASK, + .priority = 2}, + .dst_port_low = 1000, + .dst_port_high = 2000, + .src_port_low = 0, + .src_port_high = 0xffff, + }, + +/* source port */ + /* matches everything with src port 80 */ + { + .data = {.userdata = 17, .category_mask = ACL_ALLOW_MASK, + .priority = 3}, + .src_port_low = 80, + .src_port_high = 80, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches everything with src port 22-1023 */ + { + .data = {.userdata = 18, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .src_port_low = 22, + .src_port_high = 1023, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches everything with src port 1020 */ + { + .data = {.userdata = 19, .category_mask = ACL_DENY_MASK, + .priority = 3}, + .src_port_low = 1020, + .src_port_high = 1020, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches everything with src portrange 1000-2000 */ + { + .data = {.userdata = 20, .category_mask = ACL_DENY_MASK, + .priority = 2}, + .src_port_low = 1000, + .src_port_high = 2000, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* protocol number */ + /* matches all packets with protocol number either 0x64 or 0xE4 */ + { + .data = {.userdata = 21, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .proto = 0x64, + .proto_mask = 0x7f, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with protocol that have 0x5 in them */ + { + .data = {.userdata = 22, .category_mask = ACL_ALLOW_MASK, + .priority = 2}, + .proto = 0x5, + .proto_mask = 0x5, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + /* matches all packets with protocol 5 */ + { + .data = {.userdata = 23, .category_mask = ACL_DENY_MASK, + .priority = 3}, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 0, + .dst_port_high = 0xffff, + }, + +/* rules combining various fields */ + { + .data = {.userdata = 24, .category_mask = ACL_ALLOW_MASK, + .priority = 4}, + /** make sure that unmasked bytes don't fail! */ + .dst_addr = IPv4(1,2,3,4), + .dst_mask_len = 16, + .src_addr = IPv4(5,6,7,8), + .src_mask_len = 24, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x8100, + .vlan_mask = 0xffff, + .domain = 0x64, + .domain_mask = 0xffff, + }, + { + .data = {.userdata = 25, .category_mask = ACL_DENY_MASK, + .priority = 4}, + .dst_addr = IPv4(5,6,7,8), + .dst_mask_len = 24, + .src_addr = IPv4(1,2,3,4), + .src_mask_len = 16, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x8100, + .vlan_mask = 0xffff, + .domain = 0x64, + .domain_mask = 0xffff, + }, + { + .data = {.userdata = 26, .category_mask = ACL_ALLOW_MASK, + .priority = 5}, + .dst_addr = IPv4(1,2,3,4), + .dst_mask_len = 8, + .src_addr = IPv4(5,6,7,8), + .src_mask_len = 32, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x64, + .vlan_mask = 0xffff, + }, + { + .data = {.userdata = 27, .category_mask = ACL_DENY_MASK, + .priority = 5}, + .dst_addr = IPv4(5,6,7,8), + .dst_mask_len = 32, + .src_addr = IPv4(1,2,3,4), + .src_mask_len = 8, + .proto = 0x5, + .proto_mask = 0xff, + .src_port_low = 0, + .src_port_high = 0xffff, + .dst_port_low = 22, + .dst_port_high = 1024, + .vlan = 0x64, + .vlan_mask = 0xffff, + }, +}; + +/* data for ACL unit test */ +struct ipv4_7tuple acl_test_data[] = { +/* testing single rule aspects */ + {.ip_src = IPv4(10,0,0,0), .allow = 4}, /* should match 4 */ + {.ip_src = IPv4(10,1,1,2), .allow = 5}, /* should match 5 */ + {.ip_src = IPv4(10,1,1,1), .allow = 5, + .deny = 6}, /* should match 5, 6 */ + {.ip_dst = IPv4(10,0,0,0)}, /* should not match */ + {.ip_dst = IPv4(10,1,1,2)}, /* should not match */ + {.ip_dst = IPv4(10,1,1,1)}, /* should not match */ + + {.ip_src = IPv4(192,168,2,50)}, /* should not match */ + {.ip_src = IPv4(192,168,1,2)}, /* should not match */ + {.ip_src = IPv4(192,168,1,50)}, /* should not match */ + {.ip_dst = IPv4(192,168,2,50), .allow = 1}, /* should match 1 */ + {.ip_dst = IPv4(192,168,1,49), .allow = 2}, /* should match 2 */ + {.ip_dst = IPv4(192,168,1,50), .allow = 2, + .deny = 3}, /* should match 2, 3 */ + + {.vlan = 0x64, .allow = 7}, /* should match 7 */ + {.vlan = 0xfE4, .allow = 7}, /* should match 7 */ + {.vlan = 0xE2}, /* should not match */ + {.vlan = 0xD, .allow = 8}, /* should match 8 */ + {.vlan = 0x6}, /* should not match */ + {.vlan = 0x5, .allow = 8, .deny = 9}, /* should match 8, 9 */ + + {.domain = 0x64, .allow = 10}, /* should match 10 */ + {.domain = 0xfE4, .allow = 10}, /* should match 10 */ + {.domain = 0xE2}, /* should not match */ + {.domain = 0xD, .allow = 11}, /* should match 11 */ + {.domain = 0x6}, /* should not match */ + {.domain = 0x5, .allow = 11, .deny = 12}, /* should match 11, 12 */ + + {.port_dst = 80, .allow = 13}, /* should match 13 */ + {.port_dst = 79, .allow = 14}, /* should match 14 */ + {.port_dst = 81, .allow = 14}, /* should match 14 */ + {.port_dst = 21}, /* should not match */ + {.port_dst = 1024, .deny = 16}, /* should match 16 */ + {.port_dst = 1020, .allow = 14, .deny = 15}, /* should match 14, 15 */ + + {.port_src = 80, .allow = 17}, /* should match 17 */ + {.port_src = 79, .allow = 18}, /* should match 18 */ + {.port_src = 81, .allow = 18}, /* should match 18 */ + {.port_src = 21}, /* should not match */ + {.port_src = 1024, .deny = 20}, /* should match 20 */ + {.port_src = 1020, .allow = 18, .deny = 19}, /* should match 18, 19 */ + + {.proto = 0x64, .allow = 21}, /* should match 21 */ + {.proto = 0xE4, .allow = 21}, /* should match 21 */ + {.proto = 0xE2}, /* should not match */ + {.proto = 0xD, .allow = 22}, /* should match 22 */ + {.proto = 0x6}, /* should not match */ + {.proto = 0x5, .allow = 22, .deny = 23}, /* should match 22, 23 */ + +/* testing matching multiple rules at once */ + {.vlan = 0x5, .ip_src = IPv4(10,1,1,1), + .allow = 5, .deny = 9}, /* should match 5, 9 */ + {.vlan = 0x5, .ip_src = IPv4(192,168,2,50), + .allow = 8, .deny = 9}, /* should match 8, 9 */ + {.vlan = 0x55, .ip_src = IPv4(192,168,1,49), + .allow = 8}, /* should match 8 */ + {.port_dst = 80, .port_src = 1024, + .allow = 13, .deny = 20}, /* should match 13,20 */ + {.port_dst = 79, .port_src = 1024, + .allow = 14, .deny = 20}, /* should match 14,20 */ + {.proto = 0x5, .ip_dst = IPv4(192,168,2,50), + .allow = 1, .deny = 23}, /* should match 1, 23 */ + + {.proto = 0x5, .ip_dst = IPv4(192,168,1,50), + .allow = 2, .deny = 23}, /* should match 2, 23 */ + {.vlan = 0x64, .domain = 0x5, + .allow = 11, .deny = 12}, /* should match 11, 12 */ + {.proto = 0x5, .port_src = 80, + .allow = 17, .deny = 23}, /* should match 17, 23 */ + {.proto = 0x5, .port_dst = 80, + .allow = 13, .deny = 23}, /* should match 13, 23 */ + {.proto = 0x51, .port_src = 5000}, /* should not match */ + {.ip_src = IPv4(192,168,1,50), + .ip_dst = IPv4(10,0,0,0), + .proto = 0x51, + .port_src = 5000, + .port_dst = 5000}, /* should not match */ + +/* test full packet rules */ + { + .ip_dst = IPv4(1,2,100,200), + .ip_src = IPv4(5,6,7,254), + .proto = 0x5, + .vlan = 0x8100, + .domain = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 24, + .deny = 23 + }, /* should match 23, 24 */ + { + .ip_dst = IPv4(5,6,7,254), + .ip_src = IPv4(1,2,100,200), + .proto = 0x5, + .vlan = 0x8100, + .domain = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 25 + }, /* should match 13, 25 */ + { + .ip_dst = IPv4(1,10,20,30), + .ip_src = IPv4(5,6,7,8), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 26, + .deny = 23 + }, /* should match 23, 26 */ + { + .ip_dst = IPv4(5,6,7,8), + .ip_src = IPv4(1,10,20,30), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 27 + }, /* should match 13, 27 */ + { + .ip_dst = IPv4(2,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 23 + }, /* should match 13, 23 */ + { + .ip_dst = IPv4(1,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x5, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 80, + .allow = 13, + .deny = 23 + }, /* should match 13, 23 */ + + +/* visual separator! */ + { + .ip_dst = IPv4(1,2,100,200), + .ip_src = IPv4(5,6,7,254), + .proto = 0x55, + .vlan = 0x8000, + .domain = 0x6464, + .port_src = 12345, + .port_dst = 8080, + .allow = 10 + }, /* should match 10 */ + { + .ip_dst = IPv4(5,6,7,254), + .ip_src = IPv4(1,2,100,200), + .proto = 0x55, + .vlan = 0x8100, + .domain = 0x6464, + .port_src = 12345, + .port_dst = 180, + .allow = 10 + }, /* should match 10 */ + { + .ip_dst = IPv4(1,10,20,30), + .ip_src = IPv4(5,6,7,8), + .proto = 0x55, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 180, + .allow = 7 + }, /* should match 7 */ + { + .ip_dst = IPv4(5,6,7,8), + .ip_src = IPv4(1,10,20,30), + .proto = 0x55, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 180, + .allow = 7 + }, /* should match 7 */ + { + .ip_dst = IPv4(2,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x55, + .vlan = 0x64, + .port_src = 12345, + .port_dst = 180, + .allow = 7 + }, /* should match 7 */ + { + .ip_dst = IPv4(1,2,3,4), + .ip_src = IPv4(4,6,7,8), + .proto = 0x50, + .vlan = 0x6466, + .port_src = 12345, + .port_dst = 12345, + }, /* should not match */ +}; + +#endif /* TEST_PMAC_ACL_H_ */ diff --git a/app/test/test_pmac_pm.c b/app/test/test_pmac_pm.c new file mode 100644 index 0000000000..cf59c835d1 --- /dev/null +++ b/app/test/test_pmac_pm.c @@ -0,0 +1,1550 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include +#include + +#include + +#include +#include + +#include "test.h" + +#ifdef RTE_LIBRTE_PMAC + +#include + +#include "test_pmac_pm.h" + +struct pm_store_buf { + void * buf; + size_t len; +}; + +struct rte_pm_param good_param = { + .name = "param", + .socket_id = SOCKET_ID_ANY, + .max_pattern_num = 0x20000, + .max_pattern_len = 0x20000, +}; + +/* pattern set. + * this switches between clean (ASCII-only), mixed (those needing conversion + * from ASCII to binary) and P1 (a list of only 1 pattern, for use with P1 + * algorithm) pattern sets. each pattern set is attempted to be tested with all + * algorithms, thus maximizing coverage. + */ +enum pattern_set { + PAT_CLEAN, + PAT_MIXED, + PAT_P1, + PAT_NUM +}; + + +#define LEN 16 +#define BUFSIZE 0x1000000 + +#define OPT_CASE_SENSE 0x1 +#define OPT_OUT_OF_ORDER 0x2 +#define NUM_OPTS 2 + +/* keep track of which algorithms were tested */ +uint8_t tested_algorithms[RTE_PM_SEARCH_NUM]; + +/* pointer to an array with one of the test buffers from test_pmac_pm.h */ +static struct pm_test_buffer * pm_test_buf; +/* length of the list (since we can't use sizeof on a pointer) */ +int pm_test_buf_len = 0; + + +/* store pattern-match buffer */ +static int +pm_store(void *arg, const void *buf, + uint64_t offset, uint64_t size) +{ + struct pm_store_buf * dst = (struct pm_store_buf *) arg; + if (size + offset > dst->len) { + printf("Line %i: Not enough space in PM store buffer!\n", __LINE__); + return -ENOMEM; + } + memcpy((char*) dst->buf + offset, buf, size); + + return (0); +} + +/* load pattern-match buffer */ +static int +pm_load(void *arg, void *buf, + uint64_t offset, uint64_t size) +{ + struct pm_store_buf * src = (struct pm_store_buf *) arg; + if (size + offset > src->len) { + printf("Line %i: Not enough space in PM load buffer!\n", __LINE__); + return -ENOMEM; + } + memcpy(buf, (char*) src->buf + offset, size); + + return (0); +} + +/** + * perform bulk search + * + * Due to the way bulk works, we can only look for <=1 results per buffer + */ +static int +bulk_search(struct rte_pm_ctx * pmx, struct rte_pm_build_opt * bopt) +{ + struct rte_pm_match res[pm_test_buf_len]; + struct rte_pm_inbuf in_buf[pm_test_buf_len]; + + int i, len, tmp; + int num_matches, total_matches; + + if (pm_test_buf_len <= 0) { + printf("Line %i: Error at %s invalid value for " + "pm_test_buf_len: %d\n", + __LINE__, __func__, pm_test_buf_len); + return (-1); + } + + memset(res, 0, sizeof(res)); + memset(in_buf, 0, sizeof(in_buf)); + + /* prepare buffers */ + for (i = 0; i < pm_test_buf_len; i++) { + + /* prepare PM buffer */ + len = strnlen(pm_test_buf[i].string, sizeof(pm_test_buf[i].string)); + + in_buf[i].buf = (const uint8_t*) pm_test_buf[i].string; + in_buf[i].len = len; + } + + num_matches = 0; + + /* get number of total matches we're supposed to get */ + /* we can only get up to 1 results because of bulk search */ + if (bopt->case_sense) { + for (i = 0; i < pm_test_buf_len; i++) + num_matches += pm_test_buf[i].n_matches_with_case_sense > 0; + } + else { + for (i = 0; i < pm_test_buf_len; i++) + num_matches += pm_test_buf[i].n_matches > 0; + } + + /* run bulk search */ + total_matches = rte_pm_search_bulk(pmx, in_buf, res, pm_test_buf_len); + + /* check if we have a different number of total matches */ + if (total_matches != num_matches) { + rte_pm_dump(pmx); + printf("Line %i: Error bulk matching (ret=%i num_matches=%i)!\n", + __LINE__, total_matches, num_matches); + return -1; + } + /* cycle through each result and check first match, if any */ + else { + for (i = 0; i < pm_test_buf_len; i++) { + + /* get supposed number of matches */ + if (bopt->case_sense) + tmp = pm_test_buf[i].n_matches_with_case_sense > 0; + else + tmp = pm_test_buf[i].n_matches > 0; + + /* check if we have a match when we shouldn't (and vice versa) */ + if (((const char *)(uintptr_t)res[i].userdata != + NULL) == (tmp == 0)) { + printf("Line %i: Should have %i matches!\n", __LINE__, tmp); + return -1; + } + + /* skip null results */ + if (tmp == 0) + continue; + + /* compare result string */ + if ((const char*)(uintptr_t)res[i].userdata != + pm_test_buf[i].matched_str[0]) { + rte_pm_dump(pmx); + printf("Line %i: Wrong match at bulk search %i!\n", + __LINE__, i); + printf("Matched: %s\n", + (const char *)(uintptr_t) + res[i].userdata); + printf("Should have matched: %s\n", + pm_test_buf[i].matched_str[0]); + return -1; + } + } + } + return 0; +} + +/** + * perform multiple searches on a split single buffer + */ +static int +split_buffer_search(struct rte_pm_ctx * pmx, struct rte_pm_build_opt * bopt) +{ +/* works with any reasonable segment count */ +#define NUM_SEG 2 + struct rte_pm_match res_seg[NUM_SEG][MAX_MATCH_COUNT]; + struct rte_pm_inbuf in_seg[NUM_SEG]; + struct rte_pm_match * res; + struct rte_pm_state state; + + int len, seg_len, total_len; + int i, j, n_seg; + int cur_match, num_matches, total_matches; + + /* chain matching */ + for (i = 0; i < pm_test_buf_len; i++) { + + memset(res_seg, 0, sizeof(res_seg)); + memset(&state, 0, sizeof(struct rte_pm_state)); + + /* prepare PM buffer */ + len = strnlen(pm_test_buf[i].string, sizeof(pm_test_buf[i].string)); + + total_len = 0; + + /* create segments out of one string */ + for (n_seg = 0; n_seg < NUM_SEG; n_seg++) { + /* if last segment */ + if (n_seg == NUM_SEG - 1) + seg_len = len - total_len; + else + seg_len = len / NUM_SEG; + in_seg[n_seg].len = seg_len; + in_seg[n_seg].buf = + (const uint8_t*) (pm_test_buf[i].string + total_len); + total_len += seg_len; + } + + + /* number of matches we are supposed to find */ + if (bopt->case_sense) + num_matches = pm_test_buf[i].n_matches_with_case_sense; + else + num_matches = pm_test_buf[i].n_matches; + + /* search in segments */ + for (n_seg = 0; n_seg < NUM_SEG; n_seg++) { + /* if first segment */ + if (n_seg == 0) + total_matches = rte_pm_search_chain_start(pmx, &in_seg[n_seg], + res_seg[n_seg], MAX_MATCH_COUNT, &state); + else + total_matches += rte_pm_search_chain_next(pmx, &in_seg[n_seg], + res_seg[n_seg], MAX_MATCH_COUNT - total_matches, + &state); + } + + if (total_matches != num_matches) { + rte_pm_dump(pmx); + printf("Line %i: Error matching %s%s (ret=%i num_matches=%i)!\n", + __LINE__, in_seg[0].buf, in_seg[1].buf, total_matches, + num_matches); + return -1; + } + /* check if match was correct */ + else { + cur_match = 0; + for (j = 0; j < MAX_MATCH_COUNT * NUM_SEG; j++) { + + /* check if we have reached our maximum */ + if (cur_match == num_matches || cur_match == MAX_MATCH_COUNT) + break; + + n_seg = j / MAX_MATCH_COUNT; + + /* get current result pointer */ + res = &res_seg[n_seg][j % MAX_MATCH_COUNT]; + + /* skip uninitialized results */ + if (res->fin == 0) + continue; + + /* compare result string */ + if ((const char*)(uintptr_t)res->userdata != + pm_test_buf[i].matched_str[cur_match]) { + rte_pm_dump(pmx); + printf("Line %i: Wrong match at split buffer search %i!\n", + __LINE__, i); + printf("Matched: %s\n", + (const char *)(uintptr_t) + res->userdata); + printf("Should have matched: %s\n", + pm_test_buf[i].matched_str[cur_match]); + return -1; + } + /* we got ourselves a match! */ + else + cur_match++; + } + } + } + return 0; +} + +/** + * perform multiple searches on a single buffer + */ +static int +single_buffer_search(struct rte_pm_ctx * pmx, struct rte_pm_build_opt * bopt) +{ + struct rte_pm_match res[MAX_MATCH_COUNT]; + struct rte_pm_state state; + struct rte_pm_inbuf in_buf; + + int i, j, len; + int match, num_matches, total_matches; + + /* look at same segment three times */ + for (i = 0; i < pm_test_buf_len; i++) { + + memset(&res, 0, sizeof(res)); + memset(&state, 0, sizeof(struct rte_pm_state)); + + /* prepare PM buffer */ + len = strnlen(pm_test_buf[i].string, sizeof(pm_test_buf[i].string)); + + in_buf.buf = (const uint8_t*) pm_test_buf[i].string; + in_buf.len = len; + + /* number of matches we are supposed to find */ + if (bopt->case_sense) + num_matches = pm_test_buf[i].n_matches_with_case_sense; + else + num_matches = pm_test_buf[i].n_matches; + + /* run through a buffer multiple times, looking for 1 match */ + for (j = 0; j < MAX_MATCH_COUNT; j++) { + /* start search chain */ + if (j == 0) + total_matches = rte_pm_search_chain_start(pmx, &in_buf, + &res[j], 1, &state); + /* continue search */ + else + total_matches += rte_pm_search_chain(pmx, &res[j], 1, &state); + } + + if (total_matches != num_matches) { + rte_pm_dump(pmx); + printf("Line %i: Error matching %s (ret=%i num_matches=%i)!\n", + __LINE__, in_buf.buf, total_matches, num_matches); + return -1; + } + /* check if match was correct */ + else { + for (match = 0; match < num_matches; match++) { + if ((const char*)(uintptr_t) + res[match].userdata != + pm_test_buf[i].matched_str[match]) { + rte_pm_dump(pmx); + printf("Line %i: Wrong match at single buffer search %i!\n", + __LINE__, i); + printf("Matched: %s\n", + (const char *)(uintptr_t) + res[match].userdata); + printf("Should have matched: %s\n", + pm_test_buf[i].matched_str[match]); + return -1; + } + } + } + } + + return 0; +} + +/* + * perform basic searches + */ +static int +simple_search(struct rte_pm_ctx * pmx, struct rte_pm_build_opt * bopt) +{ + struct rte_pm_match res[MAX_MATCH_COUNT]; + struct rte_pm_state state; + struct rte_pm_inbuf in_buf; + + int i, len, ret; + int match, num_matches; + + /* simple matching */ + for (i = 0; i < pm_test_buf_len; i++) { + + memset(&res, 0, sizeof(res)); + memset(&state, 0, sizeof(struct rte_pm_state)); + + /* prepare PM buffer */ + len = strnlen(pm_test_buf[i].string, sizeof(pm_test_buf[i].string)); + + in_buf.buf = (const uint8_t*) pm_test_buf[i].string; + in_buf.len = len; + + /* number of matches we are supposed to find */ + if (bopt->case_sense) + num_matches = pm_test_buf[i].n_matches_with_case_sense; + else + num_matches = pm_test_buf[i].n_matches; + + ret = rte_pm_search_chain_start(pmx, &in_buf, res, + MAX_MATCH_COUNT, &state); + + if (ret != num_matches) { + rte_pm_dump(pmx); + printf("Line %i: Error matching %s (ret=%i num_matches=%i)!\n", + __LINE__, in_buf.buf, ret, num_matches); + return -1; + } + /* check if match was correct */ + else { + for (match = 0; match < num_matches; match++) { + if ((const char *)(uintptr_t) + res[match].userdata != + pm_test_buf[i].matched_str[match]) { + rte_pm_dump(pmx); + printf("Line %i: Wrong match at simple search %i!\n", + __LINE__, i); + printf("Matched: %s\n", + (const char *)(uintptr_t) + res[match].userdata); + printf("Should have matched: %s\n", + pm_test_buf[i].matched_str[match]); + return -1; + } + } + } + } + + return 0; +} + +/* + * build PM context and call search function + */ +static int +build_and_search(struct rte_pm_ctx * pmx, + struct rte_pm_search_avail * avail, + struct rte_pm_build_opt * bopt, enum pattern_set p_set) +{ + struct rte_pm_param param; + struct rte_pm_ctx * pmx2; + struct pm_store_buf buffer; + enum rte_pm_search search_type; + int ret; + + /* allocate load/store buffer */ + if ((buffer.buf = malloc(BUFSIZE)) == NULL) { + printf("%s at line %i: failed to allocate load/store buffer!\n", + __func__, __LINE__); + return (-1); + } + buffer.len = BUFSIZE; + + /* prepare data for second context */ + memcpy(¶m, &good_param, sizeof(param)); + param.name = "pmx2"; + + /* cycle through all search algorithms */ + for (search_type = RTE_PM_SEARCH_UNDEF; search_type < RTE_PM_SEARCH_NUM; + search_type++) { + + /* skip unavailable search types, but include RTE_PM_SEARCH_UNDEF + * as it should work */ + if (search_type == RTE_PM_SEARCH_UNDEF || + RTE_PM_GET_BIT(avail->avail, search_type) > 0) { + + /* make a note that we tested this algorithm */ + tested_algorithms[search_type] = 1; + + /* build pm */ + bopt->search_type = search_type; + + ret = rte_pm_build(pmx, bopt); + if (ret == -ENOTSUP) { + printf("Line %i: Algorightm %s not supported.\n", + __LINE__, rte_pm_search_names[search_type]); + continue; + } + else if (ret != 0) { + printf("Line %i: PM build for algorithm %s failed! " + "Return code: %i\n", + __LINE__, rte_pm_search_names[search_type], ret); + goto err; + } + + /* select which buffer list to process */ + switch (p_set) + { + case PAT_CLEAN: + pm_test_buf = clean_buffers; + pm_test_buf_len = DIM(clean_buffers); + break; + case PAT_MIXED: + pm_test_buf = mixed_buffers; + pm_test_buf_len = DIM(mixed_buffers); + break; + case PAT_P1: + pm_test_buf = P1_buffers; + pm_test_buf_len = DIM(P1_buffers); + break; + default: + goto err; + } + + /* do searches */ + if (simple_search(pmx, bopt) < 0) + goto err; + if (single_buffer_search(pmx, bopt) < 0) + goto err; + if (split_buffer_search(pmx, bopt) < 0) + goto err; + if (bulk_search(pmx, bopt) < 0) + goto err; + + /* create second context and load it with data from pmx */ + pmx2 = rte_pm_create(¶m); + if (pmx2 == NULL) { + printf("Line %i: Creating second context failed!\n", __LINE__); + goto err; + } + + /* clear load/store buffer, store pmx data and load into pmx2 */ + memset(buffer.buf, 0, BUFSIZE); + + ret = rte_pm_store(pmx, pm_store, &buffer); + if (ret != 0) { + printf("Line %i: PM store failed!\n", __LINE__); + goto err_pmx2; + } + + ret = rte_pm_load(pmx2, pm_load, &buffer); + if (ret != 0) { + printf("Line %i: PM load failed!\n", __LINE__); + goto err_pmx2; + } + + /* do searches for pmx2 */ + if (simple_search(pmx2, bopt) < 0) + goto err_pmx2; + if (single_buffer_search(pmx2, bopt) < 0) + goto err_pmx2; + if (split_buffer_search(pmx2, bopt) < 0) + goto err_pmx2; + if (bulk_search(pmx2, bopt) < 0) + goto err_pmx2; + + /* free second context */ + rte_pm_free(pmx2); + } + } + + /* free load/store buffer */ + free(buffer.buf); + + return 0; +err_pmx2: + rte_pm_free(pmx2); +err: + free(buffer.buf); + return -1; +} + +/* add patterns to PM context */ +static int +add_patterns(struct rte_pm_ctx * pmx, enum pattern_set p_set) +{ + int i, ret; + struct rte_pm_pattern * pat = NULL; + + /* only needed when converting strings */ + uint8_t tmp_str[DIM(mixed_patterns)][MAX_PATTERN_LEN]; + + switch (p_set) + { + case PAT_CLEAN: + { + /* allocate space for patterns */ + pat = malloc(sizeof(struct rte_pm_pattern) * DIM(clean_patterns)); + + if (!pat) { + printf("Line %i: Allocating space for patterns failed!\n", + __LINE__); + return -1; + } + + for (i = 0; i < (int) DIM(clean_patterns); i++) { + pat[i].pattern = (const uint8_t *) clean_patterns[i]; + pat[i].userdata = (uintptr_t) clean_patterns[i]; + pat[i].len = strnlen(clean_patterns[i], + sizeof(clean_patterns[i])); + } + + ret = rte_pm_add_patterns(pmx, pat, DIM(clean_patterns)); + + if (ret != 0) { + printf("Line %i: PM pattern add failed! Return code: %i\n", + __LINE__, ret); + free(pat); + return -1; + } + free(pat); + break; + } + case PAT_MIXED: + { + pat = NULL; + + pat = malloc(sizeof(struct rte_pm_pattern) * DIM(mixed_patterns)); + memset(tmp_str, 0, sizeof(tmp_str)); + + if (!pat) { + printf("Line %i: Allocating space for patterns failed!\n", + __LINE__); + if (pat) + free(pat); + return -1; + } + + for (i = 0; i < (int) DIM(mixed_patterns); i++) { + + ret = rte_pm_convert_pattern(mixed_patterns[i], + tmp_str[i], MAX_PATTERN_LEN); + + if (!ret) { + printf("Line %i: Converting pattern failed!\n", __LINE__); + free(pat); + return -1; + } + pat[i].pattern = tmp_str[i]; + /* we assign original string here so that later comparison + * doesn't fail. + */ + pat[i].userdata = (uintptr_t) mixed_patterns[i]; + pat[i].len = strnlen((const char*) tmp_str[i], MAX_PATTERN_LEN); + } + + ret = rte_pm_add_patterns(pmx, pat, DIM(mixed_patterns)); + + if (ret != 0) { + printf("Line %i: PM pattern add failed! Return code: %i\n", + __LINE__, ret); + free(pat); + return -1; + } + free(pat); + break; + } + case PAT_P1: + { + pat = malloc(sizeof(struct rte_pm_pattern) * DIM(P1_patterns)); + + if (!pat) { + printf("Line %i: Allocating space for patterns failed!\n", + __LINE__); + return -1; + } + + for (i = 0; i < (int) DIM(P1_patterns); i++) { + pat[i].pattern = (const uint8_t *) P1_patterns[i]; + pat[i].userdata = (uintptr_t) P1_patterns[i]; + pat[i].len = strnlen(P1_patterns[i], sizeof(P1_patterns[i])); + } + + ret = rte_pm_add_patterns(pmx, pat, 1); + + if (ret != 0) { + printf("Line %i: PM pattern add failed! Return code: %i\n", + __LINE__, ret); + free(pat); + return -1; + } + free(pat); + break; + } + default: + printf("Line %i: Unknown pattern type\n", __LINE__); + return -1; + } + return 0; +} + +/* + * this function is in no way a replacement for + * proper in-depth unit tests (those are available + * as a separate application). this is just a quick + * sanity test to check basic functionality. + */ +static int +test_search_patterns(void) +{ + struct rte_pm_ctx * pmx; + struct rte_pm_search_avail avail; + struct rte_pm_build_opt bopt; + int i, ret; + + /* bitmask to configure build options */ + uint8_t options_bm = 0; + /* pattern set to use for tests */ + enum pattern_set p_set; + + /* reset the tested algorithms array */ + memset(tested_algorithms, 0, sizeof(tested_algorithms)); + + /* two possible options: case sense and OOO */ + for (options_bm = 0; options_bm < (1 << NUM_OPTS); options_bm++) { + + bopt.search_type = RTE_PM_SEARCH_UNDEF; + + /* configure options according to bitmask */ + bopt.case_sense = !!(options_bm & OPT_CASE_SENSE); + bopt.out_of_order = !!(options_bm & OPT_OUT_OF_ORDER); + + for (p_set = PAT_CLEAN; p_set < PAT_NUM; p_set++) { + + /* create new PM context */ + pmx = rte_pm_create(&good_param); + if (pmx == NULL) { + printf("Line %i: Failed to create PM context!\n", __LINE__); + return -1; + } + + /* add patterns to context */ + ret = add_patterns(pmx, p_set); + if (ret < 0) + goto err; + + ret = rte_pm_analyze(pmx, &bopt, &avail); + if (ret != 0) { + printf("Line %i: PM analyze failed! Return code: %i\n", + __LINE__, ret); + goto err; + } + + ret = build_and_search(pmx, &avail, &bopt, p_set); + if (ret < 0) + goto err; + + rte_pm_free(pmx); + } + } + + ret = 0; + + /* + * check if all algorithms were attempted + */ + + /* skip nil algorithm */ + for (i = 1; i < RTE_PM_SEARCH_NUM; i++) { + if (tested_algorithms[i] == 0) { + printf("Line %i: Algorithm %s was not tested!\n", + __LINE__, rte_pm_search_names[i]); + ret = -1; + } + } + + return ret; +err: + rte_pm_free(pmx); + return -1; +} + + +/* + * Test creating and finding PM contexts, and adding patterns + */ +static int +test_create_find_add(void) +{ + struct rte_pm_param param; + struct rte_pm_ctx * pmx, *pmx2, *tmp; + struct rte_pm_pattern pat[LEN]; + const char * pmx_name = "pmx"; + const char * pmx2_name = "pmx2"; + int i, ret; + + /* create two contexts */ + memcpy(¶m, &good_param, sizeof(param)); + param.max_pattern_len = 8; + param.max_pattern_num = 2; + + param.name = pmx_name; + pmx = rte_pm_create(¶m); + if (pmx == NULL) { + printf("Line %i: Error creating %s!\n", __LINE__, pmx_name); + return -1; + } + + param.name = pmx2_name; + pmx2 = rte_pm_create(¶m); + if (pmx2 == NULL || pmx2 == pmx) { + printf("Line %i: Error creating %s!\n", __LINE__, pmx2_name); + rte_pm_free(pmx); + return -1; + } + + /* try to create third one, with an existing name */ + param.name = pmx_name; + tmp = rte_pm_create(¶m); + if (tmp != pmx) { + printf("Line %i: Creating context with existing name test failed!\n", + __LINE__); + if (tmp) + rte_pm_free(tmp); + goto err; + } + + param.name = pmx2_name; + tmp = rte_pm_create(¶m); + if (tmp != pmx2) { + printf("Line %i: Creating context with existing name test 2 failed!\n", + __LINE__); + if (tmp) + rte_pm_free(tmp); + goto err; + } + + /* try to find existing PM contexts */ + tmp = rte_pm_find_existing(pmx_name); + if (tmp != pmx) { + printf("Line %i: Finding %s failed!\n", __LINE__, pmx_name); + if (tmp) + rte_pm_free(tmp); + goto err; + } + + tmp = rte_pm_find_existing(pmx2_name); + if (tmp != pmx2) { + printf("Line %i: Finding %s failed!\n", __LINE__, pmx2_name); + if (tmp) + rte_pm_free(tmp); + goto err; + } + + /* try to find non-existing context */ + tmp = rte_pm_find_existing("invalid"); + if (tmp != NULL) { + printf("Line %i: Non-existent PM context found!\n", __LINE__); + goto err; + } + + rte_pm_free(pmx); + + + /* create valid (but severely limited) pmx */ + memcpy(¶m, &good_param, sizeof(param)); + param.max_pattern_num = LEN; + + pmx = rte_pm_create(¶m); + if (pmx == NULL) { + printf("Line %i: Error creating %s!\n", __LINE__, param.name); + goto err; + } + + /* create dummy patterns */ + for (i = 0; i < LEN; i++) { + pat[i].len = 4; + pat[i].userdata = 0; + pat[i].pattern = (const uint8_t*)"1234"; + } + + /* try filling up the context */ + ret = rte_pm_add_patterns(pmx, pat, LEN); + if (ret != 0) { + printf("Line %i: Adding %i patterns to PM context failed!\n", + __LINE__, LEN); + goto err; + } + + /* try adding to a (supposedly) full context */ + ret = rte_pm_add_patterns(pmx, pat, 1); + if (ret == 0) { + printf("Line %i: Adding patterns to full PM context " + "should have failed!\n", __LINE__); + goto err; + } + + rte_pm_free(pmx); + + /* create another valid (but severely limited) pmx */ + memcpy(¶m, &good_param, sizeof(param)); + param.max_pattern_len = LEN * 4; + + pmx = rte_pm_create(¶m); + if (pmx == NULL) { + printf("Line %i: Error creating %s!\n", __LINE__, param.name); + goto err; + } + + /* create dummy patterns */ + for (i = 0; i < LEN; i++) { + pat[i].len = 4; + pat[i].userdata = 0; + pat[i].pattern = (const uint8_t*)"1234"; + } + + /* try filling up the context */ + ret = rte_pm_add_patterns(pmx, pat, LEN); + if (ret != 0) { + printf("Line %i: Adding %i patterns to PM context failed!\n", + __LINE__, LEN); + goto err; + } + + /* try adding to a (supposedly) full context */ + ret = rte_pm_add_patterns(pmx, pat, 1); + if (ret == 0) { + printf("Line %i: Adding patterns to full PM context " + "should have failed!\n", __LINE__); + goto err; + } + + rte_pm_free(pmx); + rte_pm_free(pmx2); + + return 0; +err: + rte_pm_free(pmx); + rte_pm_free(pmx2); + return -1; +} + +/* + * test serialization functions. + * tests include: + * - passing invalid parameters to function + * - trying to load invalid pm store + * - save buffer, load buffer, save another, and compare them + * - try to load/save with a too small buffer (pm_store/pm_load should fail) + */ +static int +test_serialize(void) +{ + struct rte_pm_ctx * pmx, * pmx2; + struct rte_pm_build_opt build_opt; + struct rte_pm_pattern pat[LEN]; + int i, res; + struct pm_store_buf buffer, buffer2; + + memset(&buffer, 0, sizeof (buffer)); + memset(&buffer2, 0, sizeof (buffer2)); + + /* allocate two load/store buffers */ + if ((buffer.buf = malloc(BUFSIZE)) == NULL || + (buffer2.buf = malloc(BUFSIZE)) == NULL) { + printf("Line %i: Creating load/store buffers failed!\n", + __LINE__); + free(buffer2.buf); + free(buffer.buf); + return (-1); + } + + buffer.len = BUFSIZE; + memset(buffer.buf, 0, BUFSIZE); + + buffer2.len = BUFSIZE; + memset(buffer2.buf, 0, BUFSIZE); + + /* create a context */ + pmx = rte_pm_create(&good_param); + if (!pmx) { + printf("Line %i: Creating pmx failed!\n", __LINE__); + goto err; + } + + /* create dummy patterns */ + for (i = 0; i < LEN; i++) { + pat[i].len = 4; + pat[i].userdata = 0; + pat[i].pattern = (const uint8_t*)"1234"; + } + + /* fill context with patterns */ + res = rte_pm_add_patterns(pmx, pat, LEN); + if (res != 0) { + printf("Line %i: Adding patterns to PM context failed!\n", __LINE__); + goto err; + } + + build_opt.search_type = RTE_PM_SEARCH_UNDEF; + + /* build the patterns */ + res = rte_pm_build(pmx, &build_opt); + if (res != 0) { + printf("Line %i: Building PM context failed!\n", __LINE__); + goto err; + } + + /** + * test serialize functions + */ + res = rte_pm_store(NULL, pm_store, &buffer); + if (res != -EINVAL) { + printf("Line %i: PM store should have failed!\n", __LINE__); + goto err; + } + + res = rte_pm_store(pmx, NULL, &buffer); + if (res != -EINVAL) { + printf("Line %i: PM store should have failed!\n", __LINE__); + goto err; + } + + res = rte_pm_store(pmx, pm_store, NULL); + if (res != -EINVAL) { + printf("Line %i: PM store should have failed!\n", __LINE__); + goto err; + } + + + res = rte_pm_load(NULL, pm_load, &buffer); + if (res != -EINVAL) { + printf("Line %i: PM load should have failed!\n", __LINE__); + goto err; + } + + res = rte_pm_load(pmx, NULL, &buffer); + if (res != -EINVAL) { + printf("Line %i: PM load should have failed!\n", __LINE__); + goto err; + } + + res = rte_pm_load(pmx, pm_load, NULL); + if (res != -EINVAL) { + printf("Line %i: PM load should have failed!\n", __LINE__); + goto err; + } + + /* since buffer is currently zeroed out, load should complain about + * unsupported format*/ + res = rte_pm_load(pmx, pm_load, &buffer); + if (res != -EINVAL) { + printf("Line %i: PM load should have failed!\n", __LINE__); + goto err; + } + + /* rte_pm_load zeroed out the context, so re-add all patterns, rebuild, + * save the context to buffer and free context + */ + rte_pm_free(pmx); + + /* create a context */ + pmx = rte_pm_create(&good_param); + if (!pmx) { + printf("Line %i: Creating pmx failed!\n", __LINE__); + goto err; + } + + res = rte_pm_add_patterns(pmx, pat, LEN); + if (res != 0) { + printf("Line %i: Adding patterns to PM context failed!\n", __LINE__); + goto err; + } + + res = rte_pm_build(pmx, &build_opt); + if (res != 0) { + printf("Line %i: Building PM context failed!\n", __LINE__); + goto err; + } + + res = rte_pm_store(pmx, pm_store, &buffer); + if (res != 0) { + printf("Line %i: PM store failed!\n", __LINE__); + goto err; + } + + rte_pm_free(pmx); + pmx = NULL; + + + + /* create pmx2 */ + pmx2 = rte_pm_create(&good_param); + if (!pmx2) { + printf("Line %i: Creating pmx2 failed!\n", __LINE__); + goto err; + } + + /* load buffer into pmx2 */ + res = rte_pm_load(pmx2, pm_load, &buffer); + if (res != 0) { + printf("Line %i: PM load failed!\n", __LINE__); + goto err_pmx2; + } + + /* save pmx2 into another buffer */ + res = rte_pm_store(pmx2, pm_store, &buffer2); + if (res != 0) { + printf("Line %i: PM store failed!\n", __LINE__); + goto err_pmx2; + } + + /* compare two buffers */ + if (memcmp(buffer.buf, buffer2.buf, BUFSIZE) != 0) { + printf("Line %i: Buffers are different!\n", __LINE__); + goto err_pmx2; + } + + /* try and save pmx2 into a too small buffer */ + buffer2.len = 4; + res = rte_pm_store(pmx2, pm_store, &buffer2); + if (res != -ENOMEM) { + printf("Line %i: PM store should have failed!\n", __LINE__); + goto err_pmx2; + } + + /* try and load from a too small buffer */ + res = rte_pm_load(pmx2, pm_load, &buffer2); + if (res != -ENOMEM) { + printf("Line %i: PM load should have failed!\n", __LINE__); + goto err_pmx2; + } + + /* free everything */ + rte_pm_free(pmx2); + + free(buffer2.buf); + free(buffer.buf); + + return 0; +err_pmx2: + rte_pm_free(pmx2); +err: + rte_pm_free(pmx); + free(buffer2.buf); + free(buffer.buf); + return -1; +} + +/* + * test functions by passing invalid or + * non-workable parameters. + * + * we do NOT test pattern search functions here + * because those are performance-critical and + * thus don't do any parameter checking. + */ +static int +test_invalid_parameters(void) +{ + struct rte_pm_param param; + struct rte_pm_ctx * pmx; + enum rte_pm_search search_result; + int res = 0; + /* needed for rte_pm_convert_pattern */ + char in_buf[LEN]; + uint8_t out_buf[LEN]; + /* needed for rte_pm_add_patterns */ + struct rte_pm_pattern pat; + /* needed for rte_pm_analyze */ + struct rte_pm_search_avail build_res[LEN]; + /* needed for rte_pm_build */ + struct rte_pm_build_opt build_opt; + + + /** + * rte_pm_create() + */ + + /* NULL param */ + pmx = rte_pm_create(NULL); + if (pmx != NULL) { + printf("Line %i: PM context creation with NULL param " + "should have failed!\n", __LINE__); + rte_pm_free(pmx); + return -1; + } + + /* zero pattern len */ + memcpy(¶m, &good_param, sizeof(param)); + param.max_pattern_len = 0; + + pmx = rte_pm_create(¶m); + if (pmx == NULL) { + printf("Line %i: PM context creation with zero pattern len failed!\n", + __LINE__); + return -1; + } + else + rte_pm_free(pmx); + + /* zero pattern num */ + memcpy(¶m, &good_param, sizeof(param)); + param.max_pattern_num = 0; + + pmx = rte_pm_create(¶m); + if (pmx == NULL) { + printf("Line %i: PM context creation with zero pattern num failed!\n", + __LINE__); + return -1; + } + else + rte_pm_free(pmx); + + /* invalid NUMA node */ + memcpy(¶m, &good_param, sizeof(param)); + param.socket_id = RTE_MAX_NUMA_NODES + 1; + + pmx = rte_pm_create(¶m); + if (pmx != NULL) { + printf("Line %i: PM context creation with invalid NUMA " + "should have failed!\n", __LINE__); + rte_pm_free(pmx); + return -1; + } + + /* NULL name */ + memcpy(¶m, &good_param, sizeof(param)); + param.name = NULL; + + pmx = rte_pm_create(¶m); + if (pmx != NULL) { + printf("Line %i: PM context creation with NULL name " + "should have failed!\n", __LINE__); + rte_pm_free(pmx); + return -1; + } + + /** + * rte_pm_search_type_by_name() + */ + + /* invalid algorithm names */ + search_result = rte_pm_search_type_by_name("invalid"); + if (search_result != RTE_PM_SEARCH_UNDEF) { + printf("Line %i: Found invalid PM algorithm!\n", __LINE__); + } + + search_result = rte_pm_search_type_by_name(NULL); + if (search_result != RTE_PM_SEARCH_UNDEF) { + printf("Line %i: Found NULL PM algorithm!\n", __LINE__); + } + + /** + * rte_pm_convert_pattern() + */ + + /* null in buffer */ + res = rte_pm_convert_pattern(NULL, out_buf, sizeof(out_buf)); + if (res != (-EINVAL)) { + printf("Line %i: Converting a NULL input pattern " + "should have failed!\n", __LINE__); + return -1; + } + + /* null out buffer */ + res = rte_pm_convert_pattern(in_buf, NULL, sizeof(out_buf)); + if (res != (-EINVAL)) { + printf("Line %i: Converting to NULL output buffer " + "should have failed!\n", __LINE__); + return -1; + } + + /* zero length (should throw -ENOMEM) */ + res = rte_pm_convert_pattern(in_buf, out_buf, 0); + if (res != -(ENOMEM)) { + printf("Line %i: Converting to a 0-length output buffer " + "should have failed!\n", __LINE__); + return -1; + } + + /* wrong binary value */ + res = rte_pm_convert_pattern("|1", out_buf, sizeof(out_buf)); + if (res != (-EINVAL)) { + printf("Line %i: Converting malformed binary " + "should have failed!\n", __LINE__); + return -1; + } + + /* wrong binary value */ + res = rte_pm_convert_pattern("|P1|", out_buf, sizeof(out_buf)); + if (res != (-EINVAL)) { + printf("Line %i: Converting malformed binary " + "should have failed!\n", __LINE__); + return -1; + } + + /* wrong binary value */ + res = rte_pm_convert_pattern("|FFF|", out_buf, sizeof(out_buf)); + if (res != (-EINVAL)) { + printf("Line %i: Converting malformed binary " + "should have failed!\n", __LINE__); + return -1; + } + + /** + * rte_pm_add_patterns() + */ + /* create valid pmx since we'll need it for tests */ + memcpy(¶m, &good_param, sizeof(param)); + + param.max_pattern_len = 2; + + pmx = rte_pm_create(¶m); + if (!pmx) { + printf("Line %i: Creating pmx failed!\n", __LINE__); + return -1; + } + + /* NULL pmx */ + res = rte_pm_add_patterns(NULL, &pat, LEN); + if (res != -EINVAL) { + printf("Line %i: Adding patterns to NULL PM context " + "should have failed!\n", __LINE__); + return -1; + } + + /* NULL pat */ + res = rte_pm_add_patterns(pmx, NULL, LEN); + if (res != -EINVAL) { + printf("Line %i: Adding patterns to NULL pattern " + "should have failed!\n", __LINE__); + return -1; + } + + pat.len = 4; + + /* zero len (should succeed) */ + res = rte_pm_add_patterns(pmx, &pat, 0); + if (res != 0) { + printf("Line %i: Adding 0 patterns to PM context failed!\n", __LINE__); + rte_pm_free(pmx); + return -1; + } + + /** + * rte_pm_analyze() + */ + + /* NULL context */ + res = rte_pm_analyze(NULL, &build_opt, build_res); + if (res != -EINVAL) { + printf("Line %i: PM analyze on NULL pmx " + "should have failed!\n", __LINE__); + rte_pm_free(pmx); + return -1; + } + + /* NULL opt */ + res = rte_pm_analyze(pmx, NULL, build_res); + if (res != -EINVAL) { + printf("Line %i: PM analyze on NULL opt " + "should have failed!\n", __LINE__); + rte_pm_free(pmx); + return -1; + } + + /* NULL res */ + res = rte_pm_analyze(pmx, &build_opt, NULL); + if (res != -EINVAL) { + printf("Line %i: PM analyze on NULL res should have failed!\n", + __LINE__); + rte_pm_free(pmx); + return -1; + } + + /** + * rte_pm_build() + */ + + /* NULL context */ + res = rte_pm_build(NULL, &build_opt); + if (res != -EINVAL) { + printf("Line %i: PM build on NULL pmx should have failed!\n", + __LINE__); + rte_pm_free(pmx); + return -1; + } + + /* NULL opt */ + res = rte_pm_build(pmx, NULL); + if (res != -EINVAL) { + printf("Line %i: PM build on NULL opt should have failed!\n", __LINE__); + rte_pm_free(pmx); + return -1; + } + + /* build with unsuitable algorithm */ + build_opt.case_sense = 0; + build_opt.out_of_order = 0; + /* MB expects out_of_order */ + build_opt.search_type = RTE_PM_SEARCH_AC2_L1x4_MB; + + res = rte_pm_build(pmx, &build_opt); + if (res != -EINVAL) { + printf("Line %i: PM build on NULL opt should have failed! %i\n", + __LINE__, res); + rte_pm_free(pmx); + return -1; + } + + /* free context */ + rte_pm_free(pmx); + + /** + * make sure void functions don't crash with NULL parameters + */ + + rte_pm_free(NULL); + + rte_pm_dump(NULL); + + return 0; +} + + +/** + * Various tests that don't test much but improve coverage + */ +static int +test_misc(void) +{ + struct rte_pm_build_opt build_opt; + struct rte_pm_pattern pat; + struct rte_pm_ctx * pmx; + enum rte_pm_search search_result; + char buf[MAX_PATTERN_LEN]; + int ret; + + pmx = NULL; + + /* search for existing PM algorithm */ + search_result = rte_pm_search_type_by_name("AC2_L1x4"); + if (search_result != RTE_PM_SEARCH_AC2_L1x4) { + printf("Line %i: Wrong PM algorithm found!\n", __LINE__); + } + + pmx = rte_pm_create(&good_param); + if (!pmx) { + printf("Line %i: Failed to create PM context!\n", __LINE__); + return -1; + } + + /* convert a pattern and add it to context */ + ret = rte_pm_convert_pattern("|01 02 03 04| readable", (uint8_t*) buf, + sizeof(buf)); + if (ret <= 0) { + rte_pm_free(pmx); + printf("Line %i: Converting binary failed!\n", __LINE__); + return -1; + } + + /* add pattern to context */ + pat.len = (uint32_t) ret; + pat.pattern = (const uint8_t *) buf; + pat.userdata = 0; + + ret = rte_pm_add_patterns(pmx, &pat, 1); + if (ret != 0) { + rte_pm_free(pmx); + printf("Line %i: Adding pattern failed!\n", __LINE__); + return -1; + } + + /* convert another pattern and add it to context */ + ret = rte_pm_convert_pattern("pattern", (uint8_t*) buf, 4); + + if (ret <= 0) { + rte_pm_free(pmx); + printf("Line %i: Converting pattern failed!\n", __LINE__); + return -1; + } + + /* add pattern to context */ + pat.len = (uint32_t) ret; + pat.pattern = (const uint8_t *) buf; + pat.userdata = 0; + + ret = rte_pm_add_patterns(pmx, &pat, 1); + if (ret != 0) { + rte_pm_free(pmx); + printf("Line %i: Adding pattern failed!\n", __LINE__); + return -1; + } + + build_opt.case_sense = 0; + build_opt.out_of_order = 0; + build_opt.search_type = RTE_PM_SEARCH_AC2_L1x4; + + ret = rte_pm_build(pmx, &build_opt); + if (ret != 0) { + rte_pm_free(pmx); + printf("Line %i: Building PM failed!\n", __LINE__); + return -1; + } + + /* dump context with patterns - useful for coverage */ + rte_pm_list_dump(); + + rte_pm_dump(pmx); + + rte_pm_free(pmx); + + return 0; +} + +int +test_pmac_pm(void) +{ + if (test_invalid_parameters() < 0) + return -1; + if (test_serialize() < 0) + return -1; + if (test_create_find_add() < 0) + return -1; + if (test_search_patterns() < 0) + return -1; + if (test_misc() < 0) + return -1; + return 0; +} + +#else /* RTE_LIBRTE_PMAC=n */ + +int +test_pmac_pm(void) +{ + printf("This binary was not compiled with PMAC support!\n"); + return 0; +} + +#endif /* RTE_LIBRTE_PMAC */ diff --git a/app/test/test_pmac_pm.h b/app/test/test_pmac_pm.h new file mode 100644 index 0000000000..85c6a75932 --- /dev/null +++ b/app/test/test_pmac_pm.h @@ -0,0 +1,230 @@ +/*- + * BSD LICENSE + * + * Copyright(c) 2010-2013 Intel Corporation. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Intel Corporation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef TEST_PMAC_PM_H_ +#define TEST_PMAC_PM_H_ + +/** + * PATTERNS + */ + +/* + * clean ASCII patterns + */ +#define MAX_PATTERN_LEN 256 +const char clean_patterns[][MAX_PATTERN_LEN] = { + "Command completed", + "Bad command or filename", + "1 file(s) copied", + "Invalid URL", + "Index of /cgi-bin/", + "HTTP/1.1 403", + "subject=FrEaK+SERVER", + "friend_nickname=", + "/scripts/WWPMsg.dll", + "body=JJ+BackDoor+-+v", + + "subject=Insurrection+Page", + "backtrust.com", + "User-Agent:", + "fromemail=y3k", + "www.kornputers.com", + "# Nova CGI Notification Script", + /* test NOT converting to binary */ + "|23|", + /* test adding same pattern twice - should result in two matches */ + "fromemail=y3k", +}; + +/* + * mixed ASCII-binary patterns + */ +const char mixed_patterns[][MAX_PATTERN_LEN] = { + "1 file|28|s|29| copied", + "User-Agent|3A|", + "|23|", /* gives # */ + "|7C 32 33 7C 00|", /* gives |23| */ + /* test converter not converting stuff erroneously */ + "www.kornputers.com", +}; + +/* + * P1 patterns + * (P1 is used when having only one pattern) + */ +const char P1_patterns[][MAX_PATTERN_LEN] = { + "1111aA111111", +}; + + + +/** + * BUFFERS TO LOOK PATTERNS IN + */ +#define MAX_MATCH_COUNT 3 + +struct pm_test_buffer { + /* test string */ + const char string[MAX_PATTERN_LEN]; + /* strings that should be found marching. + * for our test we allow no more than 3 matches. + * the number is completely arbitrary */ + const char * matched_str[MAX_MATCH_COUNT]; + /* number of matches with and without case sensitivity */ + uint8_t n_matches; + uint8_t n_matches_with_case_sense; +}; + +struct pm_test_buffer clean_buffers[] = { + {"abcCommand completedcde", + {clean_patterns[0], NULL, NULL}, + 1, 1}, + {"jsljelkwlefwe|23|igu5o0", + {clean_patterns[16], NULL, NULL}, + 1, 1}, + {"Invalid URLwww.kOrnpUterS.comfRiEnD_niCKname=", + {clean_patterns[3], clean_patterns[14], clean_patterns[7]}, + 3, 1}, + {"HTTP/1.1 404", + {NULL, NULL, NULL}, + 0, 0}, + {"abcfrOmemail=y3kcde", + {clean_patterns[13], clean_patterns[17], NULL}, + 2, 0}, + {"FANOUTsubject=FrEaK+SERVERFANOUT", + {clean_patterns[6], NULL, NULL}, + 1, 1}, + {"Bad command or filenam", + {NULL, NULL, NULL}, + 0, 0}, + {"Bad command or filename", + {clean_patterns[1], NULL, NULL}, + 1, 1}, + {"845hyut8hji51 FILE(S) COPIED934ui45", + {clean_patterns[2], NULL, NULL}, + 1, 0}, + {"HTTP/1.1 403IndEx of /cgi-bin/", + {clean_patterns[5], clean_patterns[4], NULL}, + 2, 1}, + {"mail.php?subject=Mail&body=JJ+BackDoor+-+v&id=2357874", + {clean_patterns[9], NULL, NULL}, + 1, 1}, + {"/var/www/site/scripts/WWPMsg.dll", + {clean_patterns[8], NULL, NULL}, + 1, 1}, + {"backtrust.com/mail.cgi?subject=Insurrection+Page&body=JJ+BackDoor+-+v", + {clean_patterns[11], clean_patterns[10], clean_patterns[9]}, + 3, 3}, + {"User-Agent: Mozilla/6.0 (Windows NT 6.2; WOW64; rv:16.0.1)", + {clean_patterns[12], NULL, NULL}, + 1, 1}, + {"User-agent: Mozilla/6.0 (Windows NT 6.2; WOW64; rv:16.0.1)", + {clean_patterns[12], NULL, NULL}, + 1, 0}, + {"http://www.kornputers.com/index.php", + {clean_patterns[14], NULL, NULL}, + 1, 1}, + {"\r\n# Nova CGI Notification Script", + {clean_patterns[15], NULL, NULL}, + 1, 1}, + {"\r\n# Nova CGI Notification Scrupt", + {NULL, NULL, NULL}, + 0, 0}, + {"User Agent: Mozilla/6.0 (Windows NT 6.2; WOW64; rv:16.0.1)", + {NULL, NULL, NULL}, + 0, 0}, + {"abcfromemail=y3dcde", + {NULL, NULL, NULL}, + 0, 0}, +}; + +struct pm_test_buffer mixed_buffers[] = { + {"jsljelkwlefwe|23|igu5o0", + {mixed_patterns[3], NULL, NULL}, + 1, 1}, + {"User-Agent:", + {mixed_patterns[1], NULL, NULL}, + 1, 1}, + {"User-Agent#", + {mixed_patterns[2], NULL, NULL}, + 1, 1}, + {"User-agEnt:", + {mixed_patterns[1], NULL, NULL}, + 1, 0}, + {"www.kornputers.com", + {mixed_patterns[4], NULL, NULL}, + 1, 1}, + {"1 file(s) copied from www.kornputers.com ", + {mixed_patterns[0], mixed_patterns[4], NULL}, + 2, 2}, + {"www.kornputers.com: 1 File(s) Copied", + {mixed_patterns[4], mixed_patterns[0], NULL}, + 2, 1}, + {"1 file(s) copied", + {mixed_patterns[0], NULL, NULL}, + 1, 1}, + {"1 file(s) copie", + {NULL, NULL, NULL}, + 0, 0}, + {"1 file(s) copieD", + {mixed_patterns[0], NULL, NULL}, + 1, 0}, + {"iwrhf34890yuhh *Y89#9ireirgf", + {mixed_patterns[2], NULL, NULL}, + 1, 1}, +}; + +struct pm_test_buffer P1_buffers[] = { + {"1111aA111111", + {P1_patterns[0], NULL, NULL}, + 1, 1}, + {"1111Aa111111", + {P1_patterns[0], NULL, NULL}, + 1, 0}, + {"1111aA11111", + {NULL, NULL, NULL}, + 0, 0}, + {"1111aB11111", + {NULL, NULL, NULL}, + 0, 0}, + {"1111aA11112", + {NULL, NULL, NULL}, + 0, 0}, + {"1111aA1111111111aA111111", + {P1_patterns[0], P1_patterns[0], NULL}, + 2, 2}, +}; + + +#endif /* TEST_PMAC_PM_H_ */ diff --git a/lib/Makefile b/lib/Makefile index 06da89e51f..8c37c1ebb0 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -46,6 +46,7 @@ DIRS-$(CONFIG_RTE_LIBRTE_IXGBE_PMD) += librte_pmd_ixgbe DIRS-$(CONFIG_RTE_LIBRTE_HASH) += librte_hash DIRS-$(CONFIG_RTE_LIBRTE_LPM) += librte_lpm DIRS-$(CONFIG_RTE_LIBRTE_NET) += librte_net +DIRS-$(CONFIG_RTE_LIBRTE_PMAC) += librte_pmac ifeq ($(CONFIG_RTE_EXEC_ENV_LINUXAPP),y) DIRS-$(CONFIG_RTE_LIBRTE_KNI) += librte_kni diff --git a/lib/librte_eal/common/include/rte_log.h b/lib/librte_eal/common/include/rte_log.h index 3b8949333d..fc6c9b8a00 100644 --- a/lib/librte_eal/common/include/rte_log.h +++ b/lib/librte_eal/common/include/rte_log.h @@ -71,6 +71,7 @@ extern struct rte_logs rte_logs; #define RTE_LOGTYPE_HASH 0x00000040 /**< Log related to hash table. */ #define RTE_LOGTYPE_LPM 0x00000080 /**< Log related to LPM. */ #define RTE_LOGTYPE_KNI 0X00000100 /**< Log related to KNI. */ +#define RTE_LOGTYPE_PMAC 0x00000200 /**< Log related to PMAC. */ /* these log types can be used in an application */ #define RTE_LOGTYPE_USER1 0x01000000 /**< User-defined log type 1. */ diff --git a/lib/librte_eal/common/include/rte_tailq_elem.h b/lib/librte_eal/common/include/rte_tailq_elem.h index 8183addebe..a74f41f674 100644 --- a/lib/librte_eal/common/include/rte_tailq_elem.h +++ b/lib/librte_eal/common/include/rte_tailq_elem.h @@ -77,6 +77,10 @@ rte_tailq_elem(RTE_TAILQ_FBK_HASH, "RTE_FBK_HASH") rte_tailq_elem(RTE_TAILQ_LPM, "RTE_LPM") +rte_tailq_elem(RTE_TAILQ_PM, "RTE_PM") + +rte_tailq_elem(RTE_TAILQ_ACL, "RTE_ACL") + rte_tailq_end(RTE_TAILQ_NUM) #undef rte_tailq_elem diff --git a/mk/rte.app.mk b/mk/rte.app.mk index 68ef9e7a49..921f9320ad 100644 --- a/mk/rte.app.mk +++ b/mk/rte.app.mk @@ -93,6 +93,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_LPM),y) LDLIBS += -lrte_lpm endif +ifeq ($(CONFIG_RTE_LIBRTE_PMAC),y) +LDLIBS += -lrte_pmac +endif + LDLIBS += --start-group ifeq ($(CONFIG_RTE_LIBRTE_ETHER),y) -- 2.20.1