This library could be used for pattern matching and ACL.
Code of librte_pmac is not released as Open Source.
Signed-off-by: Intel
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
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)
},
]
},
+{
+ "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
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");
"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 = {
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;
--- /dev/null
+/*-
+ * 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 <string.h>
+#include <errno.h>
+
+#include <cmdline_parse.h>
+
+#include <rte_string_fns.h>
+#include <rte_mbuf.h>
+
+#include "test.h"
+
+#ifdef RTE_LIBRTE_PMAC
+
+#include <rte_byteorder.h>
+#include <rte_ip.h>
+#include <rte_acl.h>
+
+#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 */
--- /dev/null
+/*-
+ * 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_ */
--- /dev/null
+/*-
+ * 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 <string.h>
+#include <errno.h>
+
+#include <cmdline_parse.h>
+
+#include <rte_string_fns.h>
+#include <rte_mbuf.h>
+
+#include "test.h"
+
+#ifdef RTE_LIBRTE_PMAC
+
+#include <rte_pm.h>
+
+#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 */
--- /dev/null
+/*-
+ * 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_ */
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
#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. */
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
LDLIBS += -lrte_lpm
endif
+ifeq ($(CONFIG_RTE_LIBRTE_PMAC),y)
+LDLIBS += -lrte_pmac
+endif
+
LDLIBS += --start-group
ifeq ($(CONFIG_RTE_LIBRTE_ETHER),y)