0b6fbe8749
The functions and structures are moved to app/test in order to keep existing unit tests. Some minor changes were done in these functions because of library scope restrictions. An enum is also copied in two other applications to keep existing code. The library version is incremented. Signed-off-by: Thomas Monjalon <thomas.monjalon@6wind.com> Acked-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: Neil Horman <nhorman@tuxdriver.com> Acked-by: Konstantin Ananyev <konstantin.ananyev@intel.com>
1690 lines
42 KiB
C
1690 lines
42 KiB
C
/*-
|
|
* BSD LICENSE
|
|
*
|
|
* Copyright(c) 2010-2014 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 "test.h"
|
|
|
|
#include <rte_string_fns.h>
|
|
#include <rte_mbuf.h>
|
|
#include <rte_byteorder.h>
|
|
#include <rte_ip.h>
|
|
#include <rte_acl.h>
|
|
#include <rte_common.h>
|
|
|
|
#include "test_acl.h"
|
|
|
|
#define BIT_SIZEOF(x) (sizeof(x) * CHAR_BIT)
|
|
|
|
#define LEN RTE_ACL_MAX_CATEGORIES
|
|
|
|
RTE_ACL_RULE_DEF(acl_ipv4vlan_rule, RTE_ACL_IPV4VLAN_NUM_FIELDS);
|
|
|
|
struct rte_acl_param acl_param = {
|
|
.name = "acl_ctx",
|
|
.socket_id = SOCKET_ID_ANY,
|
|
.rule_size = RTE_ACL_IPV4VLAN_RULE_SZ,
|
|
.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,
|
|
};
|
|
|
|
const uint32_t ipv4_7tuple_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),
|
|
};
|
|
|
|
|
|
/* 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);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
acl_ipv4vlan_check_rule(const struct rte_acl_ipv4vlan_rule *rule)
|
|
{
|
|
if (rule->src_port_low > rule->src_port_high ||
|
|
rule->dst_port_low > rule->dst_port_high ||
|
|
rule->src_mask_len > BIT_SIZEOF(rule->src_addr) ||
|
|
rule->dst_mask_len > BIT_SIZEOF(rule->dst_addr))
|
|
return -EINVAL;
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
acl_ipv4vlan_convert_rule(const struct rte_acl_ipv4vlan_rule *ri,
|
|
struct acl_ipv4vlan_rule *ro)
|
|
{
|
|
ro->data = ri->data;
|
|
|
|
ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr;
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low;
|
|
ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low;
|
|
|
|
ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 =
|
|
ri->domain_mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
|
|
ri->src_mask_len;
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 =
|
|
ri->src_port_high;
|
|
ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 =
|
|
ri->dst_port_high;
|
|
}
|
|
|
|
/*
|
|
* Add ipv4vlan rules to an existing ACL context.
|
|
* This function is not multi-thread safe.
|
|
*
|
|
* @param ctx
|
|
* ACL context to add patterns to.
|
|
* @param rules
|
|
* Array of rules to add to the ACL context.
|
|
* Note that all fields in rte_acl_ipv4vlan_rule structures are expected
|
|
* to be in host byte order.
|
|
* @param num
|
|
* Number of elements in the input array of rules.
|
|
* @return
|
|
* - -ENOMEM if there is no space in the ACL context for these rules.
|
|
* - -EINVAL if the parameters are invalid.
|
|
* - Zero if operation completed successfully.
|
|
*/
|
|
static int
|
|
rte_acl_ipv4vlan_add_rules(struct rte_acl_ctx *ctx,
|
|
const struct rte_acl_ipv4vlan_rule *rules,
|
|
uint32_t num)
|
|
{
|
|
int32_t rc;
|
|
uint32_t i;
|
|
struct acl_ipv4vlan_rule rv;
|
|
|
|
if (ctx == NULL || rules == NULL)
|
|
return -EINVAL;
|
|
|
|
/* check input rules. */
|
|
for (i = 0; i != num; i++) {
|
|
rc = acl_ipv4vlan_check_rule(rules + i);
|
|
if (rc != 0) {
|
|
RTE_LOG(ERR, ACL, "%s: rule #%u is invalid\n",
|
|
__func__, i + 1);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/* perform conversion to the internal format and add to the context. */
|
|
for (i = 0, rc = 0; i != num && rc == 0; i++) {
|
|
acl_ipv4vlan_convert_rule(rules + i, &rv);
|
|
rc = rte_acl_add_rules(ctx, (struct rte_acl_rule *)&rv, 1);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
static void
|
|
acl_ipv4vlan_config(struct rte_acl_config *cfg,
|
|
const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
|
|
uint32_t num_categories)
|
|
{
|
|
static const struct rte_acl_field_def
|
|
ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = {
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof(uint8_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_PROTO,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_VLAN,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_VLAN,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof(uint32_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_SRC_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_SRC,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof(uint32_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_DST_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_DST,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_PORTS,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_PORTS,
|
|
},
|
|
};
|
|
|
|
memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs));
|
|
cfg->num_fields = RTE_DIM(ipv4_defs);
|
|
|
|
cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_PROTO];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_VLAN];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_VLAN] +
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_SRC];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_DST];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_PORTS];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_PORTS] +
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size;
|
|
|
|
cfg->num_categories = num_categories;
|
|
}
|
|
|
|
/*
|
|
* Analyze set of ipv4vlan rules and build required internal
|
|
* run-time structures.
|
|
* This function is not multi-thread safe.
|
|
*
|
|
* @param ctx
|
|
* ACL context to build.
|
|
* @param layout
|
|
* Layout of input data to search through.
|
|
* @param num_categories
|
|
* Maximum number of categories to use in that build.
|
|
* @return
|
|
* - -ENOMEM if couldn't allocate enough memory.
|
|
* - -EINVAL if the parameters are invalid.
|
|
* - Negative error code if operation failed.
|
|
* - Zero if operation completed successfully.
|
|
*/
|
|
static int
|
|
rte_acl_ipv4vlan_build(struct rte_acl_ctx *ctx,
|
|
const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
|
|
uint32_t num_categories)
|
|
{
|
|
struct rte_acl_config cfg;
|
|
|
|
if (ctx == NULL || layout == NULL)
|
|
return -EINVAL;
|
|
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
acl_ipv4vlan_config(&cfg, layout, num_categories);
|
|
return rte_acl_build(ctx, &cfg);
|
|
}
|
|
|
|
/*
|
|
* Test scalar and SSE ACL lookup.
|
|
*/
|
|
static int
|
|
test_classify_run(struct rte_acl_ctx *acx)
|
|
{
|
|
int ret, i;
|
|
uint32_t result, count;
|
|
uint32_t results[RTE_DIM(acl_test_data) * RTE_ACL_MAX_CATEGORIES];
|
|
const uint8_t *data[RTE_DIM(acl_test_data)];
|
|
|
|
/* swap all bytes in the data to network order */
|
|
bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 1);
|
|
|
|
/* store pointers to test data */
|
|
for (i = 0; i < (int) RTE_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 <= RTE_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);
|
|
ret = -EINVAL;
|
|
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);
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* make a quick check for scalar */
|
|
ret = rte_acl_classify_alg(acx, data, results,
|
|
RTE_DIM(acl_test_data), RTE_ACL_MAX_CATEGORIES,
|
|
RTE_ACL_CLASSIFY_SCALAR);
|
|
if (ret != 0) {
|
|
printf("Line %i: scalar classify failed!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
/* check if we allow everything we should allow */
|
|
for (i = 0; i < (int) RTE_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);
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
/* check if we deny everything we should deny */
|
|
for (i = 0; i < (int) RTE_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);
|
|
ret = -EINVAL;
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
err:
|
|
/* swap data back to cpu order so that next time tests don't fail */
|
|
bswap_test_data(acl_test_data, RTE_DIM(acl_test_data), 0);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
test_classify_buid(struct rte_acl_ctx *acx,
|
|
const struct rte_acl_ipv4vlan_rule *rules, uint32_t num)
|
|
{
|
|
int ret;
|
|
|
|
/* add rules to the context */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, rules, num);
|
|
if (ret != 0) {
|
|
printf("Line %i: Adding rules to ACL context failed!\n",
|
|
__LINE__);
|
|
return ret;
|
|
}
|
|
|
|
/* try building the context */
|
|
ret = rte_acl_ipv4vlan_build(acx, ipv4_7tuple_layout,
|
|
RTE_ACL_MAX_CATEGORIES);
|
|
if (ret != 0) {
|
|
printf("Line %i: Building ACL context failed!\n", __LINE__);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define TEST_CLASSIFY_ITER 4
|
|
|
|
/*
|
|
* Test scalar and SSE ACL lookup.
|
|
*/
|
|
static int
|
|
test_classify(void)
|
|
{
|
|
struct rte_acl_ctx *acx;
|
|
int i, ret;
|
|
|
|
acx = rte_acl_create(&acl_param);
|
|
if (acx == NULL) {
|
|
printf("Line %i: Error creating ACL context!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
ret = 0;
|
|
for (i = 0; i != TEST_CLASSIFY_ITER; i++) {
|
|
|
|
if ((i & 1) == 0)
|
|
rte_acl_reset(acx);
|
|
else
|
|
rte_acl_reset_rules(acx);
|
|
|
|
ret = test_classify_buid(acx, acl_test_rules,
|
|
RTE_DIM(acl_test_rules));
|
|
if (ret != 0) {
|
|
printf("Line %i, iter: %d: "
|
|
"Adding rules to ACL context failed!\n",
|
|
__LINE__, i);
|
|
break;
|
|
}
|
|
|
|
ret = test_classify_run(acx);
|
|
if (ret != 0) {
|
|
printf("Line %i, iter: %d: %s failed!\n",
|
|
__LINE__, i, __func__);
|
|
break;
|
|
}
|
|
|
|
/* reset rules and make sure that classify still works ok. */
|
|
rte_acl_reset_rules(acx);
|
|
ret = test_classify_run(acx);
|
|
if (ret != 0) {
|
|
printf("Line %i, iter: %d: %s failed!\n",
|
|
__LINE__, i, __func__);
|
|
break;
|
|
}
|
|
}
|
|
|
|
rte_acl_free(acx);
|
|
return ret;
|
|
}
|
|
|
|
static int
|
|
test_build_ports_range(void)
|
|
{
|
|
static const struct rte_acl_ipv4vlan_rule test_rules[] = {
|
|
{
|
|
/* match all packets. */
|
|
.data = {
|
|
.userdata = 1,
|
|
.category_mask = ACL_ALLOW_MASK,
|
|
.priority = 101,
|
|
},
|
|
.src_port_low = 0,
|
|
.src_port_high = UINT16_MAX,
|
|
.dst_port_low = 0,
|
|
.dst_port_high = UINT16_MAX,
|
|
},
|
|
{
|
|
/* match all packets with dst ports [54-65280]. */
|
|
.data = {
|
|
.userdata = 2,
|
|
.category_mask = ACL_ALLOW_MASK,
|
|
.priority = 102,
|
|
},
|
|
.src_port_low = 0,
|
|
.src_port_high = UINT16_MAX,
|
|
.dst_port_low = 54,
|
|
.dst_port_high = 65280,
|
|
},
|
|
{
|
|
/* match all packets with dst ports [0-52]. */
|
|
.data = {
|
|
.userdata = 3,
|
|
.category_mask = ACL_ALLOW_MASK,
|
|
.priority = 103,
|
|
},
|
|
.src_port_low = 0,
|
|
.src_port_high = UINT16_MAX,
|
|
.dst_port_low = 0,
|
|
.dst_port_high = 52,
|
|
},
|
|
{
|
|
/* match all packets with dst ports [53]. */
|
|
.data = {
|
|
.userdata = 4,
|
|
.category_mask = ACL_ALLOW_MASK,
|
|
.priority = 99,
|
|
},
|
|
.src_port_low = 0,
|
|
.src_port_high = UINT16_MAX,
|
|
.dst_port_low = 53,
|
|
.dst_port_high = 53,
|
|
},
|
|
{
|
|
/* match all packets with dst ports [65279-65535]. */
|
|
.data = {
|
|
.userdata = 5,
|
|
.category_mask = ACL_ALLOW_MASK,
|
|
.priority = 98,
|
|
},
|
|
.src_port_low = 0,
|
|
.src_port_high = UINT16_MAX,
|
|
.dst_port_low = 65279,
|
|
.dst_port_high = UINT16_MAX,
|
|
},
|
|
};
|
|
|
|
static struct ipv4_7tuple test_data[] = {
|
|
{
|
|
.proto = 6,
|
|
.ip_src = IPv4(10, 1, 1, 1),
|
|
.ip_dst = IPv4(192, 168, 0, 33),
|
|
.port_dst = 53,
|
|
.allow = 1,
|
|
},
|
|
{
|
|
.proto = 6,
|
|
.ip_src = IPv4(127, 84, 33, 1),
|
|
.ip_dst = IPv4(1, 2, 3, 4),
|
|
.port_dst = 65281,
|
|
.allow = 1,
|
|
},
|
|
};
|
|
|
|
struct rte_acl_ctx *acx;
|
|
int32_t ret, i, j;
|
|
uint32_t results[RTE_DIM(test_data)];
|
|
const uint8_t *data[RTE_DIM(test_data)];
|
|
|
|
acx = rte_acl_create(&acl_param);
|
|
if (acx == NULL) {
|
|
printf("Line %i: Error creating ACL context!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
/* swap all bytes in the data to network order */
|
|
bswap_test_data(test_data, RTE_DIM(test_data), 1);
|
|
|
|
/* store pointers to test data */
|
|
for (i = 0; i != RTE_DIM(test_data); i++)
|
|
data[i] = (uint8_t *)&test_data[i];
|
|
|
|
for (i = 0; i != RTE_DIM(test_rules); i++) {
|
|
rte_acl_reset(acx);
|
|
ret = test_classify_buid(acx, test_rules, i + 1);
|
|
if (ret != 0) {
|
|
printf("Line %i, iter: %d: "
|
|
"Adding rules to ACL context failed!\n",
|
|
__LINE__, i);
|
|
break;
|
|
}
|
|
ret = rte_acl_classify(acx, data, results,
|
|
RTE_DIM(data), 1);
|
|
if (ret != 0) {
|
|
printf("Line %i, iter: %d: classify failed!\n",
|
|
__LINE__, i);
|
|
break;
|
|
}
|
|
|
|
/* check results */
|
|
for (j = 0; j != RTE_DIM(results); j++) {
|
|
if (results[j] != test_data[j].allow) {
|
|
printf("Line %i: Error in allow results at %i "
|
|
"(expected %"PRIu32" got %"PRIu32")!\n",
|
|
__LINE__, j, test_data[j].allow,
|
|
results[j]);
|
|
ret = -EINVAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
bswap_test_data(test_data, RTE_DIM(test_data), 0);
|
|
|
|
rte_acl_free(acx);
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
convert_rule(const struct rte_acl_ipv4vlan_rule *ri,
|
|
struct acl_ipv4vlan_rule *ro)
|
|
{
|
|
ro->data = ri->data;
|
|
|
|
ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].value.u8 = ri->proto;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].value.u16 = ri->vlan;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].value.u16 = ri->domain;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = ri->src_addr;
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = ri->dst_addr;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].value.u16 = ri->src_port_low;
|
|
ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].value.u16 = ri->dst_port_low;
|
|
|
|
ro->field[RTE_ACL_IPV4VLAN_PROTO_FIELD].mask_range.u8 = ri->proto_mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD].mask_range.u16 = ri->vlan_mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD].mask_range.u16 =
|
|
ri->domain_mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
|
|
ri->src_mask_len;
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = ri->dst_mask_len;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD].mask_range.u16 =
|
|
ri->src_port_high;
|
|
ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD].mask_range.u16 =
|
|
ri->dst_port_high;
|
|
}
|
|
|
|
/*
|
|
* Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to
|
|
* RTE_ACL_FIELD_TYPE_BITMASK.
|
|
*/
|
|
static void
|
|
convert_rule_1(const struct rte_acl_ipv4vlan_rule *ri,
|
|
struct acl_ipv4vlan_rule *ro)
|
|
{
|
|
uint32_t v;
|
|
|
|
convert_rule(ri, ro);
|
|
v = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 =
|
|
RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v));
|
|
v = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32;
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 =
|
|
RTE_ACL_MASKLEN_TO_BITMASK(v, sizeof(v));
|
|
}
|
|
|
|
/*
|
|
* Convert IPV4 source and destination from RTE_ACL_FIELD_TYPE_MASK to
|
|
* RTE_ACL_FIELD_TYPE_RANGE.
|
|
*/
|
|
static void
|
|
convert_rule_2(const struct rte_acl_ipv4vlan_rule *ri,
|
|
struct acl_ipv4vlan_rule *ro)
|
|
{
|
|
uint32_t hi, lo, mask;
|
|
|
|
convert_rule(ri, ro);
|
|
|
|
mask = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32;
|
|
mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask));
|
|
lo = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 & mask;
|
|
hi = lo + ~mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].value.u32 = lo;
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD].mask_range.u32 = hi;
|
|
|
|
mask = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32;
|
|
mask = RTE_ACL_MASKLEN_TO_BITMASK(mask, sizeof(mask));
|
|
lo = ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 & mask;
|
|
hi = lo + ~mask;
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].value.u32 = lo;
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD].mask_range.u32 = hi;
|
|
}
|
|
|
|
/*
|
|
* Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule fields.
|
|
*/
|
|
static void
|
|
convert_rule_3(const struct rte_acl_ipv4vlan_rule *ri,
|
|
struct acl_ipv4vlan_rule *ro)
|
|
{
|
|
struct rte_acl_field t1, t2;
|
|
|
|
convert_rule(ri, ro);
|
|
|
|
t1 = ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD];
|
|
t2 = ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD];
|
|
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN1_FIELD] =
|
|
ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD];
|
|
ro->field[RTE_ACL_IPV4VLAN_VLAN2_FIELD] =
|
|
ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD];
|
|
|
|
ro->field[RTE_ACL_IPV4VLAN_SRCP_FIELD] = t1;
|
|
ro->field[RTE_ACL_IPV4VLAN_DSTP_FIELD] = t2;
|
|
}
|
|
|
|
/*
|
|
* Convert rte_acl_ipv4vlan_rule: swap SRC and DST IPv4 address rules.
|
|
*/
|
|
static void
|
|
convert_rule_4(const struct rte_acl_ipv4vlan_rule *ri,
|
|
struct acl_ipv4vlan_rule *ro)
|
|
{
|
|
struct rte_acl_field t;
|
|
|
|
convert_rule(ri, ro);
|
|
|
|
t = ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD];
|
|
ro->field[RTE_ACL_IPV4VLAN_SRC_FIELD] =
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD];
|
|
|
|
ro->field[RTE_ACL_IPV4VLAN_DST_FIELD] = t;
|
|
}
|
|
|
|
static void
|
|
ipv4vlan_config(struct rte_acl_config *cfg,
|
|
const uint32_t layout[RTE_ACL_IPV4VLAN_NUM],
|
|
uint32_t num_categories)
|
|
{
|
|
static const struct rte_acl_field_def
|
|
ipv4_defs[RTE_ACL_IPV4VLAN_NUM_FIELDS] = {
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof(uint8_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_PROTO_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_PROTO,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_VLAN1_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_VLAN,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_BITMASK,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_VLAN2_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_VLAN,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof(uint32_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_SRC_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_SRC,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_MASK,
|
|
.size = sizeof(uint32_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_DST_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_DST,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_SRCP_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_PORTS,
|
|
},
|
|
{
|
|
.type = RTE_ACL_FIELD_TYPE_RANGE,
|
|
.size = sizeof(uint16_t),
|
|
.field_index = RTE_ACL_IPV4VLAN_DSTP_FIELD,
|
|
.input_index = RTE_ACL_IPV4VLAN_PORTS,
|
|
},
|
|
};
|
|
|
|
memcpy(&cfg->defs, ipv4_defs, sizeof(ipv4_defs));
|
|
cfg->num_fields = RTE_DIM(ipv4_defs);
|
|
|
|
cfg->defs[RTE_ACL_IPV4VLAN_PROTO_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_PROTO];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_VLAN];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_VLAN] +
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].size;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_SRC];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_DST];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_PORTS];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset =
|
|
layout[RTE_ACL_IPV4VLAN_PORTS] +
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size;
|
|
|
|
cfg->num_categories = num_categories;
|
|
}
|
|
|
|
static int
|
|
convert_rules(struct rte_acl_ctx *acx,
|
|
void (*convert)(const struct rte_acl_ipv4vlan_rule *,
|
|
struct acl_ipv4vlan_rule *),
|
|
const struct rte_acl_ipv4vlan_rule *rules, uint32_t num)
|
|
{
|
|
int32_t rc;
|
|
uint32_t i;
|
|
struct acl_ipv4vlan_rule r;
|
|
|
|
for (i = 0; i != num; i++) {
|
|
convert(rules + i, &r);
|
|
rc = rte_acl_add_rules(acx, (struct rte_acl_rule *)&r, 1);
|
|
if (rc != 0) {
|
|
printf("Line %i: Adding rule %u to ACL context "
|
|
"failed with error code: %d\n",
|
|
__LINE__, i, rc);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
convert_config(struct rte_acl_config *cfg)
|
|
{
|
|
ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
|
|
}
|
|
|
|
/*
|
|
* Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_BITMASK.
|
|
*/
|
|
static void
|
|
convert_config_1(struct rte_acl_config *cfg)
|
|
{
|
|
ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_BITMASK;
|
|
}
|
|
|
|
/*
|
|
* Convert rte_acl_ipv4vlan_rule to use RTE_ACL_FIELD_TYPE_RANGE.
|
|
*/
|
|
static void
|
|
convert_config_2(struct rte_acl_config *cfg)
|
|
{
|
|
ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = RTE_ACL_FIELD_TYPE_RANGE;
|
|
}
|
|
|
|
/*
|
|
* Convert rte_acl_ipv4vlan_rule: swap VLAN and PORTS rule definitions.
|
|
*/
|
|
static void
|
|
convert_config_3(struct rte_acl_config *cfg)
|
|
{
|
|
struct rte_acl_field_def t1, t2;
|
|
|
|
ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
|
|
|
|
t1 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD];
|
|
t2 = cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD];
|
|
|
|
/* swap VLAN1 and SRCP rule definition. */
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD] =
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].field_index = t1.field_index;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN1_FIELD].input_index = t1.input_index;
|
|
|
|
/* swap VLAN2 and DSTP rule definition. */
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD] =
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].field_index = t2.field_index;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_VLAN2_FIELD].input_index = t2.input_index;
|
|
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].type = t1.type;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].size = t1.size;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRCP_FIELD].offset = t1.offset;
|
|
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].type = t2.type;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].size = t2.size;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DSTP_FIELD].offset = t2.offset;
|
|
}
|
|
|
|
/*
|
|
* Convert rte_acl_ipv4vlan_rule: swap SRC and DST ip address rule definitions.
|
|
*/
|
|
static void
|
|
convert_config_4(struct rte_acl_config *cfg)
|
|
{
|
|
struct rte_acl_field_def t;
|
|
|
|
ipv4vlan_config(cfg, ipv4_7tuple_layout, RTE_ACL_MAX_CATEGORIES);
|
|
|
|
t = cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD];
|
|
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD] =
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD];
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].field_index = t.field_index;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_SRC_FIELD].input_index = t.input_index;
|
|
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].type = t.type;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].size = t.size;
|
|
cfg->defs[RTE_ACL_IPV4VLAN_DST_FIELD].offset = t.offset;
|
|
}
|
|
|
|
|
|
static int
|
|
build_convert_rules(struct rte_acl_ctx *acx,
|
|
void (*config)(struct rte_acl_config *),
|
|
size_t max_size)
|
|
{
|
|
struct rte_acl_config cfg;
|
|
|
|
memset(&cfg, 0, sizeof(cfg));
|
|
config(&cfg);
|
|
cfg.max_size = max_size;
|
|
return rte_acl_build(acx, &cfg);
|
|
}
|
|
|
|
static int
|
|
test_convert_rules(const char *desc,
|
|
void (*config)(struct rte_acl_config *),
|
|
void (*convert)(const struct rte_acl_ipv4vlan_rule *,
|
|
struct acl_ipv4vlan_rule *))
|
|
{
|
|
struct rte_acl_ctx *acx;
|
|
int32_t rc;
|
|
uint32_t i;
|
|
static const size_t mem_sizes[] = {0, -1};
|
|
|
|
printf("running %s(%s)\n", __func__, desc);
|
|
|
|
acx = rte_acl_create(&acl_param);
|
|
if (acx == NULL) {
|
|
printf("Line %i: Error creating ACL context!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
rc = convert_rules(acx, convert, acl_test_rules,
|
|
RTE_DIM(acl_test_rules));
|
|
if (rc != 0)
|
|
printf("Line %i: Error converting ACL rules!\n", __LINE__);
|
|
|
|
for (i = 0; rc == 0 && i != RTE_DIM(mem_sizes); i++) {
|
|
|
|
rc = build_convert_rules(acx, config, mem_sizes[i]);
|
|
if (rc != 0) {
|
|
printf("Line %i: Error @ build_convert_rules(%zu)!\n",
|
|
__LINE__, mem_sizes[i]);
|
|
break;
|
|
}
|
|
|
|
rc = test_classify_run(acx);
|
|
if (rc != 0)
|
|
printf("%s failed at line %i, max_size=%zu\n",
|
|
__func__, __LINE__, mem_sizes[i]);
|
|
}
|
|
|
|
rte_acl_free(acx);
|
|
return rc;
|
|
}
|
|
|
|
static int
|
|
test_convert(void)
|
|
{
|
|
static const struct {
|
|
const char *desc;
|
|
void (*config)(struct rte_acl_config *);
|
|
void (*convert)(const struct rte_acl_ipv4vlan_rule *,
|
|
struct acl_ipv4vlan_rule *);
|
|
} convert_param[] = {
|
|
{
|
|
"acl_ipv4vlan_tuple",
|
|
convert_config,
|
|
convert_rule,
|
|
},
|
|
{
|
|
"acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_BITMASK type "
|
|
"for IPv4",
|
|
convert_config_1,
|
|
convert_rule_1,
|
|
},
|
|
{
|
|
"acl_ipv4vlan_tuple, RTE_ACL_FIELD_TYPE_RANGE type "
|
|
"for IPv4",
|
|
convert_config_2,
|
|
convert_rule_2,
|
|
},
|
|
{
|
|
"acl_ipv4vlan_tuple: swap VLAN and PORTs order",
|
|
convert_config_3,
|
|
convert_rule_3,
|
|
},
|
|
{
|
|
"acl_ipv4vlan_tuple: swap SRC and DST IPv4 order",
|
|
convert_config_4,
|
|
convert_rule_4,
|
|
},
|
|
};
|
|
|
|
uint32_t i;
|
|
int32_t rc;
|
|
|
|
for (i = 0; i != RTE_DIM(convert_param); i++) {
|
|
rc = test_convert_rules(convert_param[i].desc,
|
|
convert_param[i].config,
|
|
convert_param[i].convert);
|
|
if (rc != 0) {
|
|
printf("%s for test-case: %s failed, error code: %d;\n",
|
|
__func__, convert_param[i].desc, rc);
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* 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[RTE_DIM(invalid_layout_data)];
|
|
const uint8_t *data[RTE_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,
|
|
RTE_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, RTE_DIM(invalid_layout_data), 1);
|
|
|
|
/* prepare data */
|
|
for (i = 0; i < (int) RTE_DIM(invalid_layout_data); i++) {
|
|
data[i] = (uint8_t *)&invalid_layout_data[i];
|
|
}
|
|
|
|
/* classify tuples */
|
|
ret = rte_acl_classify_alg(acx, data, results,
|
|
RTE_DIM(results), 1, RTE_ACL_CLASSIFY_SCALAR);
|
|
if (ret != 0) {
|
|
printf("Line %i: SSE classify failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < (int) RTE_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_alg(acx, data, results, RTE_DIM(results), 1,
|
|
RTE_ACL_CLASSIFY_SCALAR);
|
|
|
|
if (ret != 0) {
|
|
printf("Line %i: Scalar classify failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
for (i = 0; i < (int) RTE_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, RTE_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, RTE_DIM(invalid_layout_data), 0);
|
|
|
|
rte_acl_free(acx);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Test creating and finding ACL contexts, and adding rules
|
|
*/
|
|
static int
|
|
test_create_find_add(void)
|
|
{
|
|
struct rte_acl_param param;
|
|
struct rte_acl_ctx *acx, *acx2, *tmp;
|
|
struct rte_acl_ipv4vlan_rule rules[LEN];
|
|
|
|
const uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
|
|
|
|
const char *acx_name = "acx";
|
|
const char *acx2_name = "acx2";
|
|
int i, ret;
|
|
|
|
/* create two contexts */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
param.max_rule_num = 2;
|
|
|
|
param.name = acx_name;
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: Error creating %s!\n", __LINE__, acx_name);
|
|
return -1;
|
|
}
|
|
|
|
param.name = acx2_name;
|
|
acx2 = rte_acl_create(¶m);
|
|
if (acx2 == NULL || acx2 == acx) {
|
|
printf("Line %i: Error creating %s!\n", __LINE__, acx2_name);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* try to create third one, with an existing name */
|
|
param.name = acx_name;
|
|
tmp = rte_acl_create(¶m);
|
|
if (tmp != acx) {
|
|
printf("Line %i: Creating context with existing name "
|
|
"test failed!\n",
|
|
__LINE__);
|
|
if (tmp)
|
|
rte_acl_free(tmp);
|
|
goto err;
|
|
}
|
|
|
|
param.name = acx2_name;
|
|
tmp = rte_acl_create(¶m);
|
|
if (tmp != acx2) {
|
|
printf("Line %i: Creating context with existing "
|
|
"name test 2 failed!\n",
|
|
__LINE__);
|
|
if (tmp)
|
|
rte_acl_free(tmp);
|
|
goto err;
|
|
}
|
|
|
|
/* try to find existing ACL 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 ACL context found!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
/* free context */
|
|
rte_acl_free(acx);
|
|
|
|
|
|
/* create valid (but severely limited) acx */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
param.max_rule_num = LEN;
|
|
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: Error creating %s!\n", __LINE__, param.name);
|
|
goto err;
|
|
}
|
|
|
|
/* create dummy acl */
|
|
for (i = 0; i < LEN; i++) {
|
|
memcpy(&rules[i], &acl_rule,
|
|
sizeof(struct rte_acl_ipv4vlan_rule));
|
|
/* skip zero */
|
|
rules[i].data.userdata = i + 1;
|
|
/* one rule per category */
|
|
rules[i].data.category_mask = 1 << i;
|
|
}
|
|
|
|
/* try filling up the context */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, rules, LEN);
|
|
if (ret != 0) {
|
|
printf("Line %i: Adding %i rules to ACL context failed!\n",
|
|
__LINE__, LEN);
|
|
goto err;
|
|
}
|
|
|
|
/* try adding to a (supposedly) full context */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, rules, 1);
|
|
if (ret == 0) {
|
|
printf("Line %i: Adding rules to full ACL context should"
|
|
"have failed!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
/* try building the context */
|
|
ret = rte_acl_ipv4vlan_build(acx, layout, RTE_ACL_MAX_CATEGORIES);
|
|
if (ret != 0) {
|
|
printf("Line %i: Building ACL context failed!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
rte_acl_free(acx);
|
|
rte_acl_free(acx2);
|
|
|
|
return 0;
|
|
err:
|
|
rte_acl_free(acx);
|
|
rte_acl_free(acx2);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* test various invalid rules
|
|
*/
|
|
static int
|
|
test_invalid_rules(void)
|
|
{
|
|
struct rte_acl_ctx *acx;
|
|
int ret;
|
|
|
|
struct rte_acl_ipv4vlan_rule rule;
|
|
|
|
acx = rte_acl_create(&acl_param);
|
|
if (acx == NULL) {
|
|
printf("Line %i: Error creating ACL context!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
/* test inverted high/low source and destination ports.
|
|
* originally, there was a problem with memory consumption when using
|
|
* such rules.
|
|
*/
|
|
/* create dummy acl */
|
|
memcpy(&rule, &acl_rule, sizeof(struct rte_acl_ipv4vlan_rule));
|
|
rule.data.userdata = 1;
|
|
rule.dst_port_low = 0xfff0;
|
|
rule.dst_port_high = 0x0010;
|
|
|
|
/* add rules to context and try to build it */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
|
|
if (ret == 0) {
|
|
printf("Line %i: Adding rules to ACL context "
|
|
"should have failed!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
rule.dst_port_low = 0x0;
|
|
rule.dst_port_high = 0xffff;
|
|
rule.src_port_low = 0xfff0;
|
|
rule.src_port_high = 0x0010;
|
|
|
|
/* add rules to context and try to build it */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
|
|
if (ret == 0) {
|
|
printf("Line %i: Adding rules to ACL context "
|
|
"should have failed!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
rule.dst_port_low = 0x0;
|
|
rule.dst_port_high = 0xffff;
|
|
rule.src_port_low = 0x0;
|
|
rule.src_port_high = 0xffff;
|
|
|
|
rule.dst_mask_len = 33;
|
|
|
|
/* add rules to context and try to build it */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
|
|
if (ret == 0) {
|
|
printf("Line %i: Adding rules to ACL context "
|
|
"should have failed!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
rule.dst_mask_len = 0;
|
|
rule.src_mask_len = 33;
|
|
|
|
/* add rules to context and try to build it */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
|
|
if (ret == 0) {
|
|
printf("Line %i: Adding rules to ACL context "
|
|
"should have failed!\n", __LINE__);
|
|
goto err;
|
|
}
|
|
|
|
rule.dst_mask_len = 0;
|
|
rule.src_mask_len = 0;
|
|
rule.data.userdata = 0;
|
|
|
|
/* try adding this rule (it should fail because userdata is invalid) */
|
|
ret = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
|
|
if (ret == 0) {
|
|
printf("Line %i: Adding a rule with invalid user data "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
rte_acl_free(acx);
|
|
|
|
return 0;
|
|
|
|
err:
|
|
rte_acl_free(acx);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* test functions by passing invalid or
|
|
* non-workable parameters.
|
|
*
|
|
* we do very limited testing of classify functions here
|
|
* because those are performance-critical and
|
|
* thus don't do much parameter checking.
|
|
*/
|
|
static int
|
|
test_invalid_parameters(void)
|
|
{
|
|
struct rte_acl_param param;
|
|
struct rte_acl_ctx *acx;
|
|
struct rte_acl_ipv4vlan_rule rule;
|
|
int result;
|
|
|
|
uint32_t layout[RTE_ACL_IPV4VLAN_NUM] = {0};
|
|
|
|
|
|
/**
|
|
* rte_ac_create()
|
|
*/
|
|
|
|
/* NULL param */
|
|
acx = rte_acl_create(NULL);
|
|
if (acx != NULL) {
|
|
printf("Line %i: ACL context creation with NULL param "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* zero rule size */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
param.rule_size = 0;
|
|
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: ACL context creation with zero rule len "
|
|
"failed!\n", __LINE__);
|
|
return -1;
|
|
} else
|
|
rte_acl_free(acx);
|
|
|
|
/* zero max rule num */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
param.max_rule_num = 0;
|
|
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: ACL context creation with zero rule num "
|
|
"failed!\n", __LINE__);
|
|
return -1;
|
|
} else
|
|
rte_acl_free(acx);
|
|
|
|
/* invalid NUMA node */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
param.socket_id = RTE_MAX_NUMA_NODES + 1;
|
|
|
|
acx = rte_acl_create(¶m);
|
|
if (acx != NULL) {
|
|
printf("Line %i: ACL context creation with invalid NUMA "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* NULL name */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
param.name = NULL;
|
|
|
|
acx = rte_acl_create(¶m);
|
|
if (acx != NULL) {
|
|
printf("Line %i: ACL context creation with NULL name "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* rte_acl_find_existing
|
|
*/
|
|
|
|
acx = rte_acl_find_existing(NULL);
|
|
if (acx != NULL) {
|
|
printf("Line %i: NULL ACL context found!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* rte_acl_ipv4vlan_add_rules
|
|
*/
|
|
|
|
/* initialize everything */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: ACL context creation failed!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&rule, &acl_rule, sizeof(rule));
|
|
|
|
/* NULL context */
|
|
result = rte_acl_ipv4vlan_add_rules(NULL, &rule, 1);
|
|
if (result == 0) {
|
|
printf("Line %i: Adding rules with NULL ACL context "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* NULL rule */
|
|
result = rte_acl_ipv4vlan_add_rules(acx, NULL, 1);
|
|
if (result == 0) {
|
|
printf("Line %i: Adding NULL rule to ACL context "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* zero count (should succeed) */
|
|
result = rte_acl_ipv4vlan_add_rules(acx, &rule, 0);
|
|
if (result != 0) {
|
|
printf("Line %i: Adding 0 rules to ACL context failed!\n",
|
|
__LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* free ACL context */
|
|
rte_acl_free(acx);
|
|
|
|
/* set wrong rule_size so that adding any rules would fail */
|
|
param.rule_size = RTE_ACL_IPV4VLAN_RULE_SZ + 4;
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: ACL context creation failed!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
/* try adding a rule with size different from context rule_size */
|
|
result = rte_acl_ipv4vlan_add_rules(acx, &rule, 1);
|
|
if (result == 0) {
|
|
printf("Line %i: Adding an invalid sized rule "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* free ACL context */
|
|
rte_acl_free(acx);
|
|
|
|
|
|
/**
|
|
* rte_acl_ipv4vlan_build
|
|
*/
|
|
|
|
/* reinitialize context */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: ACL context creation failed!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
/* NULL context */
|
|
result = rte_acl_ipv4vlan_build(NULL, layout, 1);
|
|
if (result == 0) {
|
|
printf("Line %i: Building with NULL context "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* NULL layout */
|
|
result = rte_acl_ipv4vlan_build(acx, NULL, 1);
|
|
if (result == 0) {
|
|
printf("Line %i: Building with NULL layout "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* zero categories (should not fail) */
|
|
result = rte_acl_ipv4vlan_build(acx, layout, 0);
|
|
if (result == 0) {
|
|
printf("Line %i: Building with 0 categories should fail!\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_alg(acx, NULL, NULL, 0, 0,
|
|
RTE_ACL_CLASSIFY_SCALAR);
|
|
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(acx, NULL, NULL, 0, 3);
|
|
if (result == 0) {
|
|
printf("Line %i: Scalar classify with 3 categories "
|
|
"should have failed!\n", __LINE__);
|
|
rte_acl_free(acx);
|
|
return -1;
|
|
}
|
|
|
|
/* free ACL context */
|
|
rte_acl_free(acx);
|
|
|
|
|
|
/**
|
|
* make sure void functions don't crash with NULL parameters
|
|
*/
|
|
|
|
rte_acl_free(NULL);
|
|
|
|
rte_acl_dump(NULL);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Various tests that don't test much but improve coverage
|
|
*/
|
|
static int
|
|
test_misc(void)
|
|
{
|
|
struct rte_acl_param param;
|
|
struct rte_acl_ctx *acx;
|
|
|
|
/* create context */
|
|
memcpy(¶m, &acl_param, sizeof(param));
|
|
|
|
acx = rte_acl_create(¶m);
|
|
if (acx == NULL) {
|
|
printf("Line %i: Error creating ACL context!\n", __LINE__);
|
|
return -1;
|
|
}
|
|
|
|
/* dump context with rules - useful for coverage */
|
|
rte_acl_list_dump();
|
|
|
|
rte_acl_dump(acx);
|
|
|
|
rte_acl_free(acx);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
test_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;
|
|
if (test_build_ports_range() < 0)
|
|
return -1;
|
|
if (test_convert() < 0)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static struct test_command acl_cmd = {
|
|
.command = "acl_autotest",
|
|
.callback = test_acl,
|
|
};
|
|
REGISTER_TEST_COMMAND(acl_cmd);
|