pmac: integration without lib
authorIntel <intel.com>
Tue, 12 Mar 2013 11:03:00 +0000 (12:03 +0100)
committerThomas Monjalon <thomas.monjalon@6wind.com>
Thu, 25 Jul 2013 14:07:50 +0000 (16:07 +0200)
This library could be used for pattern matching and ACL.
Code of librte_pmac is not released as Open Source.

Signed-off-by: Intel
13 files changed:
app/Makefile
app/test/Makefile
app/test/autotest_data.py
app/test/commands.c
app/test/test.h
app/test/test_pmac_acl.c [new file with mode: 0644]
app/test/test_pmac_acl.h [new file with mode: 0644]
app/test/test_pmac_pm.c [new file with mode: 0644]
app/test/test_pmac_pm.h [new file with mode: 0644]
lib/Makefile
lib/librte_eal/common/include/rte_log.h
lib/librte_eal/common/include/rte_tailq_elem.h
mk/rte.app.mk

index 4af5631..7a019ab 100644 (file)
@@ -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
index 543db4a..0124176 100644 (file)
@@ -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)
index 7a15b35..7c5b964 100644 (file)
@@ -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
index b42ca34..705671c 100644 (file)
@@ -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 = {
index 538c39f..ef62ba0 100644 (file)
@@ -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 (file)
index 0000000..fe7172b
--- /dev/null
@@ -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 <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(&param, &acl_param, sizeof(param));
+       param.max_rule_num = 2;
+
+       param.name = acx_name;
+       acx = rte_acl_create(&param);
+       if (acx == NULL) {
+               printf("Line %i: Error creating %s!\n", __LINE__, acx_name);
+               return -1;
+       }
+
+       param.name = acx2_name;
+       acx2 = rte_acl_create(&param);
+       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(&param);
+       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(&param);
+       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(&param, &acl_param, sizeof(param));
+       param.max_rule_num = LEN;
+
+       acx = rte_acl_create(&param);
+       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(&param, &acl_param, sizeof(param));
+       param.rule_size = 0;
+
+       acx = rte_acl_create(&param);
+       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(&param, &acl_param, sizeof(param));
+       param.max_rule_num = 0;
+
+       acx = rte_acl_create(&param);
+       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(&param, &acl_param, sizeof(param));
+       param.socket_id = RTE_MAX_NUMA_NODES + 1;
+
+       acx = rte_acl_create(&param);
+       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(&param, &acl_param, sizeof(param));
+       param.name = NULL;
+
+       acx = rte_acl_create(&param);
+       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(&param, &acl_param, sizeof(param));
+       acx = rte_acl_create(&param);
+       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(&param);
+       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(&param, &acl_param, sizeof(param));
+       acx = rte_acl_create(&param);
+       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(&param, &acl_param, sizeof(param));
+
+       acx = rte_acl_create(&param);
+       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 (file)
index 0000000..2e9f405
--- /dev/null
@@ -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 (file)
index 0000000..cf59c83
--- /dev/null
@@ -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 <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(&param, &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(&param);
+                       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(&param, &good_param, sizeof(param));
+       param.max_pattern_len = 8;
+       param.max_pattern_num = 2;
+
+       param.name = pmx_name;
+       pmx = rte_pm_create(&param);
+       if (pmx == NULL) {
+               printf("Line %i: Error creating %s!\n", __LINE__, pmx_name);
+               return -1;
+       }
+
+       param.name = pmx2_name;
+       pmx2 = rte_pm_create(&param);
+       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(&param);
+       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(&param);
+       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(&param, &good_param, sizeof(param));
+       param.max_pattern_num = LEN;
+
+       pmx = rte_pm_create(&param);
+       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(&param, &good_param, sizeof(param));
+       param.max_pattern_len = LEN * 4;
+
+       pmx = rte_pm_create(&param);
+       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(&param, &good_param, sizeof(param));
+       param.max_pattern_len = 0;
+
+       pmx = rte_pm_create(&param);
+       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(&param, &good_param, sizeof(param));
+       param.max_pattern_num = 0;
+
+       pmx = rte_pm_create(&param);
+       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(&param, &good_param, sizeof(param));
+       param.socket_id = RTE_MAX_NUMA_NODES + 1;
+
+       pmx = rte_pm_create(&param);
+       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(&param, &good_param, sizeof(param));
+       param.name = NULL;
+
+       pmx = rte_pm_create(&param);
+       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(&param, &good_param, sizeof(param));
+
+       param.max_pattern_len = 2;
+
+       pmx = rte_pm_create(&param);
+       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 (file)
index 0000000..85c6a75
--- /dev/null
@@ -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_ */
index 06da89e..8c37c1e 100644 (file)
@@ -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
index 3b89493..fc6c9b8 100644 (file)
@@ -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. */
index 8183add..a74f41f 100644 (file)
@@ -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
index 68ef9e7..921f932 100644 (file)
@@ -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)